voly 0.0.186__tar.gz → 0.0.189__tar.gz
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-0.0.186/src/voly.egg-info → voly-0.0.189}/PKG-INFO +1 -1
- {voly-0.0.186 → voly-0.0.189}/pyproject.toml +2 -2
- {voly-0.0.186 → voly-0.0.189}/src/voly/core/fit.py +58 -10
- {voly-0.0.186 → voly-0.0.189/src/voly.egg-info}/PKG-INFO +1 -1
- {voly-0.0.186 → voly-0.0.189}/LICENSE +0 -0
- {voly-0.0.186 → voly-0.0.189}/README.md +0 -0
- {voly-0.0.186 → voly-0.0.189}/setup.cfg +0 -0
- {voly-0.0.186 → voly-0.0.189}/setup.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/__init__.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/client.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/core/__init__.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/core/charts.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/core/data.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/core/hd.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/core/interpolate.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/core/rnd.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/exceptions.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/formulas.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/models.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/utils/__init__.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/utils/density.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly/utils/logger.py +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly.egg-info/SOURCES.txt +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly.egg-info/dependency_links.txt +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly.egg-info/requires.txt +0 -0
- {voly-0.0.186 → voly-0.0.189}/src/voly.egg-info/top_level.txt +0 -0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "voly"
|
7
|
-
version = "0.0.
|
7
|
+
version = "0.0.189"
|
8
8
|
description = "Options & volatility research package"
|
9
9
|
readme = "README.md"
|
10
10
|
authors = [
|
@@ -60,7 +60,7 @@ line_length = 100
|
|
60
60
|
multi_line_output = 3
|
61
61
|
|
62
62
|
[tool.mypy]
|
63
|
-
python_version = "0.0.
|
63
|
+
python_version = "0.0.189"
|
64
64
|
warn_return_any = true
|
65
65
|
warn_unused_configs = true
|
66
66
|
disallow_untyped_defs = true
|
@@ -37,11 +37,8 @@ def fit_model(option_chain: pd.DataFrame) -> pd.DataFrame:
|
|
37
37
|
# Define column names and their data types
|
38
38
|
column_dtypes = {
|
39
39
|
's': float,
|
40
|
-
'u': float,
|
41
40
|
't': float,
|
42
41
|
'r': float,
|
43
|
-
'oi': float,
|
44
|
-
'volume': float,
|
45
42
|
'maturity_date': 'datetime64[ns]',
|
46
43
|
'a': float,
|
47
44
|
'b': float,
|
@@ -67,6 +64,7 @@ def fit_model(option_chain: pd.DataFrame) -> pd.DataFrame:
|
|
67
64
|
}
|
68
65
|
|
69
66
|
s = option_chain['index_price'].iloc[0]
|
67
|
+
unique_ts = sorted(option_chain['t'].unique())
|
70
68
|
maturity_names = [option_chain[option_chain['t'] == t]['maturity_name'].iloc[0] for t in unique_ts]
|
71
69
|
groups = option_chain.groupby('maturity_date')
|
72
70
|
params_dict = {}
|
@@ -94,7 +92,6 @@ def fit_model(option_chain: pd.DataFrame) -> pd.DataFrame:
|
|
94
92
|
|
95
93
|
# Combine cleaned duplicates and unique rows
|
96
94
|
maturity_data = pd.concat([unique_iv, cleaned_duplicated_iv])
|
97
|
-
#maturity_name = maturity_data['maturity_name'].iloc[0]
|
98
95
|
maturity_date = maturity_data['maturity_date'].iloc[0]
|
99
96
|
|
100
97
|
t = group['t'].iloc[0]
|
@@ -113,10 +110,7 @@ def fit_model(option_chain: pd.DataFrame) -> pd.DataFrame:
|
|
113
110
|
nu = psi = p = c = nu_tilde = np.nan
|
114
111
|
rmse = mae = r2 = max_error = np.nan
|
115
112
|
butterfly_arbitrage_free = True
|
116
|
-
u = s # Assume underlying_price is index_price
|
117
113
|
r = maturity_data['interest_rate'].iloc[0] if 'interest_rate' in maturity_data.columns else 0
|
118
|
-
oi = maturity_data['open_interest'].sum() if 'open_interest' in maturity_data.columns else 0
|
119
|
-
volume = maturity_data['volume'].sum() if 'volume' in maturity_data.columns else 0
|
120
114
|
log_min_strike = usd_min_strike = np.nan
|
121
115
|
|
122
116
|
if len(k) > 5:
|
@@ -165,11 +159,8 @@ def fit_model(option_chain: pd.DataFrame) -> pd.DataFrame:
|
|
165
159
|
|
166
160
|
# Store results
|
167
161
|
results_data['s'].append(float(s))
|
168
|
-
results_data['u'].append(float(u))
|
169
162
|
results_data['t'].append(float(t))
|
170
163
|
results_data['r'].append(float(r))
|
171
|
-
results_data['oi'].append(float(oi))
|
172
|
-
results_data['volume'].append(float(volume))
|
173
164
|
results_data['maturity_date'].append(maturity_date)
|
174
165
|
results_data['a'].append(float(a_scaled) if not np.isnan(params[0]) else np.nan)
|
175
166
|
results_data['b'].append(float(b_scaled) if not np.isnan(params[0]) else np.nan)
|
@@ -370,3 +361,60 @@ def fit_model(option_chain: pd.DataFrame) -> pd.DataFrame:
|
|
370
361
|
|
371
362
|
logger.info("Model fitting complete.")
|
372
363
|
return results_df
|
364
|
+
|
365
|
+
|
366
|
+
@catch_exception
|
367
|
+
def get_iv_surface(model_results: pd.DataFrame,
|
368
|
+
domain_params: Tuple[float, float, int] = (-1.5, 1.5, 1000),
|
369
|
+
return_domain: str = 'log_moneyness') -> Tuple[Dict[str, np.ndarray], Dict[str, np.ndarray]]:
|
370
|
+
"""
|
371
|
+
Generate implied volatility surface using optimized SVI parameters.
|
372
|
+
|
373
|
+
Works with both regular fit_results and interpolated_results dataframes.
|
374
|
+
|
375
|
+
Parameters:
|
376
|
+
- model_results: DataFrame from fit_model() or interpolate_model(). Maturity names or DTM as Index
|
377
|
+
- domain_params: Tuple of (min, max, num_points) for the log-moneyness array
|
378
|
+
- return_domain: Domain for x-axis values ('log_moneyness', 'moneyness', 'returns', 'strikes', 'delta')
|
379
|
+
|
380
|
+
Returns:
|
381
|
+
- Tuple of (iv_surface, x_surface)
|
382
|
+
iv_surface: Dictionary mapping maturity/dtm names to IV arrays
|
383
|
+
x_surface: Dictionary mapping maturity/dtm names to requested x domain arrays
|
384
|
+
"""
|
385
|
+
# Check if required columns are present
|
386
|
+
required_columns = ['a', 'b', 'm', 'rho', 'sigma', 't']
|
387
|
+
missing_columns = [col for col in required_columns if col not in model_results.columns]
|
388
|
+
if missing_columns:
|
389
|
+
raise VolyError(f"Required columns missing in model_results: {missing_columns}")
|
390
|
+
|
391
|
+
# Generate implied volatility surface in log-moneyness domain
|
392
|
+
LM = np.linspace(domain_params[0], domain_params[1], domain_params[2])
|
393
|
+
|
394
|
+
iv_surface = {}
|
395
|
+
x_surface = {}
|
396
|
+
|
397
|
+
# Process each maturity/dtm
|
398
|
+
for i in model_results.index:
|
399
|
+
# Calculate SVI total implied variance and convert to IV
|
400
|
+
params = [
|
401
|
+
model_results.loc[i, 'a'],
|
402
|
+
model_results.loc[i, 'b'],
|
403
|
+
model_results.loc[i, 'm'],
|
404
|
+
model_results.loc[i, 'rho'],
|
405
|
+
model_results.loc[i, 'sigma']
|
406
|
+
]
|
407
|
+
s = model_results.loc[i, 's']
|
408
|
+
r = model_results.loc[i, 'r']
|
409
|
+
t = model_results.loc[i, 't']
|
410
|
+
|
411
|
+
# Calculate implied volatility
|
412
|
+
w = np.array([SVIModel.svi(x, *params) for x in LM])
|
413
|
+
o = np.sqrt(w / t)
|
414
|
+
iv_surface[i] = o
|
415
|
+
|
416
|
+
# Calculate x domain for this maturity/dtm
|
417
|
+
x = get_domain(domain_params, s, r, o, t, return_domain)
|
418
|
+
x_surface[i] = x
|
419
|
+
|
420
|
+
return iv_surface, x_surface
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|