voly 0.0.86__tar.gz → 0.0.89__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.86/src/voly.egg-info → voly-0.0.89}/PKG-INFO +1 -1
- {voly-0.0.86 → voly-0.0.89}/pyproject.toml +2 -2
- {voly-0.0.86 → voly-0.0.89}/src/voly/client.py +20 -204
- voly-0.0.89/src/voly/core/charts.py +415 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly/core/data.py +1 -4
- {voly-0.0.86 → voly-0.0.89}/src/voly/core/fit.py +35 -43
- {voly-0.0.86 → voly-0.0.89}/src/voly/core/interpolate.py +5 -6
- voly-0.0.89/src/voly/core/rnd.py +288 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly/formulas.py +27 -29
- {voly-0.0.86 → voly-0.0.89}/src/voly/models.py +0 -6
- {voly-0.0.86 → voly-0.0.89/src/voly.egg-info}/PKG-INFO +1 -1
- {voly-0.0.86 → voly-0.0.89}/src/voly.egg-info/SOURCES.txt +1 -2
- voly-0.0.86/src/voly/core/charts.py +0 -922
- voly-0.0.86/src/voly/core/rnd.py +0 -367
- voly-0.0.86/tests/test_client.py +0 -244
- {voly-0.0.86 → voly-0.0.89}/LICENSE +0 -0
- {voly-0.0.86 → voly-0.0.89}/README.md +0 -0
- {voly-0.0.86 → voly-0.0.89}/setup.cfg +0 -0
- {voly-0.0.86 → voly-0.0.89}/setup.py +0 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly/__init__.py +0 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly/core/__init__.py +0 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly/exceptions.py +0 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly/utils/__init__.py +0 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly/utils/logger.py +0 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly.egg-info/dependency_links.txt +0 -0
- {voly-0.0.86 → voly-0.0.89}/src/voly.egg-info/requires.txt +0 -0
- {voly-0.0.86 → voly-0.0.89}/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.89"
|
|
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.89"
|
|
64
64
|
warn_return_any = true
|
|
65
65
|
warn_unused_configs = true
|
|
66
66
|
disallow_untyped_defs = true
|
|
@@ -19,12 +19,11 @@ from voly.formulas import (
|
|
|
19
19
|
)
|
|
20
20
|
from voly.core.data import fetch_option_chain, process_option_chain
|
|
21
21
|
from voly.core.fit import fit_model, get_iv_surface
|
|
22
|
-
from voly.core.rnd import get_rnd_surface
|
|
22
|
+
from voly.core.rnd import get_rnd_surface
|
|
23
23
|
from voly.core.interpolate import interpolate_model
|
|
24
24
|
from voly.core.charts import (
|
|
25
25
|
plot_all_smiles, plot_raw_parameters, plot_jw_parameters, plot_fit_performance, plot_3d_surface,
|
|
26
|
-
plot_fit_performance
|
|
27
|
-
plot_rnd_3d, plot_rnd_statistics, plot_interpolated_surface
|
|
26
|
+
plot_fit_performance
|
|
28
27
|
)
|
|
29
28
|
|
|
30
29
|
|
|
@@ -349,7 +348,7 @@ class VolyClient:
|
|
|
349
348
|
|
|
350
349
|
@staticmethod
|
|
351
350
|
def get_iv_surface(model_results: pd.DataFrame,
|
|
352
|
-
|
|
351
|
+
domain_params: Tuple[float, float, int] = (-2, 2, 500),
|
|
353
352
|
return_domain: str = 'log_moneyness',
|
|
354
353
|
) -> Dict[str, Any]:
|
|
355
354
|
"""
|
|
@@ -357,7 +356,7 @@ class VolyClient:
|
|
|
357
356
|
|
|
358
357
|
Parameters:
|
|
359
358
|
- model_results: DataFrame from fit_model() or interpolate_model()
|
|
360
|
-
-
|
|
359
|
+
- domain_params: Tuple of (min, max, num_points) for the moneyness grid
|
|
361
360
|
- return_domain: str Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'delta')
|
|
362
361
|
|
|
363
362
|
Returns:
|
|
@@ -366,7 +365,7 @@ class VolyClient:
|
|
|
366
365
|
# Generate the surface
|
|
367
366
|
iv_surface, x_surface = get_iv_surface(
|
|
368
367
|
model_results=model_results,
|
|
369
|
-
|
|
368
|
+
domain_params=domain_params,
|
|
370
369
|
return_domain=return_domain
|
|
371
370
|
)
|
|
372
371
|
|
|
@@ -375,7 +374,7 @@ class VolyClient:
|
|
|
375
374
|
@staticmethod
|
|
376
375
|
def plot_model(fit_results: pd.DataFrame,
|
|
377
376
|
option_chain: pd.DataFrame = None,
|
|
378
|
-
|
|
377
|
+
domain_params: Tuple[float, float, int] = (-2, 2, 500),
|
|
379
378
|
return_domain: str = 'log_moneyness',
|
|
380
379
|
) -> Dict[str, Any]:
|
|
381
380
|
"""
|
|
@@ -384,8 +383,8 @@ class VolyClient:
|
|
|
384
383
|
Parameters:
|
|
385
384
|
- fit_results: DataFrame with fitting results from fit_model()
|
|
386
385
|
- option_chain: Optional market data for comparison
|
|
387
|
-
-
|
|
388
|
-
- return_domain: Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'delta')
|
|
386
|
+
- domain_params: Grid of log-moneyness values
|
|
387
|
+
- return_domain: Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'returns', 'delta')
|
|
389
388
|
|
|
390
389
|
Returns:
|
|
391
390
|
- Dictionary of plot figures
|
|
@@ -393,7 +392,7 @@ class VolyClient:
|
|
|
393
392
|
plots = {}
|
|
394
393
|
|
|
395
394
|
# Generate IV surface and domain
|
|
396
|
-
iv_surface, x_surface = get_iv_surface(fit_results,
|
|
395
|
+
iv_surface, x_surface = get_iv_surface(fit_results, domain_params, return_domain)
|
|
397
396
|
|
|
398
397
|
# Plot volatility smiles
|
|
399
398
|
plots['smiles'] = plot_all_smiles(
|
|
@@ -453,202 +452,19 @@ class VolyClient:
|
|
|
453
452
|
# -------------------------------------------------------------------------
|
|
454
453
|
|
|
455
454
|
@staticmethod
|
|
456
|
-
def get_rnd_surface(
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
Calculate risk-neutral density from fitted model.
|
|
461
|
-
|
|
462
|
-
Parameters:
|
|
455
|
+
def get_rnd_surface(model_results: pd.DataFrame,
|
|
456
|
+
domain_params: Tuple[float, float, int] = (-1.5, 1.5, 1000),
|
|
457
|
+
return_domain: str = 'log_moneyness',
|
|
458
|
+
method: str = 'rookley') -> Tuple[Dict[str, np.ndarray], Dict[str, np.ndarray], Dict[str, np.ndarray], pd.DataFrame]:
|
|
463
459
|
|
|
464
|
-
|
|
465
|
-
- Array with RND results over moneyness
|
|
466
|
-
"""
|
|
467
|
-
logger.info("Calculating risk-neutral density")
|
|
460
|
+
logger.info("Calculating RND surface")
|
|
468
461
|
|
|
469
462
|
# 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
|
|
463
|
+
pdf_surface, cdf_surface, x_surface, moments = get_rnd_surface(
|
|
464
|
+
model_results=model_results,
|
|
465
|
+
domain_params=domain_params,
|
|
466
|
+
return_domain=return_domain,
|
|
467
|
+
method=method
|
|
646
468
|
)
|
|
647
469
|
|
|
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
|
|
470
|
+
return pdf_surface, cdf_surface, x_surface, moments
|