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.
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/PKG-INFO +14 -2
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/README.md +13 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/pyproject.toml +1 -4
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/__init__.py +3 -3
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/data/option_chain.py +3 -4
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_heston_sv_pricer.py +0 -2
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_pricing_options_on_qvar.py +2 -3
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/gmm_pricer.py +1 -55
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/heston_pricer.py +1 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/logsv_params.py +6 -5
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/tests/bsm_mgf_pricer.py +1 -1
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/funcs.py +26 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/mc_payoffs.py +0 -1
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/mgf_pricer.py +0 -1
- stochvolmodels-1.0.25/stochvolmodels/data/fetch_option_chain.py +0 -176
- stochvolmodels-1.0.25/stochvolmodels/examples/run_gmm_fit.py +0 -41
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/LICENSE.txt +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/data/__init__.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/data/test_option_chain.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/quick_run_lognormal_sv_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_heston.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_lognormal_sv_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/__init__.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/__init__.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/bachelier.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/bsm.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/tdist.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/double_exp_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/factor_hjm_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_affine_expansion.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_core.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_evaluate.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_factor_basis.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_logsv_ivols.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_logsv_params.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_logsv_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/hawkes_jd_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/__init__.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/affine_expansion.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/vol_moments_ode.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/model_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/tdist_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/tests/__init__.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/tests/qv_pricer.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/__init__.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/config.py +0 -0
- {stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/utils/plots.py +0 -0
- {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.
|
|
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.
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
{stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/logsv_params.py
RENAMED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
|
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
|
-
|
|
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
|
+
|
|
@@ -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()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/examples/run_lognormal_sv_pricer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/analytic/bachelier.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_core.py
RENAMED
|
File without changes
|
{stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/factor_hjm/rate_evaluate.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/affine_expansion.py
RENAMED
|
File without changes
|
{stochvolmodels-1.0.25 → stochvolmodels-1.0.26}/stochvolmodels/pricers/logsv/vol_moments_ode.py
RENAMED
|
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
|