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.
Files changed (26) hide show
  1. {voly-0.0.186/src/voly.egg-info → voly-0.0.189}/PKG-INFO +1 -1
  2. {voly-0.0.186 → voly-0.0.189}/pyproject.toml +2 -2
  3. {voly-0.0.186 → voly-0.0.189}/src/voly/core/fit.py +58 -10
  4. {voly-0.0.186 → voly-0.0.189/src/voly.egg-info}/PKG-INFO +1 -1
  5. {voly-0.0.186 → voly-0.0.189}/LICENSE +0 -0
  6. {voly-0.0.186 → voly-0.0.189}/README.md +0 -0
  7. {voly-0.0.186 → voly-0.0.189}/setup.cfg +0 -0
  8. {voly-0.0.186 → voly-0.0.189}/setup.py +0 -0
  9. {voly-0.0.186 → voly-0.0.189}/src/voly/__init__.py +0 -0
  10. {voly-0.0.186 → voly-0.0.189}/src/voly/client.py +0 -0
  11. {voly-0.0.186 → voly-0.0.189}/src/voly/core/__init__.py +0 -0
  12. {voly-0.0.186 → voly-0.0.189}/src/voly/core/charts.py +0 -0
  13. {voly-0.0.186 → voly-0.0.189}/src/voly/core/data.py +0 -0
  14. {voly-0.0.186 → voly-0.0.189}/src/voly/core/hd.py +0 -0
  15. {voly-0.0.186 → voly-0.0.189}/src/voly/core/interpolate.py +0 -0
  16. {voly-0.0.186 → voly-0.0.189}/src/voly/core/rnd.py +0 -0
  17. {voly-0.0.186 → voly-0.0.189}/src/voly/exceptions.py +0 -0
  18. {voly-0.0.186 → voly-0.0.189}/src/voly/formulas.py +0 -0
  19. {voly-0.0.186 → voly-0.0.189}/src/voly/models.py +0 -0
  20. {voly-0.0.186 → voly-0.0.189}/src/voly/utils/__init__.py +0 -0
  21. {voly-0.0.186 → voly-0.0.189}/src/voly/utils/density.py +0 -0
  22. {voly-0.0.186 → voly-0.0.189}/src/voly/utils/logger.py +0 -0
  23. {voly-0.0.186 → voly-0.0.189}/src/voly.egg-info/SOURCES.txt +0 -0
  24. {voly-0.0.186 → voly-0.0.189}/src/voly.egg-info/dependency_links.txt +0 -0
  25. {voly-0.0.186 → voly-0.0.189}/src/voly.egg-info/requires.txt +0 -0
  26. {voly-0.0.186 → voly-0.0.189}/src/voly.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voly
3
- Version: 0.0.186
3
+ Version: 0.0.189
4
4
  Summary: Options & volatility research package
5
5
  Author-email: Manu de Cara <manu.de.cara@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "voly"
7
- version = "0.0.186"
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.186"
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voly
3
- Version: 0.0.186
3
+ Version: 0.0.189
4
4
  Summary: Options & volatility research package
5
5
  Author-email: Manu de Cara <manu.de.cara@gmail.com>
6
6
  License: MIT
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