voly 0.0.85__tar.gz → 0.0.87__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.85/src/voly.egg-info → voly-0.0.87}/PKG-INFO +1 -1
- {voly-0.0.85 → voly-0.0.87}/pyproject.toml +2 -2
- {voly-0.0.85 → voly-0.0.87}/src/voly/client.py +18 -201
- voly-0.0.87/src/voly/core/charts.py +415 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly/core/data.py +1 -4
- {voly-0.0.85 → voly-0.0.87}/src/voly/core/fit.py +40 -48
- {voly-0.0.85 → voly-0.0.87}/src/voly/core/interpolate.py +5 -6
- voly-0.0.87/src/voly/core/rnd.py +288 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly/formulas.py +27 -29
- {voly-0.0.85 → voly-0.0.87}/src/voly/models.py +0 -2
- {voly-0.0.85 → voly-0.0.87/src/voly.egg-info}/PKG-INFO +1 -1
- voly-0.0.85/src/voly/core/charts.py +0 -922
- voly-0.0.85/src/voly/core/rnd.py +0 -367
- {voly-0.0.85 → voly-0.0.87}/LICENSE +0 -0
- {voly-0.0.85 → voly-0.0.87}/README.md +0 -0
- {voly-0.0.85 → voly-0.0.87}/setup.cfg +0 -0
- {voly-0.0.85 → voly-0.0.87}/setup.py +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly/__init__.py +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly/core/__init__.py +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly/exceptions.py +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly/utils/__init__.py +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly/utils/logger.py +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly.egg-info/SOURCES.txt +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly.egg-info/dependency_links.txt +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly.egg-info/requires.txt +0 -0
- {voly-0.0.85 → voly-0.0.87}/src/voly.egg-info/top_level.txt +0 -0
- {voly-0.0.85 → voly-0.0.87}/tests/test_client.py +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.87"
|
|
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.87"
|
|
64
64
|
warn_return_any = true
|
|
65
65
|
warn_unused_configs = true
|
|
66
66
|
disallow_untyped_defs = true
|
|
@@ -349,7 +349,7 @@ class VolyClient:
|
|
|
349
349
|
|
|
350
350
|
@staticmethod
|
|
351
351
|
def get_iv_surface(model_results: pd.DataFrame,
|
|
352
|
-
|
|
352
|
+
domain_params: Tuple[float, float, int] = (-2, 2, 500),
|
|
353
353
|
return_domain: str = 'log_moneyness',
|
|
354
354
|
) -> Dict[str, Any]:
|
|
355
355
|
"""
|
|
@@ -357,7 +357,7 @@ class VolyClient:
|
|
|
357
357
|
|
|
358
358
|
Parameters:
|
|
359
359
|
- model_results: DataFrame from fit_model() or interpolate_model()
|
|
360
|
-
-
|
|
360
|
+
- domain_params: Tuple of (min, max, num_points) for the moneyness grid
|
|
361
361
|
- return_domain: str Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'delta')
|
|
362
362
|
|
|
363
363
|
Returns:
|
|
@@ -366,7 +366,7 @@ class VolyClient:
|
|
|
366
366
|
# Generate the surface
|
|
367
367
|
iv_surface, x_surface = get_iv_surface(
|
|
368
368
|
model_results=model_results,
|
|
369
|
-
|
|
369
|
+
domain_params=domain_params,
|
|
370
370
|
return_domain=return_domain
|
|
371
371
|
)
|
|
372
372
|
|
|
@@ -375,7 +375,7 @@ class VolyClient:
|
|
|
375
375
|
@staticmethod
|
|
376
376
|
def plot_model(fit_results: pd.DataFrame,
|
|
377
377
|
option_chain: pd.DataFrame = None,
|
|
378
|
-
|
|
378
|
+
domain_params: Tuple[float, float, int] = (-2, 2, 500),
|
|
379
379
|
return_domain: str = 'log_moneyness',
|
|
380
380
|
) -> Dict[str, Any]:
|
|
381
381
|
"""
|
|
@@ -384,8 +384,8 @@ class VolyClient:
|
|
|
384
384
|
Parameters:
|
|
385
385
|
- fit_results: DataFrame with fitting results from fit_model()
|
|
386
386
|
- option_chain: Optional market data for comparison
|
|
387
|
-
-
|
|
388
|
-
- return_domain: Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'delta')
|
|
387
|
+
- domain_params: Grid of log-moneyness values
|
|
388
|
+
- return_domain: Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'returns', 'delta')
|
|
389
389
|
|
|
390
390
|
Returns:
|
|
391
391
|
- Dictionary of plot figures
|
|
@@ -393,7 +393,7 @@ class VolyClient:
|
|
|
393
393
|
plots = {}
|
|
394
394
|
|
|
395
395
|
# Generate IV surface and domain
|
|
396
|
-
iv_surface, x_surface = get_iv_surface(fit_results,
|
|
396
|
+
iv_surface, x_surface = get_iv_surface(fit_results, domain_params, return_domain)
|
|
397
397
|
|
|
398
398
|
# Plot volatility smiles
|
|
399
399
|
plots['smiles'] = plot_all_smiles(
|
|
@@ -453,202 +453,19 @@ class VolyClient:
|
|
|
453
453
|
# -------------------------------------------------------------------------
|
|
454
454
|
|
|
455
455
|
@staticmethod
|
|
456
|
-
def get_rnd_surface(
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
Calculate risk-neutral density from fitted model.
|
|
461
|
-
|
|
462
|
-
Parameters:
|
|
456
|
+
def get_rnd_surface(model_results: pd.DataFrame,
|
|
457
|
+
domain_params: Tuple[float, float, int] = (-1.5, 1.5, 1000),
|
|
458
|
+
return_domain: str = 'log_moneyness',
|
|
459
|
+
method: str = 'rookley') -> Tuple[Dict[str, np.ndarray], Dict[str, np.ndarray], Dict[str, np.ndarray], pd.DataFrame]:
|
|
463
460
|
|
|
464
|
-
|
|
465
|
-
- Array with RND results over moneyness
|
|
466
|
-
"""
|
|
467
|
-
logger.info("Calculating risk-neutral density")
|
|
461
|
+
logger.info("Calculating RND surface")
|
|
468
462
|
|
|
469
463
|
# Generate the surface
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
return {
|
|
476
|
-
'moneyness_array': moneyness_array,
|
|
477
|
-
'rnd_surface': rnd_surface
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
@staticmethod
|
|
481
|
-
def pdf(rnd_results: Dict[str, Any],
|
|
482
|
-
maturity: Optional[str] = None,
|
|
483
|
-
plot: bool = False) -> Tuple[np.ndarray, np.ndarray]:
|
|
484
|
-
"""
|
|
485
|
-
Calculate probability density function (PDF) from RND results.
|
|
486
|
-
|
|
487
|
-
Parameters:
|
|
488
|
-
- rnd_results: Dictionary with RND results from rnd()
|
|
489
|
-
- maturity: Optional maturity name for a specific expiry
|
|
490
|
-
- plot: Whether to generate and return a plot
|
|
491
|
-
|
|
492
|
-
Returns:
|
|
493
|
-
- Tuple of (prices, pdf_values) and optional plot
|
|
494
|
-
"""
|
|
495
|
-
logger.info("Calculating PDF from RND")
|
|
496
|
-
|
|
497
|
-
# Extract required data
|
|
498
|
-
moneyness_grid = rnd_results['moneyness_grid']
|
|
499
|
-
rnd_surface = rnd_results['rnd_surface']
|
|
500
|
-
spot_price = rnd_results['spot_price']
|
|
501
|
-
|
|
502
|
-
# Select maturity
|
|
503
|
-
if maturity is None:
|
|
504
|
-
# Use first maturity if not specified
|
|
505
|
-
maturity = list(rnd_surface.keys())[0]
|
|
506
|
-
elif maturity not in rnd_surface:
|
|
507
|
-
raise VolyError(f"Maturity '{maturity}' not found in RND results")
|
|
508
|
-
|
|
509
|
-
# Get RND values for the selected maturity
|
|
510
|
-
rnd_values = rnd_surface[maturity]
|
|
511
|
-
|
|
512
|
-
# Calculate PDF
|
|
513
|
-
prices, pdf_values = calculate_pdf(moneyness_grid, rnd_values, spot_price)
|
|
514
|
-
|
|
515
|
-
result = (prices, pdf_values)
|
|
516
|
-
|
|
517
|
-
# Generate plot if requested
|
|
518
|
-
if plot:
|
|
519
|
-
logger.info(f"Generating PDF plot for {maturity}")
|
|
520
|
-
pdf_plot = plot_pdf(
|
|
521
|
-
moneyness_grid, rnd_values, spot_price,
|
|
522
|
-
title=f"Probability Density Function - {maturity}"
|
|
523
|
-
)
|
|
524
|
-
result = (prices, pdf_values, pdf_plot)
|
|
525
|
-
|
|
526
|
-
return result
|
|
527
|
-
|
|
528
|
-
@staticmethod
|
|
529
|
-
def cdf(rnd_results: Dict[str, Any],
|
|
530
|
-
maturity: Optional[str] = None,
|
|
531
|
-
plot: bool = False) -> Tuple[np.ndarray, np.ndarray]:
|
|
532
|
-
"""
|
|
533
|
-
Calculate cumulative distribution function (CDF) from RND results.
|
|
534
|
-
|
|
535
|
-
Parameters:
|
|
536
|
-
- rnd_results: Dictionary with RND results from rnd()
|
|
537
|
-
- maturity: Optional maturity name for a specific expiry
|
|
538
|
-
- plot: Whether to generate and return a plot
|
|
539
|
-
|
|
540
|
-
Returns:
|
|
541
|
-
- Tuple of (prices, cdf_values) and optional plot
|
|
542
|
-
"""
|
|
543
|
-
logger.info("Calculating CDF from RND")
|
|
544
|
-
|
|
545
|
-
# Extract required data
|
|
546
|
-
moneyness_grid = rnd_results['moneyness_grid']
|
|
547
|
-
rnd_surface = rnd_results['rnd_surface']
|
|
548
|
-
spot_price = rnd_results['spot_price']
|
|
549
|
-
|
|
550
|
-
# Select maturity
|
|
551
|
-
if maturity is None:
|
|
552
|
-
# Use first maturity if not specified
|
|
553
|
-
maturity = list(rnd_surface.keys())[0]
|
|
554
|
-
elif maturity not in rnd_surface:
|
|
555
|
-
raise VolyError(f"Maturity '{maturity}' not found in RND results")
|
|
556
|
-
|
|
557
|
-
# Get RND values for the selected maturity
|
|
558
|
-
rnd_values = rnd_surface[maturity]
|
|
559
|
-
|
|
560
|
-
# Calculate CDF
|
|
561
|
-
prices, cdf_values = calculate_cdf(moneyness_grid, rnd_values, spot_price)
|
|
562
|
-
|
|
563
|
-
result = (prices, cdf_values)
|
|
564
|
-
|
|
565
|
-
# Generate plot if requested
|
|
566
|
-
if plot:
|
|
567
|
-
logger.info(f"Generating CDF plot for {maturity}")
|
|
568
|
-
cdf_plot = plot_cdf(
|
|
569
|
-
moneyness_grid, rnd_values, spot_price,
|
|
570
|
-
title=f"Cumulative Distribution Function - {maturity}"
|
|
571
|
-
)
|
|
572
|
-
result = (prices, cdf_values, cdf_plot)
|
|
573
|
-
|
|
574
|
-
return result
|
|
575
|
-
|
|
576
|
-
@staticmethod
|
|
577
|
-
def probability(rnd_results: Dict[str, Any],
|
|
578
|
-
target_price: float,
|
|
579
|
-
maturity: Optional[str] = None,
|
|
580
|
-
direction: str = 'above') -> float:
|
|
581
|
-
"""
|
|
582
|
-
Calculate the probability of price being above or below a target price.
|
|
583
|
-
|
|
584
|
-
Parameters:
|
|
585
|
-
- rnd_results: Dictionary with RND results from rnd()
|
|
586
|
-
- target_price: Target price level
|
|
587
|
-
- maturity: Optional maturity name for a specific expiry
|
|
588
|
-
- direction: 'above' or 'below'
|
|
589
|
-
|
|
590
|
-
Returns:
|
|
591
|
-
- Probability (0 to 1)
|
|
592
|
-
"""
|
|
593
|
-
if direction not in ['above', 'below']:
|
|
594
|
-
raise VolyError("Direction must be 'above' or 'below'")
|
|
595
|
-
|
|
596
|
-
# Extract required data
|
|
597
|
-
moneyness_grid = rnd_results['moneyness_grid']
|
|
598
|
-
rnd_surface = rnd_results['rnd_surface']
|
|
599
|
-
spot_price = rnd_results['spot_price']
|
|
600
|
-
|
|
601
|
-
# Select maturity
|
|
602
|
-
if maturity is None:
|
|
603
|
-
# Use first maturity if not specified
|
|
604
|
-
maturity = list(rnd_surface.keys())[0]
|
|
605
|
-
elif maturity not in rnd_surface:
|
|
606
|
-
raise VolyError(f"Maturity '{maturity}' not found in RND results")
|
|
607
|
-
|
|
608
|
-
# Get RND values for the selected maturity
|
|
609
|
-
rnd_values = rnd_surface[maturity]
|
|
610
|
-
|
|
611
|
-
# Calculate probability
|
|
612
|
-
prob = calculate_strike_probability(
|
|
613
|
-
target_price, moneyness_grid, rnd_values, spot_price, direction
|
|
614
|
-
)
|
|
615
|
-
|
|
616
|
-
return prob
|
|
617
|
-
|
|
618
|
-
# -------------------------------------------------------------------------
|
|
619
|
-
# Interpolation
|
|
620
|
-
# -------------------------------------------------------------------------
|
|
621
|
-
|
|
622
|
-
@staticmethod
|
|
623
|
-
def interpolate(fit_results: Dict[str, Any],
|
|
624
|
-
specific_days: Optional[List[int]] = None,
|
|
625
|
-
num_points: int = 10,
|
|
626
|
-
method: str = 'cubic',
|
|
627
|
-
plot: bool = False) -> Dict[str, Any]:
|
|
628
|
-
"""
|
|
629
|
-
Interpolate a fitted model to specific days to expiry.
|
|
630
|
-
|
|
631
|
-
Parameters:
|
|
632
|
-
- fit_results: Dictionary with fitting results from fit_model()
|
|
633
|
-
- specific_days: Optional list of specific days to include (e.g., [7, 30, 90, 180])
|
|
634
|
-
- num_points: Number of points for regular grid if specific_days is None
|
|
635
|
-
- method: Interpolation method ('linear', 'cubic', 'pchip', etc.)
|
|
636
|
-
- plot: Whether to generate and return a plot
|
|
637
|
-
|
|
638
|
-
Returns:
|
|
639
|
-
- Dictionary with interpolation results and optional plot
|
|
640
|
-
"""
|
|
641
|
-
logger.info(f"Interpolating model with {method} method")
|
|
642
|
-
|
|
643
|
-
# Interpolate the model
|
|
644
|
-
interp_results = interpolate_model(
|
|
645
|
-
fit_results, specific_days, num_points, method
|
|
464
|
+
pdf_surface, cdf_surface, x_surface, moments = get_rnd_surface(
|
|
465
|
+
model_results=model_results,
|
|
466
|
+
domain_params=domain_params,
|
|
467
|
+
return_domain=return_domain,
|
|
468
|
+
method=method
|
|
646
469
|
)
|
|
647
470
|
|
|
648
|
-
|
|
649
|
-
if plot:
|
|
650
|
-
logger.info("Generating interpolated surface plot")
|
|
651
|
-
interp_plot = plot_interpolated_surface(interp_results)
|
|
652
|
-
interp_results['plot'] = interp_plot
|
|
653
|
-
|
|
654
|
-
return interp_results
|
|
471
|
+
return pdf_surface, cdf_surface, x_surface, moments
|