stochvolmodels 1.0.25__tar.gz → 1.0.26__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 (49) hide show
  1. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/PKG-INFO +14 -2
  2. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/README.md +13 -0
  3. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/pyproject.toml +1 -4
  4. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/__init__.py +3 -3
  5. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/data/option_chain.py +3 -4
  6. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_heston_sv_pricer.py +0 -2
  7. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_pricing_options_on_qvar.py +2 -3
  8. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/gmm_pricer.py +1 -55
  9. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/heston_pricer.py +1 -0
  10. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/logsv_params.py +6 -5
  11. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/tests/bsm_mgf_pricer.py +1 -1
  12. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/funcs.py +26 -0
  13. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/mc_payoffs.py +0 -1
  14. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/mgf_pricer.py +0 -1
  15. stochvolmodels-1.0.25/stochvolmodels/data/fetch_option_chain.py +0 -176
  16. stochvolmodels-1.0.25/stochvolmodels/examples/run_gmm_fit.py +0 -41
  17. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/LICENSE.txt +0 -0
  18. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/data/__init__.py +0 -0
  19. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/data/test_option_chain.py +0 -0
  20. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/quick_run_lognormal_sv_pricer.py +0 -0
  21. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_heston.py +0 -0
  22. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_lognormal_sv_pricer.py +0 -0
  23. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/__init__.py +0 -0
  24. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/__init__.py +0 -0
  25. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/bachelier.py +0 -0
  26. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/bsm.py +0 -0
  27. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/tdist.py +0 -0
  28. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/double_exp_pricer.py +0 -0
  29. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/factor_hjm_pricer.py +0 -0
  30. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_affine_expansion.py +0 -0
  31. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_core.py +0 -0
  32. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_evaluate.py +0 -0
  33. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_factor_basis.py +0 -0
  34. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_logsv_ivols.py +0 -0
  35. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_logsv_params.py +0 -0
  36. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_logsv_pricer.py +0 -0
  37. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/hawkes_jd_pricer.py +0 -0
  38. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/__init__.py +0 -0
  39. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/affine_expansion.py +0 -0
  40. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/vol_moments_ode.py +0 -0
  41. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv_pricer.py +0 -0
  42. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/model_pricer.py +0 -0
  43. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/tdist_pricer.py +0 -0
  44. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/tests/__init__.py +0 -0
  45. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/tests/qv_pricer.py +0 -0
  46. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/__init__.py +0 -0
  47. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/config.py +0 -0
  48. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/plots.py +0 -0
  49. {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/var_swap_pricer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: stochvolmodels
3
- Version: 1.0.25
3
+ Version: 1.0.26
4
4
  Summary: Implementation of stochastic volatility models for option pricing
5
5
  License: LICENSE.txt
6
6
  Keywords: volatility,options,Black-Scholes,Heston,Monte-Carlo
@@ -32,7 +32,6 @@ Requires-Dist: numpy (>=1.22.4)
32
32
  Requires-Dist: pandas (>=0.19)
33
33
  Requires-Dist: scipy (>=1.3)
34
34
  Requires-Dist: seaborn (>=0.11.2)
35
- Requires-Dist: statsmodels (>=0.13.0)
36
35
  Project-URL: Documentation, https://github.com/ArturSepp/StochVolModels
37
36
  Project-URL: Issues, https://github.com/ArturSepp/StochVolModels/issues
38
37
  Project-URL: Personal website, https://artursepp.com
@@ -75,6 +74,19 @@ Close using
75
74
  git clone https://github.com/ArturSepp/StochVolModels.git
76
75
  ```
77
76
 
77
+ Core dependencies:
78
+ python = ">=3.8",
79
+ numba = ">=0.56.4",
80
+ numpy = ">=1.22.4",
81
+ scipy = ">=1.10",
82
+ pandas = ">=2.2.0",
83
+ matplotlib = ">=3.2.2",
84
+ seaborn = ">=0.12.2"
85
+
86
+ Optional dependencies:
87
+ qis ">=2.1.38" (for running code in my_papers and volatility_book)
88
+
89
+
78
90
  # Table of contents
79
91
  1. [Model Interface](#introduction)
80
92
  1. [Log-normal stochastic volatility model](#logsv)
@@ -34,6 +34,19 @@ Close using
34
34
  git clone https://github.com/ArturSepp/StochVolModels.git
35
35
  ```
36
36
 
37
+ Core dependencies:
38
+ python = ">=3.8",
39
+ numba = ">=0.56.4",
40
+ numpy = ">=1.22.4",
41
+ scipy = ">=1.10",
42
+ pandas = ">=2.2.0",
43
+ matplotlib = ">=3.2.2",
44
+ seaborn = ">=0.12.2"
45
+
46
+ Optional dependencies:
47
+ qis ">=2.1.38" (for running code in my_papers and volatility_book)
48
+
49
+
37
50
  # Table of contents
38
51
  1. [Model Interface](#introduction)
39
52
  1. [Log-normal stochastic volatility model](#logsv)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "stochvolmodels"
3
- version = "1.0.25"
3
+ version = "1.0.26"
4
4
  description = "Implementation of stochastic volatility models for option pricing"
5
5
  license = "LICENSE.txt"
6
6
  authors = ["Artur Sepp <artursepp@gmail.com>"]
@@ -37,7 +37,6 @@ python = ">=3.8"
37
37
  numba = ">=0.55"
38
38
  numpy = ">=1.22.4"
39
39
  scipy = ">=1.3"
40
- statsmodels = ">=0.13.0"
41
40
  pandas = ">=0.19"
42
41
  matplotlib = ">=3.5.2"
43
42
  seaborn = ">=0.11.2"
@@ -45,5 +44,3 @@ seaborn = ">=0.11.2"
45
44
  [build-system]
46
45
  requires = ["poetry-core>=1.0.0"]
47
46
  build-backend = "poetry.core.masonry.api"
48
-
49
-
@@ -22,7 +22,8 @@ from stochvolmodels.utils.funcs import (
22
22
  to_flat_np_array,
23
23
  update_kwargs,
24
24
  ncdf,
25
- npdf
25
+ npdf,
26
+ find_nearest
26
27
  )
27
28
 
28
29
  from stochvolmodels.pricers.analytic.bsm import (
@@ -111,8 +112,7 @@ from stochvolmodels.pricers.logsv.logsv_params import LogSvParams
111
112
 
112
113
  from stochvolmodels.pricers.gmm_pricer import (
113
114
  GmmParams,
114
- GmmPricer,
115
- plot_gmm_pdfs
115
+ GmmPricer
116
116
  )
117
117
 
118
118
  from stochvolmodels.pricers.tdist_pricer import (
@@ -8,16 +8,15 @@ data is provided as:
8
8
  from __future__ import annotations
9
9
 
10
10
  import numpy as np
11
+ import pandas as pd
11
12
  from dataclasses import dataclass
12
13
  from typing import Tuple, Optional
13
-
14
- import pandas as pd
15
14
  from numba.typed import List
16
15
 
17
16
  import stochvolmodels.pricers.analytic.bsm as bsm
18
- from stochvolmodels.utils.var_swap_pricer import compute_var_swap_strike
19
- from stochvolmodels.pricers.factor_hjm.rate_core import get_default_swap_term_structure, swap_rate
20
17
  import stochvolmodels.pricers.analytic.bachelier as bachel
18
+ from stochvolmodels.utils.var_swap_pricer import compute_var_swap_strike
19
+ from stochvolmodels.pricers.factor_hjm.rate_core import get_default_swap_term_structure, swap_rate
21
20
 
22
21
 
23
22
  @dataclass
@@ -1,8 +1,6 @@
1
1
 
2
2
  import numpy as np
3
3
  import matplotlib.pyplot as plt
4
- from enum import Enum
5
-
6
4
  import stochvolmodels as sv
7
5
  from stochvolmodels import HestonPricer, HestonParams, OptionChain, BTC_HESTON_PARAMS
8
6
 
@@ -3,7 +3,6 @@ run valuation for options on quadratic variance
3
3
  """
4
4
  import numpy as np
5
5
  import matplotlib.pyplot as plt
6
- import qis as qis
7
6
  import stochvolmodels.data.test_option_chain as chains
8
7
  from numba.typed import List
9
8
  from stochvolmodels import (LogSVPricer, LogSvParams, compute_analytic_qvar, OptionChain,
@@ -37,7 +36,7 @@ fig1 = logsv_pricer.plot_model_ivols_vs_mc(option_chain=option_chain,
37
36
  params=LOGSV_BTC_PARAMS,
38
37
  variable_type=VariableType.Q_VAR,
39
38
  nb_path=nb_path)
40
- qis.set_suptitle(fig1, title='Implied variance skew by Log-Normal SV model')
39
+ fig1.suptitle('Implied variance skew by Log-Normal SV model')
41
40
 
42
41
  # run Heston prices
43
42
  heston_pricer = HestonPricer()
@@ -45,7 +44,7 @@ fig2 = heston_pricer.plot_model_ivols_vs_mc(option_chain=option_chain,
45
44
  params=BTC_HESTON_PARAMS,
46
45
  variable_type=VariableType.Q_VAR,
47
46
  nb_path=nb_path)
48
- qis.set_suptitle(fig2, title='Implied variance skew by Heston SV model')
47
+ fig2.suptitle('Implied variance skew by Heston SV model')
49
48
 
50
49
 
51
50
  plt.show()
@@ -4,16 +4,12 @@ implementation of gaussian mixture pricer and calibration
4
4
  import numpy as np
5
5
  import matplotlib.pyplot as plt
6
6
  from dataclasses import dataclass
7
-
8
- import pandas as pd
9
- import qis as qis
10
- import seaborn as sns
11
7
  from scipy.optimize import minimize
12
8
  from numba import njit
13
9
  from numba.typed import List
14
10
  from typing import Tuple
15
11
  from enum import Enum
16
-
12
+ # project
17
13
  import stochvolmodels.pricers.analytic.bsm as bsm
18
14
  from stochvolmodels.utils.funcs import to_flat_np_array, timer, npdf
19
15
  from stochvolmodels.pricers.model_pricer import ModelParams, ModelPricer
@@ -263,56 +259,6 @@ def gmm_vanilla_chain_pricer(gmm_weights: np.ndarray,
263
259
  return model_prices_ttms
264
260
 
265
261
 
266
- def plot_gmm_pdfs(params: GmmParams,
267
- option_chain0: OptionChain,
268
- nstdev: float = 10.0,
269
- titles: List[str] = None,
270
- axs: List[plt.Subplot] = None
271
- ) -> plt.Figure:
272
- """
273
- plot gmm pdf and model fit
274
- """
275
- stdev = nstdev * params.get_get_avg_vol() * np.sqrt(params.ttm)
276
- x = np.linspace(-stdev, stdev, 3000)
277
- state_pdfs, agg_pdf = params.compute_state_pdfs(x=x)
278
-
279
- columns = []
280
- for idx in range(len(params.gmm_weights)):
281
- columns.append(
282
- f"state-{idx + 1}: mean={params.gmm_mus[idx]:0.2f}, vol={params.gmm_vols[idx]:0.2f}, weight={params.gmm_weights[idx]:0.2f}")
283
-
284
- state_pdfs = pd.DataFrame(state_pdfs, index=x, columns=columns)
285
- agg_pdf = pd.Series(agg_pdf, index=x, name='Aggregate PDF')
286
- df = pd.concat([agg_pdf, state_pdfs], axis=1)
287
-
288
- kwargs = dict(fontsize=14, framealpha=0.80)
289
-
290
- if axs is None:
291
- with sns.axes_style("darkgrid"):
292
- fig, axs = plt.subplots(1, 2, figsize=(16, 4.5))
293
- else:
294
- fig = None
295
-
296
- qis.plot_line(df=df,
297
- linestyles=['--'] + ['-'] * len(params.gmm_weights),
298
- y_limits=(0.0, None),
299
- xvar_format='{:,.2f}',
300
- xlabel='log-price',
301
- first_color_fixed=True,
302
- ax=axs[0],
303
- **kwargs)
304
- axs[0].get_lines()[0].set_linewidth(4.0)
305
- axs[0].get_legend().get_lines()[0].set_linewidth(4.0)
306
- qis.set_title(ax=axs[0], title='(A) State PDF and Aggregate Risk-Neutral PDF', **kwargs)
307
-
308
- gmm_pricer = GmmPricer()
309
- gmm_pricer.plot_model_ivols_vs_bid_ask(option_chain=option_chain0, params=params,
310
- is_log_strike_xaxis=True,
311
- axs=[axs[1]],
312
- **kwargs)
313
- return fig
314
-
315
-
316
262
  class UnitTests(Enum):
317
263
  CALIBRATOR = 1
318
264
 
@@ -348,6 +348,7 @@ class UnitTests(Enum):
348
348
  MC_COMPARISION = 4
349
349
  MC_COMPARISION_QVAR = 5
350
350
 
351
+
351
352
  def run_unit_test(unit_test: UnitTests):
352
353
 
353
354
  import stochvolmodels.data.test_option_chain as chains
@@ -1,12 +1,13 @@
1
- from dataclasses import dataclass, asdict
2
- from typing import Optional, Dict, Any
3
-
1
+ """
2
+ implementation of log sv params
3
+ """
4
4
  import numpy as np
5
5
  import pandas as pd
6
6
  from numpy import linalg as la
7
- from qis import find_nearest
7
+ from dataclasses import dataclass, asdict
8
+ from typing import Optional, Dict, Any
8
9
 
9
- from stochvolmodels import VariableType
10
+ from stochvolmodels import VariableType, find_nearest
10
11
  from stochvolmodels.pricers.model_pricer import ModelParams
11
12
 
12
13
 
@@ -9,7 +9,7 @@ import seaborn as sns
9
9
  from typing import Tuple
10
10
  from enum import Enum
11
11
 
12
- from stochvolmodels.pricers.analytic import mgf_pricer as mgfp
12
+ import stochvolmodels.utils.mgf_pricer as mgfp
13
13
  from stochvolmodels.pricers.analytic.bsm import infer_bsm_ivols_from_model_chain_prices
14
14
  from stochvolmodels.utils.config import VariableType
15
15
 
@@ -94,3 +94,29 @@ def ncdf(x: Union[float, np.ndarray]) -> Union[float, np.ndarray]:
94
94
  @njit(cache=False, fastmath=True)
95
95
  def npdf(x: Union[float, np.ndarray], mu: float = 0.0, vol: float = 1.0) -> Union[float, np.ndarray]:
96
96
  return np.exp(-0.5*np.square((x-mu)/vol))/(vol*np.sqrt(2.0*np.pi))
97
+
98
+
99
+ def find_nearest(a: np.ndarray,
100
+ value: float,
101
+ is_sorted: bool = True,
102
+ is_equal_or_largest: bool = False
103
+ ) -> float:
104
+ """
105
+ find closes element
106
+ https://stackoverflow.com/questions/2566412/find-nearest-value-in-numpy-array
107
+ """
108
+ if is_sorted:
109
+ idx = np.searchsorted(a, value, side="left")
110
+ if is_equal_or_largest: # return the equal or largest element
111
+ return a[idx]
112
+ else:
113
+ if idx > 0 and (idx == len(a) or np.abs(value - a[idx - 1]) < np.abs(value - a[idx])):
114
+ return a[idx - 1]
115
+ else:
116
+ return a[idx]
117
+ else:
118
+ a = np.asarray(a)
119
+ idx = (np.abs(a - value)).argmin()
120
+ return a[idx]
121
+
122
+
@@ -4,7 +4,6 @@ Montecarlo analytics for option pay-off computations
4
4
 
5
5
  import numpy as np
6
6
  from numba import njit
7
-
8
7
  from stochvolmodels.utils.config import VariableType
9
8
 
10
9
 
@@ -5,7 +5,6 @@ generic analytics for option pricing using Fourier transforms of payoffs
5
5
  import numpy as np
6
6
  from numba import njit
7
7
  from typing import Tuple
8
-
9
8
  from stochvolmodels.utils.config import VariableType
10
9
 
11
10
 
@@ -1,176 +0,0 @@
1
- """
2
- this module is using option-chain-analytics package
3
- to fetch OptionChain data with options data
4
- see https://pypi.org/project/option-chain-analytics
5
- """
6
-
7
- import pandas as pd
8
- import numpy as np
9
- import matplotlib.pyplot as plt
10
- import qis
11
- from qis import TimePeriod
12
- from typing import Dict, Tuple, Optional, Literal
13
- from numba.typed import List
14
- from enum import Enum
15
-
16
- # chain
17
- from option_chain_analytics import OptionsDataDFs, create_chain_from_from_options_dfs
18
- from option_chain_analytics.option_chain import SliceColumn, SlicesChain
19
-
20
- # analytics
21
- from stochvolmodels.data.option_chain import OptionChain
22
-
23
-
24
- def generate_vol_chain_np(chain: SlicesChain,
25
- value_time: pd.Timestamp,
26
- days_map: Dict[str, int] = {'1w': 7, '1m': 21},
27
- delta_bounds: Tuple[Optional[float], Optional[float]] = (-0.1, 0.1),
28
- is_filtered: bool = True
29
- ) -> OptionChain:
30
- """
31
- given SlicesChain generate OptionChain for calibration inputs
32
- """
33
-
34
- ttms, future_prices, discfactors = List(), List(), List()
35
- optiontypes_ttms, strikes_ttms = List(), List()
36
- bid_ivs, ask_ivs = List(), List()
37
- bid_prices, ask_prices = List(), List()
38
- slice_ids = []
39
- for label, day in days_map.items():
40
- next_date = value_time + pd.DateOffset(days=day) # if overlapping next date will be last avilable maturity
41
- slice_date = chain.get_next_slice_after_date(mat_date=next_date)
42
- slice_t = chain.expiry_slices[slice_date]
43
- df = slice_t.get_joint_slice(delta_bounds=delta_bounds, is_filtered=is_filtered)
44
- if not df.empty:
45
- slice_ids.append(f"{label}: {slice_t.expiry_id}")
46
- ttms.append(slice_t.get_ttm())
47
- future_prices.append(slice_t.get_future_price())
48
- discfactors.append(1.0)
49
- strikes_ttms.append(df.index.to_numpy())
50
- optiontypes_ttms.append(df[SliceColumn.OPTION_TYPE].to_numpy(dtype=str))
51
- bid_ivs.append(df[SliceColumn.BID_IV].to_numpy())
52
- ask_ivs.append(df[SliceColumn.ASK_IV].to_numpy())
53
- bid_prices.append(df[SliceColumn.BID_PRICE].to_numpy())
54
- ask_prices.append(df[SliceColumn.ASK_PRICE].to_numpy())
55
-
56
- out = OptionChain(ttms=np.array(ttms),
57
- forwards=np.array(future_prices),
58
- discfactors=np.array(discfactors),
59
- ids=np.array(slice_ids),
60
- strikes_ttms=strikes_ttms,
61
- optiontypes_ttms=optiontypes_ttms,
62
- bid_ivs=bid_ivs,
63
- ask_ivs=ask_ivs,
64
- bid_prices=bid_prices,
65
- ask_prices=ask_prices)
66
- return out
67
-
68
-
69
- def load_option_chain(options_data_dfs: OptionsDataDFs,
70
- value_time: pd.Timestamp = pd.Timestamp('2023-02-06 08:00:00+00:00'),
71
- days_map: Dict[str, int] = {'1w': 7, '1m': 21},
72
- delta_bounds: Tuple[Optional[float], Optional[float]] = (-0.1, 0.1),
73
- is_filtered: bool = True
74
- ) -> Optional[OptionChain]:
75
- chain = create_chain_from_from_options_dfs(options_data_dfs=options_data_dfs, value_time=value_time)
76
- if chain is not None:
77
- option_chain = generate_vol_chain_np(chain=chain,
78
- value_time=value_time,
79
- days_map=days_map,
80
- delta_bounds=delta_bounds,
81
- is_filtered=is_filtered)
82
- else:
83
- option_chain = None
84
-
85
- return option_chain
86
-
87
-
88
- def sample_option_chain_at_times(options_data_dfs: OptionsDataDFs,
89
- time_period: TimePeriod,
90
- freq: str = 'W-FRI',
91
- days_map: Dict[str, int] = {'1w': 7, '1m': 21},
92
- delta_bounds: Tuple[Optional[float], Optional[float]] = (-0.1, 0.1),
93
- hour_offset: int = 8
94
- ) -> Dict[pd.Timestamp, OptionChain]:
95
- value_times = qis.generate_dates_schedule(time_period=time_period,
96
- freq=freq,
97
- hour_offset=hour_offset)
98
- option_chains = {}
99
- for value_time in value_times:
100
- option_chains[value_time] = load_option_chain(options_data_dfs=options_data_dfs,
101
- value_time=value_time,
102
- days_map=days_map,
103
- delta_bounds=delta_bounds,
104
- is_filtered=True)
105
- return option_chains
106
-
107
-
108
- def load_price_data(options_data_dfs: OptionsDataDFs,
109
- time_period: TimePeriod = None,
110
- data: Literal['spot', 'perp', 'funding_rate'] = 'spot',
111
- freq: Optional[str] = 'D' # to do
112
- ) -> pd.Series:
113
- #options_data_dfs = OptionsDataDFs(**ts_data_loader_wrapper(ticker=ticker, freq='D', hour_offset=8))
114
- spot_price = options_data_dfs.get_spot_data()[data]
115
- if freq is not None:
116
- spot_price = spot_price.resample(freq).last()
117
- if time_period is not None:
118
- spot_price = time_period.locate(spot_price)
119
- return spot_price
120
-
121
-
122
- class UnitTests(Enum):
123
- PRINT_CHAIN_DATA = 1
124
- GENERATE_VOL_CHAIN_NP = 2
125
- SAMPLE_CHAIN_AT_TIMES = 3
126
-
127
-
128
- def run_unit_test(unit_test: UnitTests):
129
-
130
- ticker = 'BTC' # BTC, ETH
131
- value_time = pd.Timestamp('2021-10-21 08:00:00+00:00')
132
- value_time = pd.Timestamp('2023-10-06 08:00:00+00:00')
133
-
134
- from option_chain_analytics.ts_loaders import ts_data_loader_wrapper
135
- options_data_dfs = OptionsDataDFs(**ts_data_loader_wrapper(ticker=ticker))
136
- options_data_dfs.get_start_end_date().print()
137
- chain = create_chain_from_from_options_dfs(options_data_dfs=options_data_dfs, value_time=value_time)
138
-
139
- if unit_test == UnitTests.PRINT_CHAIN_DATA:
140
- for expiry, eslice in chain.expiry_slices.items():
141
- eslice.print()
142
-
143
- elif unit_test == UnitTests.GENERATE_VOL_CHAIN_NP:
144
- option_chain = generate_vol_chain_np(chain=chain,
145
- value_time=value_time,
146
- days_map={'1w': 7},
147
- delta_bounds=(-0.1, 0.1),
148
- is_filtered=True)
149
- option_chain.print()
150
- skews = option_chain.get_chain_skews(delta=0.35)
151
- print(skews)
152
-
153
- elif unit_test == UnitTests.SAMPLE_CHAIN_AT_TIMES:
154
- time_period = qis.TimePeriod('01Jan2023', '31Jan2023', tz='UTC')
155
- option_chains = sample_option_chain_at_times(options_data_dfs=options_data_dfs,
156
- time_period=time_period,
157
- freq='W-FRI',
158
- hour_offset=9
159
- )
160
- for key, chain in option_chains.items():
161
- print(f"{key}")
162
- print(chain)
163
-
164
- plt.show()
165
-
166
-
167
- if __name__ == '__main__':
168
-
169
- unit_test = UnitTests.SAMPLE_CHAIN_AT_TIMES
170
-
171
- is_run_all_tests = False
172
- if is_run_all_tests:
173
- for unit_test in UnitTests:
174
- run_unit_test(unit_test=unit_test)
175
- else:
176
- run_unit_test(unit_test=unit_test)
@@ -1,41 +0,0 @@
1
- """
2
- example of fitting GMM
3
- see StochVolModels/examples/run_gmm_fit.py
4
- """
5
- import matplotlib.pyplot as plt
6
- import seaborn as sns
7
- import qis as qis
8
- from stochvolmodels import (get_btc_test_chain_data,
9
- get_spy_test_chain_data,
10
- OptionChain, GmmPricer,
11
- plot_gmm_pdfs)
12
-
13
- # get test option chain data
14
- # option_chain = get_btc_test_chain_data()
15
- option_chain = get_spy_test_chain_data()
16
-
17
- # run GMM fit
18
- gmm_pricer = GmmPricer()
19
- fit_params = gmm_pricer.calibrate_model_params_to_chain(option_chain=option_chain, n_mixtures=4)
20
-
21
- # illustrate fitted parameters and model fit to market bid-ask
22
- # plot two ids
23
- ids = ['2m', '6m']
24
- n = len(ids)
25
- with sns.axes_style('darkgrid'):
26
- fig, axs = plt.subplots(n, 2, figsize=(14, 12), tight_layout=True)
27
- # axs = qis.to_flat_list(axs)
28
- current_ax = 0
29
-
30
- for key, params in fit_params.items():
31
- print(f"{key}: {params}")
32
- if key in ids:
33
- option_chain0 = OptionChain.get_slices_as_chain(option_chain, ids=[key])
34
- # gmm_pricer.plot_model_ivols_vs_bid_ask(option_chain=option_chain0, params=params, axs=[axs[idx]])
35
- plot_gmm_pdfs(params=params, option_chain0=option_chain0, axs=axs[current_ax, :])
36
- qis.set_title(ax=axs[current_ax, 0], title=f"{key}-slice: (A) State PDF and Aggregate Risk-Neutral PDF")
37
- qis.set_title(ax=axs[current_ax, 1], title=f"{key}-slice: Model to Market Bid/Ask vols")
38
- current_ax += 1
39
-
40
- qis.set_suptitle(fig, title='Fit of 4-state GMM to SPY implied vols @ 15_Jul_2022_10_23_09')
41
- plt.show()