voly 0.0.60__py3-none-any.whl → 0.0.62__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- voly/client.py +7 -7
- voly/core/charts.py +5 -5
- voly/core/fit.py +7 -7
- {voly-0.0.60.dist-info → voly-0.0.62.dist-info}/METADATA +1 -1
- {voly-0.0.60.dist-info → voly-0.0.62.dist-info}/RECORD +8 -8
- {voly-0.0.60.dist-info → voly-0.0.62.dist-info}/LICENSE +0 -0
- {voly-0.0.60.dist-info → voly-0.0.62.dist-info}/WHEEL +0 -0
- {voly-0.0.60.dist-info → voly-0.0.62.dist-info}/top_level.txt +0 -0
voly/client.py
CHANGED
|
@@ -319,7 +319,7 @@ class VolyClient:
|
|
|
319
319
|
# -------------------------------------------------------------------------
|
|
320
320
|
|
|
321
321
|
@staticmethod
|
|
322
|
-
def fit_model(
|
|
322
|
+
def fit_model(option_chain: pd.DataFrame,
|
|
323
323
|
model_name: str = 'svi',
|
|
324
324
|
initial_params: Optional[List[float]] = None,
|
|
325
325
|
param_bounds: Optional[Tuple] = None) -> Dict[str, Any]:
|
|
@@ -327,19 +327,19 @@ class VolyClient:
|
|
|
327
327
|
Fit a volatility model to market data.
|
|
328
328
|
|
|
329
329
|
Parameters:
|
|
330
|
-
-
|
|
330
|
+
- option_chain: DataFrame with option market data
|
|
331
331
|
- model_name: Name of model to fit (default: 'svi')
|
|
332
332
|
- initial_params: Optional initial parameters for optimization
|
|
333
333
|
- param_bounds: Optional parameter bounds for optimization
|
|
334
334
|
|
|
335
335
|
Returns:
|
|
336
|
-
-
|
|
336
|
+
- Tuple of (fit_results, fit_performance)
|
|
337
337
|
"""
|
|
338
338
|
logger.info(f"Fitting {model_name.upper()} model to market data")
|
|
339
339
|
|
|
340
340
|
# Fit the model
|
|
341
341
|
fit_results, fit_performance = fit_model(
|
|
342
|
-
|
|
342
|
+
option_chain=option_chain,
|
|
343
343
|
model_name=model_name,
|
|
344
344
|
initial_params=initial_params,
|
|
345
345
|
param_bounds=param_bounds
|
|
@@ -377,7 +377,7 @@ class VolyClient:
|
|
|
377
377
|
|
|
378
378
|
@staticmethod
|
|
379
379
|
def plot_model(fit_results: Dict[str, Any],
|
|
380
|
-
|
|
380
|
+
option_chain: pd.DataFrame = None,
|
|
381
381
|
moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
|
|
382
382
|
) -> Dict[str, go.Figure]:
|
|
383
383
|
"""
|
|
@@ -385,7 +385,7 @@ class VolyClient:
|
|
|
385
385
|
|
|
386
386
|
Parameters:
|
|
387
387
|
- fit_results: Dictionary with fitting results from fit_model()
|
|
388
|
-
-
|
|
388
|
+
- option_chain: Optional market data for comparison
|
|
389
389
|
- moneyness_params: Grid of log-moneyness values
|
|
390
390
|
|
|
391
391
|
Returns:
|
|
@@ -401,7 +401,7 @@ class VolyClient:
|
|
|
401
401
|
fit_performance = fit_results['fit_performance']
|
|
402
402
|
|
|
403
403
|
# Plot volatility smiles
|
|
404
|
-
plots['smiles'] = plot_all_smiles(moneyness_array, iv_surface,
|
|
404
|
+
plots['smiles'] = plot_all_smiles(moneyness_array, iv_surface, option_chain)
|
|
405
405
|
|
|
406
406
|
# Plot 3D surface
|
|
407
407
|
plots['surface_3d'] = plot_3d_surface(moneyness_array, iv_surface)
|
voly/core/charts.py
CHANGED
|
@@ -21,7 +21,7 @@ pio.renderers.default = "browser"
|
|
|
21
21
|
@catch_exception
|
|
22
22
|
def plot_volatility_smile(moneyness_array: np.ndarray,
|
|
23
23
|
iv_array: np.ndarray,
|
|
24
|
-
|
|
24
|
+
option_chain: pd.DataFrame = None,
|
|
25
25
|
maturity: Optional[str] = None) -> go.Figure:
|
|
26
26
|
"""Plot volatility smile for a single expiry."""
|
|
27
27
|
fig = go.Figure()
|
|
@@ -38,8 +38,8 @@ def plot_volatility_smile(moneyness_array: np.ndarray,
|
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
# Add market data if provided
|
|
41
|
-
if
|
|
42
|
-
maturity_data =
|
|
41
|
+
if option_chain is not None and maturity is not None:
|
|
42
|
+
maturity_data = option_chain[option_chain['maturity_name'] == maturity]
|
|
43
43
|
|
|
44
44
|
if not maturity_data.empty:
|
|
45
45
|
# Add bid and ask IVs
|
|
@@ -72,13 +72,13 @@ def plot_volatility_smile(moneyness_array: np.ndarray,
|
|
|
72
72
|
@catch_exception
|
|
73
73
|
def plot_all_smiles(moneyness_array: np.ndarray,
|
|
74
74
|
iv_surface: Dict[str, np.ndarray],
|
|
75
|
-
|
|
75
|
+
option_chain: Optional[pd.DataFrame] = None) -> List[go.Figure]:
|
|
76
76
|
"""Plot volatility smiles for all expiries."""
|
|
77
77
|
return [
|
|
78
78
|
plot_volatility_smile(
|
|
79
79
|
moneyness_array=moneyness_array,
|
|
80
80
|
iv_array=iv_surface[maturity],
|
|
81
|
-
|
|
81
|
+
option_chain=option_chain,
|
|
82
82
|
maturity=maturity
|
|
83
83
|
)
|
|
84
84
|
for maturity in iv_surface.keys()
|
voly/core/fit.py
CHANGED
|
@@ -19,17 +19,17 @@ warnings.filterwarnings("ignore")
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
@catch_exception
|
|
22
|
-
def calculate_residuals(params: List[float], ytm: float,
|
|
22
|
+
def calculate_residuals(params: List[float], ytm: float, option_chain: pd.DataFrame,
|
|
23
23
|
model: Any = SVIModel) -> np.ndarray:
|
|
24
24
|
"""Calculate residuals between market and model implied volatilities."""
|
|
25
|
-
maturity_data =
|
|
25
|
+
maturity_data = option_chain[option_chain['ytm'] == ytm]
|
|
26
26
|
w = np.array([model.svi(x, *params) for x in maturity_data['log_moneyness']])
|
|
27
27
|
iv_actual = maturity_data['mark_iv'].values
|
|
28
28
|
return iv_actual - np.sqrt(w / ytm)
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
@catch_exception
|
|
32
|
-
def fit_model(
|
|
32
|
+
def fit_model(option_chain: pd.DataFrame,
|
|
33
33
|
model_name: str = 'svi',
|
|
34
34
|
initial_params: Optional[List[float]] = None,
|
|
35
35
|
param_bounds: Optional[Tuple] = None) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
|
@@ -56,8 +56,8 @@ def fit_model(market_data: pd.DataFrame,
|
|
|
56
56
|
'rmse', 'mae', 'r2', 'max_error', 'n_points']
|
|
57
57
|
|
|
58
58
|
# Get unique maturities and sort them
|
|
59
|
-
unique_ytms = sorted(
|
|
60
|
-
maturity_names = [
|
|
59
|
+
unique_ytms = sorted(option_chain['ytm'].unique())
|
|
60
|
+
maturity_names = [option_chain[option_chain['ytm'] == ytm]['maturity_name'].iloc[0] for ytm in unique_ytms]
|
|
61
61
|
|
|
62
62
|
# Create empty DataFrames
|
|
63
63
|
fit_results_df = pd.DataFrame(index=results_index, columns=maturity_names)
|
|
@@ -68,7 +68,7 @@ def fit_model(market_data: pd.DataFrame,
|
|
|
68
68
|
|
|
69
69
|
for ytm in unique_ytms:
|
|
70
70
|
# Get data for this maturity
|
|
71
|
-
maturity_data =
|
|
71
|
+
maturity_data = option_chain[option_chain['ytm'] == ytm]
|
|
72
72
|
maturity_name = maturity_data['maturity_name'].iloc[0]
|
|
73
73
|
dtm = maturity_data['dtm'].iloc[0]
|
|
74
74
|
|
|
@@ -79,7 +79,7 @@ def fit_model(market_data: pd.DataFrame,
|
|
|
79
79
|
result = least_squares(
|
|
80
80
|
calculate_residuals,
|
|
81
81
|
initial_params,
|
|
82
|
-
args=(ytm,
|
|
82
|
+
args=(ytm, option_chain, SVIModel),
|
|
83
83
|
bounds=param_bounds,
|
|
84
84
|
max_nfev=1000
|
|
85
85
|
)
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
voly/__init__.py,sha256=8xyDk7rFCn_MOD5hxuv5cxxKZvBVRiSIM7TgaMPpwpw,211
|
|
2
|
-
voly/client.py,sha256=
|
|
2
|
+
voly/client.py,sha256=5_duFk_9B7z6U7yADyB5W2morahDZkZf_KkEVFIWCA0,20457
|
|
3
3
|
voly/exceptions.py,sha256=PBsbn1vNMvKcCJwwJ4lBO6glD85jo1h2qiEmD7ArAjs,92
|
|
4
4
|
voly/formulas.py,sha256=Xgaq4lx1fNzRfu9W84fMNeH6GRJ0FNFNUUUYn5ffjjE,8843
|
|
5
5
|
voly/models.py,sha256=LXXIlpXZQEfXTuCngxC8Hd3bWtw6wdXDCSGxTLmHM-c,3659
|
|
6
6
|
voly/core/__init__.py,sha256=bu6fS2I1Pj9fPPnl-zY3L7NqrZSY5Zy6NY2uMUvdhKs,183
|
|
7
|
-
voly/core/charts.py,sha256=
|
|
7
|
+
voly/core/charts.py,sha256=0fYD748wHUBtuOcRufzfDwjlhmLf6g081KH-zquIj0A,24381
|
|
8
8
|
voly/core/data.py,sha256=e8qBArubNqPkrfuIYB_q2WhRf7TKzA4Z3FhMC-xyLEE,8862
|
|
9
|
-
voly/core/fit.py,sha256=
|
|
9
|
+
voly/core/fit.py,sha256=zn8o58yc83QyP9DG9JjTG0s0h2CAhYhZYRwjhT83V7w,6500
|
|
10
10
|
voly/core/interpolate.py,sha256=ztVIePJZOh-CIbn69wkh1JW2rKywNe2FEewRN0zcSAo,8185
|
|
11
11
|
voly/core/rnd.py,sha256=8FTU-Qp9epW9yE4XSOdiFGIRXrGyXqF6mVgZn1NMvxk,11813
|
|
12
12
|
voly/utils/__init__.py,sha256=E05mWatyC-PDOsCxQV1p5Xi1IgpOomxrNURyCx_gB-w,200
|
|
13
13
|
voly/utils/logger.py,sha256=4-_2bVJmq17Q0d7Rd2mPg1AeR8gxv6EPvcmBDMFWcSM,1744
|
|
14
|
-
voly-0.0.
|
|
15
|
-
voly-0.0.
|
|
16
|
-
voly-0.0.
|
|
17
|
-
voly-0.0.
|
|
18
|
-
voly-0.0.
|
|
14
|
+
voly-0.0.62.dist-info/LICENSE,sha256=wcHIVbE12jfcBOai_wqBKY6xvNQU5E909xL1zZNq_2Q,1065
|
|
15
|
+
voly-0.0.62.dist-info/METADATA,sha256=3fFRqBZffusUSlSbf3Z74pbXpNBAiu2ASZ0qBd5wz2w,4092
|
|
16
|
+
voly-0.0.62.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
|
17
|
+
voly-0.0.62.dist-info/top_level.txt,sha256=ZfLw2sSxF-LrKAkgGjOmeTcw6_gD-30zvtdEY5W4B7c,5
|
|
18
|
+
voly-0.0.62.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|