voly 0.0.62__py3-none-any.whl → 0.0.64__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 CHANGED
@@ -352,27 +352,30 @@ class VolyClient:
352
352
 
353
353
  @staticmethod
354
354
  def get_iv_surface(fit_results: Dict[str, Any],
355
- moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
355
+ log_moneyness_params: Tuple[float, float, int] = (-2, 2, 500),
356
+ return_domain: str = 'log_moneyness',
356
357
  ) -> Dict[str, Any]:
357
358
  """
358
359
  Generate implied volatility surface using optimized SVI parameters.
359
360
 
360
361
  Parameters:
361
- - param_matrix: Matrix of optimized SVI parameters from fit_results
362
- - moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
362
+ - fit_results: DataFrame from fit_model()
363
+ - log_moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
364
+ - return_domain: str Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'delta')
363
365
 
364
366
  Returns:
365
- - Tuple of (moneyness_array, iv_surface)
367
+ - Tuple of (iv_surface, x_surface)
366
368
  """
367
369
  # Generate the surface
368
- moneyness_array, iv_surface = get_iv_surface(
370
+ iv_surface, x_surface = get_iv_surface(
369
371
  fit_results=fit_results,
370
- moneyness_params=moneyness_params
372
+ log_moneyness_params=log_moneyness_params,
373
+ return_domain=return_domain
371
374
  )
372
375
 
373
376
  return {
374
- 'moneyness_array': moneyness_array,
375
- 'iv_surface': iv_surface
377
+ 'iv_surface': iv_surface,
378
+ 'x_surface': x_surface
376
379
  }
377
380
 
378
381
  @staticmethod
voly/core/fit.py CHANGED
@@ -11,6 +11,7 @@ from typing import List, Tuple, Dict, Optional, Union, Any
11
11
  from scipy.optimize import least_squares
12
12
  from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
13
13
  from voly.utils.logger import logger, catch_exception
14
+ from voly.formulas import get_x_domain
14
15
  from voly.exceptions import VolyError
15
16
  from voly.models import SVIModel
16
17
  import warnings
@@ -136,19 +137,30 @@ def fit_model(option_chain: pd.DataFrame,
136
137
 
137
138
  @catch_exception
138
139
  def get_iv_surface(fit_results: pd.DataFrame,
139
- log_moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
140
- ) -> Tuple[np.ndarray, Dict[str, np.ndarray]]:
141
- """Generate implied volatility surface using optimized SVI parameters."""
142
- # Extract moneyness parameters
140
+ log_moneyness_params: Tuple[float, float, int] = (-1.5, 1.5, 1000),
141
+ return_domain: str = 'log_moneyness') -> Tuple[Dict[str, np.ndarray], np.ndarray]:
142
+ """
143
+ Generate implied volatility surface using optimized SVI parameters.
144
+
145
+ Parameters:
146
+ - fit_results: DataFrame from fit_model()
147
+ - log_moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
148
+ - return_domain: Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'delta')
149
+
150
+ Returns:
151
+ - Tuple of (iv_surface, x_surface)
152
+ iv_surface: Dictionary mapping maturity names to IV arrays
153
+ x_surface: Dictionary mapping maturity names to requested x domain arrays
154
+ """
155
+
156
+ # Generate implied volatility surface in log-moneyness domain
143
157
  min_m, max_m, num_points = log_moneyness_params
158
+ log_moneyness_array = np.linspace(min_m, max_m, num=num_points)
144
159
 
145
- # Generate moneyness array and initialize surface dictionary
146
- moneyness_array = np.linspace(min_m, max_m, num=num_points)
147
160
  iv_surface = {}
148
-
149
- # Generate implied volatility for each maturity
161
+ x_surface = {}
150
162
  for maturity in fit_results.columns:
151
- # Extract parameters and YTM
163
+ # Calculate SVI total implied variance and convert to IV
152
164
  params = [
153
165
  fit_results.loc['a', maturity],
154
166
  fit_results.loc['b', maturity],
@@ -158,8 +170,19 @@ def get_iv_surface(fit_results: pd.DataFrame,
158
170
  ]
159
171
  ytm = fit_results.loc['ytm', maturity]
160
172
 
161
- # Calculate SVI total implied variance and convert to IV
162
- w_svi = np.array([SVIModel.svi(x, *params) for x in moneyness_array])
163
- iv_surface[maturity] = np.sqrt(w_svi / ytm)
173
+ w_svi = np.array([SVIModel.svi(x, *params) for x in log_moneyness_array])
174
+ iv_array = np.sqrt(w_svi / ytm)
175
+ iv_surface[maturity] = iv_array
176
+
177
+ x_domain = get_x_domain(
178
+ log_moneyness_params=log_moneyness_params,
179
+ return_domain=return_domain,
180
+ s=fit_results.loc['s', maturity],
181
+ r=fit_results.loc['r', maturity],
182
+ iv_array=iv_array,
183
+ ytm=fit_results.loc['ytm', maturity]
184
+ )
185
+
186
+ x_surface[maturity] = x_domain
164
187
 
165
- return moneyness_array, iv_surface
188
+ return iv_surface, x_surface
voly/formulas.py CHANGED
@@ -7,7 +7,7 @@ from scipy.stats import norm
7
7
  from typing import Tuple, Dict, Union, List, Optional
8
8
  from voly.utils.logger import catch_exception
9
9
  from voly.models import SVIModel
10
- from math import exp
10
+ from typing import Tuple
11
11
 
12
12
 
13
13
  @catch_exception
@@ -276,3 +276,86 @@ def iv(option_price: float, s: float, k: float, r: float, t: float,
276
276
 
277
277
  # If we reach here, we didn't converge
278
278
  return np.nan
279
+
280
+
281
+ @catch_exception
282
+ def get_x_domain(log_moneyness_params: Tuple[float, float, int] = (-1.5, 1.5, 1000),
283
+ return_domain: str = 'log_moneyness',
284
+ s: float = None,
285
+ r: float = None,
286
+ iv_array: np.ndarray = None,
287
+ ytm: float = None) -> np.ndarray:
288
+ """
289
+ Compute the x-domain for a given return type (log-moneyness, moneyness, strikes, or delta).
290
+
291
+ Parameters:
292
+ -----------
293
+ log_moneyness_params : Tuple[float, float, int],
294
+ Parameters for log-moneyness domain: (min_log_moneyness, max_log_moneyness, num_points).
295
+ Default is (-1.5, 1.5, 1000).
296
+ return_domain : str, optional
297
+ The desired domain to return. Options are 'log_moneyness', 'moneyness', 'strikes', or 'delta'.
298
+ Default is 'log_moneyness'.
299
+ s : float, optional
300
+ Spot price of the underlying asset. Required for 'strikes' and 'delta' domains.
301
+ r : float, optional
302
+ Risk-free interest rate. Required for 'delta' domain.
303
+ iv_array : np.ndarray, optional
304
+ Array of implied volatilities. Required for 'delta' domain.
305
+ ytm : float, optional
306
+ Time to maturity in years. Required for 'delta' domain.
307
+
308
+ Returns:
309
+ --------
310
+ np.ndarray
311
+ The x-domain array corresponding to the specified return_domain.
312
+
313
+ Raises:
314
+ -------
315
+ ValueError
316
+ If required parameters are missing for the specified return_domain.
317
+ """
318
+
319
+ # Extract log-moneyness parameters
320
+ min_m, max_m, num_points = log_moneyness_params
321
+
322
+ # Generate the base log-moneyness array
323
+ log_moneyness = np.linspace(min_m, max_m, num_points)
324
+
325
+ # Handle different return domains
326
+ if return_domain == 'log_moneyness':
327
+ return log_moneyness
328
+
329
+ elif return_domain == 'moneyness':
330
+ return np.exp(log_moneyness)
331
+
332
+ elif return_domain == 'strikes':
333
+ if s is None:
334
+ raise ValueError("Spot price 's' is required for return_domain='strikes'.")
335
+ return s / np.exp(log_moneyness) # K = S/exp(log_moneyness)
336
+
337
+ elif return_domain == 'delta':
338
+ # Check for required parameters
339
+ required_params = {'s': s, 'r': r, 'iv_array': iv_array, 'ytm': ytm}
340
+ missing_params = [param for param, value in required_params.items() if value is None]
341
+ if missing_params:
342
+ raise ValueError(f"The following parameters are required for return_domain='delta': {missing_params}")
343
+
344
+ if len(iv_array) != len(log_moneyness):
345
+ raise ValueError(
346
+ f"iv_array must have the same length as the log-moneyness array ({len(log_moneyness)}).")
347
+
348
+ # Compute strikes
349
+ strikes = s / np.exp(log_moneyness)
350
+
351
+ # Compute deltas
352
+ delta_values = np.array([
353
+ delta(s, k, r, vol, ytm, 'call')
354
+ for k, vol in zip(strikes, iv_array)
355
+ ])
356
+
357
+ return delta_values
358
+
359
+ else:
360
+ raise ValueError(
361
+ f"Invalid return_domain: {return_domain}. Must be one of ['log_moneyness', 'moneyness', 'strikes', 'delta'].")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voly
3
- Version: 0.0.62
3
+ Version: 0.0.64
4
4
  Summary: Options & volatility research package
5
5
  Author-email: Manu de Cara <manu.de.cara@gmail.com>
6
6
  License: MIT
@@ -1,18 +1,18 @@
1
1
  voly/__init__.py,sha256=8xyDk7rFCn_MOD5hxuv5cxxKZvBVRiSIM7TgaMPpwpw,211
2
- voly/client.py,sha256=5_duFk_9B7z6U7yADyB5W2morahDZkZf_KkEVFIWCA0,20457
2
+ voly/client.py,sha256=8_ICxM-tOZsY5Ip85J61U7IziMBkyE5gNjqiu4uJy50,20643
3
3
  voly/exceptions.py,sha256=PBsbn1vNMvKcCJwwJ4lBO6glD85jo1h2qiEmD7ArAjs,92
4
- voly/formulas.py,sha256=Xgaq4lx1fNzRfu9W84fMNeH6GRJ0FNFNUUUYn5ffjjE,8843
4
+ voly/formulas.py,sha256=gl4L_KtSd8ZJTAc6_RroJSDwOS8z6gcnpARG7oJFxdk,11897
5
5
  voly/models.py,sha256=LXXIlpXZQEfXTuCngxC8Hd3bWtw6wdXDCSGxTLmHM-c,3659
6
6
  voly/core/__init__.py,sha256=bu6fS2I1Pj9fPPnl-zY3L7NqrZSY5Zy6NY2uMUvdhKs,183
7
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=zn8o58yc83QyP9DG9JjTG0s0h2CAhYhZYRwjhT83V7w,6500
9
+ voly/core/fit.py,sha256=N1wey5NYeInIPKfa5xC0P4eBVhoTf0wwu7cYMmgv-Xg,7310
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.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,,
14
+ voly-0.0.64.dist-info/LICENSE,sha256=wcHIVbE12jfcBOai_wqBKY6xvNQU5E909xL1zZNq_2Q,1065
15
+ voly-0.0.64.dist-info/METADATA,sha256=gNoS4lyABUFajKIbF1KjaPVKuKwC2AVTMyv4FwXK6pc,4092
16
+ voly-0.0.64.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
17
+ voly-0.0.64.dist-info/top_level.txt,sha256=ZfLw2sSxF-LrKAkgGjOmeTcw6_gD-30zvtdEY5W4B7c,5
18
+ voly-0.0.64.dist-info/RECORD,,
File without changes
File without changes