voly 0.0.30__tar.gz → 0.0.33__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voly
3
- Version: 0.0.30
3
+ Version: 0.0.33
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.30"
7
+ version = "0.0.33"
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.30"
63
+ python_version = "0.0.33"
64
64
  warn_return_any = true
65
65
  warn_unused_configs = true
66
66
  disallow_untyped_defs = true
@@ -18,8 +18,8 @@ from voly.formulas import (
18
18
  bs, delta, gamma, vega, theta, rho, vanna, volga, charm, greeks, iv
19
19
  )
20
20
  from voly.core.data import fetch_option_chain, process_option_chain
21
- from voly.core.fit import fit_model, get_surface
22
- from voly.core.rnd import calculate_rnd, calculate_pdf, calculate_cdf, calculate_strike_probability
21
+ from voly.core.fit import fit_model, get_iv_surface
22
+ from voly.core.rnd import get_rnd, get_rnd_surface, calculate_pdf, calculate_cdf, calculate_strike_probability
23
23
  from voly.core.interpolate import interpolate_model
24
24
  from voly.core.charts import (
25
25
  plot_all_smiles, plot_3d_surface, plot_parameters, plot_fit_performance,
@@ -322,9 +322,9 @@ class VolyClient:
322
322
  return fit_results
323
323
 
324
324
  @staticmethod
325
- def get_surface(fit_results: Dict[str, Any],
326
- moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
327
- ) -> Dict[str, Any]:
325
+ def get_iv_surface(fit_results: Dict[str, Any],
326
+ moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
327
+ ) -> Dict[str, Any]:
328
328
  """
329
329
  Generate implied volatility surface using optimized SVI parameters.
330
330
 
@@ -333,18 +333,15 @@ class VolyClient:
333
333
  - moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
334
334
 
335
335
  Returns:
336
- - Tuple of (moneyness_grid, iv_surface)
336
+ - Tuple of (moneyness_array, iv_surface)
337
337
  """
338
338
  # Generate the surface
339
- moneyness_grid, iv_surface = get_surface(
339
+ iv_surface = get_iv_surface(
340
340
  fit_results=fit_results,
341
341
  moneyness_params=moneyness_params
342
342
  )
343
343
 
344
- return {
345
- 'moneyness_grid': moneyness_grid,
346
- 'iv_surface': iv_surface
347
- }
344
+ return iv_surface
348
345
 
349
346
  @staticmethod
350
347
  def plot_model(fit_results: Dict[str, Any],
@@ -364,7 +361,7 @@ class VolyClient:
364
361
  """
365
362
  plots = {}
366
363
 
367
- moneyness_grid, iv_surface = get_surface(fit_results, moneyness_params)
364
+ moneyness_array, iv_surface = get_iv_surface(fit_results, moneyness_params)
368
365
 
369
366
  # Extract data from fit results
370
367
  raw_param_matrix = fit_results['raw_param_matrix']
@@ -372,10 +369,10 @@ class VolyClient:
372
369
  fit_performance = fit_results['fit_performance']
373
370
 
374
371
  # Plot volatility smiles
375
- plots['smiles'] = plot_all_smiles(moneyness_grid, iv_surface, market_data)
372
+ plots['smiles'] = plot_all_smiles(moneyness_array, iv_surface, market_data)
376
373
 
377
374
  # Plot 3D surface
378
- plots['surface_3d'] = plot_3d_surface(moneyness_grid, iv_surface)
375
+ plots['surface_3d'] = plot_3d_surface(moneyness_array, iv_surface)
379
376
 
380
377
  # Plot parameters
381
378
  plots['raw_params'], plots['jw_params'] = plot_parameters(raw_param_matrix, jw_param_matrix)
@@ -390,34 +387,55 @@ class VolyClient:
390
387
  # -------------------------------------------------------------------------
391
388
 
392
389
  @staticmethod
393
- def rnd(fit_results: Dict[str, Any],
394
- maturity: Optional[str] = None,
395
- spot_price: float = 1.0,
396
- plot: bool = False) -> Dict[str, Any]:
390
+ def get_rnd(svi_params_list: float[List],
391
+ moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
392
+ ) -> np.ndarray:
397
393
  """
398
394
  Calculate risk-neutral density from fitted model.
399
395
 
400
396
  Parameters:
401
- - fit_results: Dictionary with fitting results from fit_model()
402
- - maturity: Optional maturity name to calculate RND for a specific expiry
403
- - spot_price: Current spot price
404
- - plot: Whether to generate and return plots
405
397
 
406
398
  Returns:
407
- - Dictionary with RND results and optional plots
399
+ - Array with RND results over moneyness
408
400
  """
409
401
  logger.info("Calculating risk-neutral density")
410
402
 
411
- # Calculate RND
412
- rnd_results = calculate_rnd(fit_results, maturity, spot_price)
403
+ # Generate the surface
404
+ moneyness_array, iv_surface = get_rnd(
405
+ svi_params_list=svi_params_list,
406
+ moneyness_params=moneyness_params
407
+ )
413
408
 
414
- # Generate plots if requested
415
- if plot:
416
- logger.info("Generating RND plots")
417
- plots = generate_all_plots(fit_results, rnd_results)
418
- rnd_results['plots'] = plots
409
+ return {
410
+ 'moneyness_grid': moneyness_array,
411
+ 'rnd_values': rnd_values
412
+ }
413
+
414
+ @staticmethod
415
+ def get_rnd_surface(fit_results: Dict[str, Any],
416
+ moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
417
+ ) -> Dict[str, np.ndarray]:
418
+ """
419
+ Calculate risk-neutral density from fitted model.
420
+
421
+ Parameters:
422
+
423
+ Returns:
424
+ - Array with RND results over moneyness
425
+ """
426
+ logger.info("Calculating risk-neutral density")
427
+
428
+ # Generate the surface
429
+ moneyness_array, iv_surface = get_rnd_surface(
430
+ fit_results=fit_results,
431
+ moneyness_params=moneyness_params
432
+ )
433
+
434
+ return {
435
+ 'moneyness_grid': moneyness_grid,
436
+ 'rnd_values': rnd_values
437
+ }
419
438
 
420
- return rnd_results
421
439
 
422
440
  @staticmethod
423
441
  def pdf(rnd_results: Dict[str, Any],
@@ -358,8 +358,8 @@ def plot_3d_surface(moneyness_grid: np.ndarray,
358
358
  Returns:
359
359
  - Plotly figure
360
360
  """
361
- start_color = '#3a9cfc'
362
- end_color = '#003870' # Darker blue
361
+ start_color = '#60AEFC'
362
+ end_color = '#002040' # Darker blue
363
363
  custom_blue_scale = [[0, start_color], [1, end_color]]
364
364
  yte_values = list(iv_surface.keys())
365
365
 
@@ -265,18 +265,18 @@ def fit_model(market_data: pd.DataFrame,
265
265
 
266
266
 
267
267
  @catch_exception
268
- def get_surface(fit_results: Dict[str, Any],
269
- moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
270
- ) -> Dict[str, Any]:
268
+ def get_iv_surface(fit_results: Dict[str, Any],
269
+ moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
270
+ ) -> Dict[str, Any]:
271
271
  """
272
272
  Generate implied volatility surface using optimized SVI parameters.
273
273
 
274
274
  Parameters:
275
- - param_matrix: Matrix of optimized SVI parameters from fit_results
275
+ - fit_results: results from fit_model()
276
276
  - moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
277
277
 
278
278
  Returns:
279
- - Tuple of (moneyness_grid, iv_surface)
279
+ - iv_surface
280
280
  """
281
281
  iv_surface = {}
282
282
 
@@ -284,7 +284,7 @@ def get_surface(fit_results: Dict[str, Any],
284
284
  min_m, max_m, num_points = moneyness_params
285
285
 
286
286
  # Generate moneyness grid
287
- moneyness_grid = np.linspace(min_m, max_m, num=num_points)
287
+ moneyness_array = np.linspace(min_m, max_m, num=num_points)
288
288
 
289
289
  # Get YTE values from the parameter matrix attributes
290
290
  yte_values = fit_results['fit_performance']['YTE']
@@ -294,7 +294,7 @@ def get_surface(fit_results: Dict[str, Any],
294
294
  # Generate implied volatility for each expiry
295
295
  for maturity, yte in zip(maturity_values, yte_values):
296
296
  svi_params = param_matrix[maturity].values
297
- w_svi = [SVIModel.svi(x, *svi_params) for x in moneyness_grid]
297
+ w_svi = [SVIModel.svi(x, *svi_params) for x in moneyness_array]
298
298
  iv_surface[yte] = np.sqrt(np.array(w_svi) / yte)
299
299
 
300
- return moneyness_grid, iv_surface
300
+ return iv_surface
@@ -9,71 +9,78 @@ from typing import Dict, List, Tuple, Optional, Union, Any
9
9
  from voly.utils.logger import logger, catch_exception
10
10
  from voly.exceptions import VolyError
11
11
  from voly.models import SVIModel
12
- from voly.formulas import rnd
13
12
 
14
13
 
15
14
  @catch_exception
16
- def calculate_risk_neutral_density(
17
- log_moneyness: np.ndarray,
18
- params: List[float],
19
- model: Any = SVIModel
20
- ) -> np.ndarray:
21
- """
22
- Calculate the risk-neutral density (RND) from model parameters.
15
+ def rnd(moneyness_array: float, total_var: float) -> float:
16
+ return np.exp(-(moneyness_array ** 2) / (2 * total_var)) / (np.sqrt(2 * np.pi * total_var))
23
17
 
24
- Parameters:
25
- - log_moneyness: Array of log-moneyness values
26
- - params: Model parameters (e.g., SVI parameters [a, b, sigma, rho, m])
27
- - model: Model class to use (default: SVIModel)
28
18
 
29
- Returns:
30
- - Array of RND values corresponding to each log-moneyness value
31
- """
19
+ @catch_exception
20
+ def get_rnd(svi_params_list: float[List],
21
+ moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
22
+ ) -> Dict[str, Any]:
23
+
32
24
  # Adjust parameter order to match function signatures
33
- a, b, sigma, rho, m = params
25
+ a, b, sigma, rho, m = svi_params_list
26
+
27
+ # Extract moneyness parameters
28
+ min_m, max_m, num_points = moneyness_params
29
+
30
+ # Generate moneyness grid
31
+ moneyness_array = np.linspace(min_m, max_m, num=num_points)
34
32
 
35
33
  # Calculate total variance
36
- total_var = np.array([model.svi(x, a, b, sigma, rho, m) for x in log_moneyness])
34
+ total_var = np.array([SVIModel.svi(x, a, b, sigma, rho, m) for x in moneyness_array])
37
35
 
38
36
  # Calculate risk-neutral density using the base RND function
39
- rnd_values = np.array([rnd(x, var) for x, var in zip(log_moneyness, total_var)])
37
+ rnd_values = np.array([rnd(x, var) for x, var in zip(moneyness_array, total_var)])
40
38
 
41
- return rnd_values
39
+ return {
40
+ 'moneyness_array': moneyness_array,
41
+ 'rnd_values': rnd_values
42
+ }
42
43
 
43
44
 
44
45
  @catch_exception
45
- def calculate_rnd_for_all_expiries(
46
- moneyness_grid: np.ndarray,
47
- param_matrix: pd.DataFrame,
48
- model: Any = SVIModel
49
- ) -> Dict[str, np.ndarray]:
46
+ def get_rnd_surface(fit_results: Dict[str, Any],
47
+ moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
48
+ ) -> Dict[str, Any]:
50
49
  """
51
- Calculate RND for all expiries in the parameter matrix.
50
+ Calculate RND for all expiries using the SVI parameter matrix.
52
51
 
53
52
  Parameters:
54
- - moneyness_grid: Grid of log-moneyness values
55
- - param_matrix: Matrix containing model parameters for each expiry
56
- - model: Model class to use (default: SVIModel)
53
+ - moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
54
+ - fit_results: results from fit_model()
57
55
 
58
56
  Returns:
59
57
  - Dictionary mapping maturity names to RND arrays
60
58
  """
61
59
  rnd_surface = {}
62
60
 
63
- # Get YTE values from the parameter matrix attributes
64
- yte_values = param_matrix.attrs['yte_values']
61
+ # Extract moneyness parameters
62
+ min_m, max_m, num_points = moneyness_params
63
+
64
+ # Generate moneyness grid
65
+ moneyness_array = np.linspace(min_m, max_m, num=num_points)
66
+
67
+ # Get YTE values from the fit results attributes
68
+ yte_values = fit_results['fit_performance']['YTE']
69
+ maturity_values = fit_results['fit_performance']['Maturity']
70
+ param_matrix = fit_results['raw_param_matrix']
71
+
72
+ # Generate implied volatility for each expiry
73
+ for maturity, yte in zip(maturity_values, yte_values):
74
+ svi_params_list = list(param_matrix[maturity].values)
75
+
76
+ # Adjust parameter order to match function signatures
77
+ a, b, sigma, rho, m = svi_params_list
78
+
79
+ # Calculate total variance
80
+ total_var = np.array([SVIModel.svi(x, a, b, sigma, rho, m) for x in moneyness_array])
65
81
 
66
- # Calculate RND for each expiry
67
- for maturity_name, yte in yte_values.items():
68
- params = param_matrix[maturity_name].values
69
-
70
- # Calculate RND
71
- rnd_values = calculate_risk_neutral_density(
72
- moneyness_grid,
73
- params,
74
- yte,
75
- model=model
76
- )
82
+ # Calculate risk-neutral density using the base RND function
83
+ rnd_values = np.array([rnd(x, var) for x, var in zip(moneyness_array, total_var)])
77
84
 
78
85
  rnd_surface[maturity_name] = rnd_values
79
86
 
@@ -236,8 +236,3 @@ def iv(option_price: float, s: float, k: float, r: float, t: float,
236
236
 
237
237
  # If we reach here, we didn't converge
238
238
  return np.nan
239
-
240
-
241
- @catch_exception
242
- def rnd(log_moneyness: float, total_var: float) -> float:
243
- return np.exp(-(log_moneyness ** 2) / (2 * total_var)) / (np.sqrt(2 * np.pi * total_var))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voly
3
- Version: 0.0.30
3
+ Version: 0.0.33
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