stochvolmodels 1.0.27__tar.gz → 1.0.29__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.27 → stochvolmodels-1.0.29}/PKG-INFO +1 -1
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/pyproject.toml +1 -1
- stochvolmodels-1.0.29/stochvolmodels/data/fetch_option_chain.py +174 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/examples/run_lognormal_sv_pricer.py +12 -12
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/logsv_pricer.py +2 -2
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/LICENSE.txt +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/README.md +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/__init__.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/data/__init__.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/data/option_chain.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/data/test_option_chain.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/examples/quick_run_lognormal_sv_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/examples/run_heston.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/examples/run_heston_sv_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/examples/run_pricing_options_on_qvar.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/__init__.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/analytic/__init__.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/analytic/bachelier.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/analytic/bsm.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/analytic/tdist.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/double_exp_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/factor_hjm_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/rate_affine_expansion.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/rate_core.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/rate_evaluate.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/rate_factor_basis.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/rate_logsv_ivols.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/rate_logsv_params.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/rate_logsv_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/gmm_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/hawkes_jd_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/heston_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/logsv/__init__.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/logsv/affine_expansion.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/logsv/logsv_params.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/logsv/vol_moments_ode.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/model_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/tdist_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/tests/__init__.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/tests/bsm_mgf_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/tests/qv_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/utils/__init__.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/utils/config.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/utils/funcs.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/utils/mc_payoffs.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/utils/mgf_pricer.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/utils/plots.py +0 -0
- {stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/utils/var_swap_pricer.py +0 -0
|
@@ -0,0 +1,174 @@
|
|
|
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
|
+
from qis import TimePeriod
|
|
11
|
+
from typing import Dict, Tuple, Optional, Literal
|
|
12
|
+
from numba.typed import List
|
|
13
|
+
from enum import Enum
|
|
14
|
+
import qis as qis
|
|
15
|
+
# chain
|
|
16
|
+
from option_chain_analytics import OptionsDataDFs, create_chain_from_from_options_dfs
|
|
17
|
+
from option_chain_analytics.option_chain import SliceColumn, SlicesChain
|
|
18
|
+
# analytics
|
|
19
|
+
from stochvolmodels.data.option_chain import OptionChain
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def generate_vol_chain_np(chain: SlicesChain,
|
|
23
|
+
value_time: pd.Timestamp,
|
|
24
|
+
days_map: Dict[str, int] = {'1w': 7, '1m': 21},
|
|
25
|
+
delta_bounds: Tuple[Optional[float], Optional[float]] = (-0.1, 0.1),
|
|
26
|
+
is_filtered: bool = True
|
|
27
|
+
) -> OptionChain:
|
|
28
|
+
"""
|
|
29
|
+
given SlicesChain generate OptionChain for calibration inputs
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
ttms, future_prices, discfactors = List(), List(), List()
|
|
33
|
+
optiontypes_ttms, strikes_ttms = List(), List()
|
|
34
|
+
bid_ivs, ask_ivs = List(), List()
|
|
35
|
+
bid_prices, ask_prices = List(), List()
|
|
36
|
+
slice_ids = []
|
|
37
|
+
for label, day in days_map.items():
|
|
38
|
+
next_date = value_time + pd.DateOffset(days=day) # if overlapping next date will be last avilable maturity
|
|
39
|
+
slice_date = chain.get_next_slice_after_date(mat_date=next_date)
|
|
40
|
+
slice_t = chain.expiry_slices[slice_date]
|
|
41
|
+
df = slice_t.get_joint_slice(delta_bounds=delta_bounds, is_filtered=is_filtered)
|
|
42
|
+
if not df.empty:
|
|
43
|
+
slice_ids.append(f"{label}: {slice_t.expiry_id}")
|
|
44
|
+
ttms.append(slice_t.get_ttm())
|
|
45
|
+
future_prices.append(slice_t.get_future_price())
|
|
46
|
+
discfactors.append(1.0)
|
|
47
|
+
strikes_ttms.append(df.index.to_numpy())
|
|
48
|
+
optiontypes_ttms.append(df[SliceColumn.OPTION_TYPE].to_numpy(dtype=str))
|
|
49
|
+
bid_ivs.append(df[SliceColumn.BID_IV].to_numpy())
|
|
50
|
+
ask_ivs.append(df[SliceColumn.ASK_IV].to_numpy())
|
|
51
|
+
bid_prices.append(df[SliceColumn.BID_PRICE].to_numpy())
|
|
52
|
+
ask_prices.append(df[SliceColumn.ASK_PRICE].to_numpy())
|
|
53
|
+
|
|
54
|
+
out = OptionChain(ttms=np.array(ttms),
|
|
55
|
+
forwards=np.array(future_prices),
|
|
56
|
+
discfactors=np.array(discfactors),
|
|
57
|
+
ids=np.array(slice_ids),
|
|
58
|
+
strikes_ttms=strikes_ttms,
|
|
59
|
+
optiontypes_ttms=optiontypes_ttms,
|
|
60
|
+
bid_ivs=bid_ivs,
|
|
61
|
+
ask_ivs=ask_ivs,
|
|
62
|
+
bid_prices=bid_prices,
|
|
63
|
+
ask_prices=ask_prices)
|
|
64
|
+
return out
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def load_option_chain(options_data_dfs: OptionsDataDFs,
|
|
68
|
+
value_time: pd.Timestamp = pd.Timestamp('2023-02-06 08:00:00+00:00'),
|
|
69
|
+
days_map: Dict[str, int] = {'1w': 7, '1m': 21},
|
|
70
|
+
delta_bounds: Tuple[Optional[float], Optional[float]] = (-0.1, 0.1),
|
|
71
|
+
is_filtered: bool = True
|
|
72
|
+
) -> Optional[OptionChain]:
|
|
73
|
+
chain = create_chain_from_from_options_dfs(options_data_dfs=options_data_dfs, value_time=value_time)
|
|
74
|
+
if chain is not None:
|
|
75
|
+
option_chain = generate_vol_chain_np(chain=chain,
|
|
76
|
+
value_time=value_time,
|
|
77
|
+
days_map=days_map,
|
|
78
|
+
delta_bounds=delta_bounds,
|
|
79
|
+
is_filtered=is_filtered)
|
|
80
|
+
else:
|
|
81
|
+
option_chain = None
|
|
82
|
+
|
|
83
|
+
return option_chain
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def sample_option_chain_at_times(options_data_dfs: OptionsDataDFs,
|
|
87
|
+
time_period: TimePeriod,
|
|
88
|
+
freq: str = 'W-FRI',
|
|
89
|
+
days_map: Dict[str, int] = {'1w': 7, '1m': 21},
|
|
90
|
+
delta_bounds: Tuple[Optional[float], Optional[float]] = (-0.1, 0.1),
|
|
91
|
+
hour_offset: int = 8
|
|
92
|
+
) -> Dict[pd.Timestamp, OptionChain]:
|
|
93
|
+
value_times = qis.generate_dates_schedule(time_period=time_period,
|
|
94
|
+
freq=freq,
|
|
95
|
+
hour_offset=hour_offset)
|
|
96
|
+
option_chains = {}
|
|
97
|
+
for value_time in value_times:
|
|
98
|
+
option_chains[value_time] = load_option_chain(options_data_dfs=options_data_dfs,
|
|
99
|
+
value_time=value_time,
|
|
100
|
+
days_map=days_map,
|
|
101
|
+
delta_bounds=delta_bounds,
|
|
102
|
+
is_filtered=True)
|
|
103
|
+
return option_chains
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def load_price_data(options_data_dfs: OptionsDataDFs,
|
|
107
|
+
time_period: TimePeriod = None,
|
|
108
|
+
data: Literal['spot', 'perp', 'funding_rate'] = 'spot',
|
|
109
|
+
freq: Optional[str] = 'D' # to do
|
|
110
|
+
) -> pd.Series:
|
|
111
|
+
#options_data_dfs = OptionsDataDFs(**ts_data_loader_wrapper(ticker=ticker, freq='D', hour_offset=8))
|
|
112
|
+
spot_price = options_data_dfs.get_spot_data()[data]
|
|
113
|
+
if freq is not None:
|
|
114
|
+
spot_price = spot_price.resample(freq).last()
|
|
115
|
+
if time_period is not None:
|
|
116
|
+
spot_price = time_period.locate(spot_price)
|
|
117
|
+
return spot_price
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class UnitTests(Enum):
|
|
121
|
+
PRINT_CHAIN_DATA = 1
|
|
122
|
+
GENERATE_VOL_CHAIN_NP = 2
|
|
123
|
+
SAMPLE_CHAIN_AT_TIMES = 3
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def run_unit_test(unit_test: UnitTests):
|
|
127
|
+
|
|
128
|
+
ticker = 'BTC' # BTC, ETH
|
|
129
|
+
value_time = pd.Timestamp('2021-10-21 08:00:00+00:00')
|
|
130
|
+
value_time = pd.Timestamp('2023-10-06 08:00:00+00:00')
|
|
131
|
+
|
|
132
|
+
from option_chain_analytics.ts_loaders import ts_data_loader_wrapper
|
|
133
|
+
options_data_dfs = OptionsDataDFs(**ts_data_loader_wrapper(ticker=ticker))
|
|
134
|
+
options_data_dfs.get_start_end_date().print()
|
|
135
|
+
chain = create_chain_from_from_options_dfs(options_data_dfs=options_data_dfs, value_time=value_time)
|
|
136
|
+
|
|
137
|
+
if unit_test == UnitTests.PRINT_CHAIN_DATA:
|
|
138
|
+
for expiry, eslice in chain.expiry_slices.items():
|
|
139
|
+
eslice.print()
|
|
140
|
+
|
|
141
|
+
elif unit_test == UnitTests.GENERATE_VOL_CHAIN_NP:
|
|
142
|
+
option_chain = generate_vol_chain_np(chain=chain,
|
|
143
|
+
value_time=value_time,
|
|
144
|
+
days_map={'1w': 7},
|
|
145
|
+
delta_bounds=(-0.1, 0.1),
|
|
146
|
+
is_filtered=True)
|
|
147
|
+
option_chain.print()
|
|
148
|
+
skews = option_chain.get_chain_skews(delta=0.35)
|
|
149
|
+
print(skews)
|
|
150
|
+
|
|
151
|
+
elif unit_test == UnitTests.SAMPLE_CHAIN_AT_TIMES:
|
|
152
|
+
time_period = qis.TimePeriod('01Jan2023', '31Jan2023', tz='UTC')
|
|
153
|
+
option_chains = sample_option_chain_at_times(options_data_dfs=options_data_dfs,
|
|
154
|
+
time_period=time_period,
|
|
155
|
+
freq='W-FRI',
|
|
156
|
+
hour_offset=9
|
|
157
|
+
)
|
|
158
|
+
for key, chain in option_chains.items():
|
|
159
|
+
print(f"{key}")
|
|
160
|
+
print(chain)
|
|
161
|
+
|
|
162
|
+
plt.show()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if __name__ == '__main__':
|
|
166
|
+
|
|
167
|
+
unit_test = UnitTests.SAMPLE_CHAIN_AT_TIMES
|
|
168
|
+
|
|
169
|
+
is_run_all_tests = False
|
|
170
|
+
if is_run_all_tests:
|
|
171
|
+
for unit_test in UnitTests:
|
|
172
|
+
run_unit_test(unit_test=unit_test)
|
|
173
|
+
else:
|
|
174
|
+
run_unit_test(unit_test=unit_test)
|
{stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/examples/run_lognormal_sv_pricer.py
RENAMED
|
@@ -97,17 +97,6 @@ def run_unit_test(unit_test: UnitTests):
|
|
|
97
97
|
logsv_pricer.plot_model_ivols_vs_bid_ask(option_chain=btc_option_chain,
|
|
98
98
|
params=btc_calibrated_params)
|
|
99
99
|
|
|
100
|
-
elif unit_test == UnitTests.CALIBRATE_MODEL_TO_BTC_OPTIONS:
|
|
101
|
-
btc_option_chain = sv.get_btc_test_chain_data()
|
|
102
|
-
params0 = LogSvParams(sigma0=0.8, theta=1.0, kappa1=2.21, kappa2=2.18, beta=0.15, volvol=2.0)
|
|
103
|
-
btc_calibrated_params = logsv_pricer.calibrate_model_params_to_chain(option_chain=btc_option_chain,
|
|
104
|
-
params0=params0,
|
|
105
|
-
model_calibration_type=LogsvModelCalibrationType.PARAMS4,
|
|
106
|
-
constraints_type=sv.ConstraintsType.INVERSE_MARTINGALE)
|
|
107
|
-
print(btc_calibrated_params)
|
|
108
|
-
logsv_pricer.plot_model_ivols_vs_bid_ask(option_chain=btc_option_chain,
|
|
109
|
-
params=btc_calibrated_params)
|
|
110
|
-
|
|
111
100
|
elif unit_test == UnitTests.MC_WITH_FIXED_RANDOMS:
|
|
112
101
|
btc_option_chain = sv.get_btc_test_chain_data()
|
|
113
102
|
W0s, W1s, dts = sv.get_randoms_for_chain_valuation(ttms=btc_option_chain.ttms,
|
|
@@ -138,6 +127,17 @@ def run_unit_test(unit_test: UnitTests):
|
|
|
138
127
|
option_prices_ttm, option_std_ttm = sv.logsv_mc_chain_pricer_fixed_randoms(**args)
|
|
139
128
|
print(option_prices_ttm)
|
|
140
129
|
|
|
130
|
+
elif unit_test == UnitTests.CALIBRATE_MODEL_TO_BTC_OPTIONS:
|
|
131
|
+
btc_option_chain = sv.get_btc_test_chain_data()
|
|
132
|
+
params0 = LogSvParams(sigma0=0.8, theta=1.0, kappa1=2.21, kappa2=2.18, beta=0.15, volvol=2.0)
|
|
133
|
+
btc_calibrated_params = logsv_pricer.calibrate_model_params_to_chain(option_chain=btc_option_chain,
|
|
134
|
+
params0=params0,
|
|
135
|
+
model_calibration_type=LogsvModelCalibrationType.PARAMS4,
|
|
136
|
+
constraints_type=sv.ConstraintsType.INVERSE_MARTINGALE)
|
|
137
|
+
print(btc_calibrated_params)
|
|
138
|
+
logsv_pricer.plot_model_ivols_vs_bid_ask(option_chain=btc_option_chain,
|
|
139
|
+
params=btc_calibrated_params)
|
|
140
|
+
|
|
141
141
|
elif unit_test == UnitTests.CALIBRATE_MODEL_TO_BTC_OPTIONS_WITH_MC:
|
|
142
142
|
btc_option_chain = sv.get_btc_test_chain_data()
|
|
143
143
|
params0 = LogSvParams(sigma0=0.8, theta=1.0, kappa1=2.21, kappa2=2.18, beta=0.15, volvol=2.0)
|
|
@@ -157,7 +157,7 @@ def run_unit_test(unit_test: UnitTests):
|
|
|
157
157
|
|
|
158
158
|
if __name__ == '__main__':
|
|
159
159
|
|
|
160
|
-
unit_test = UnitTests.
|
|
160
|
+
unit_test = UnitTests.CALIBRATE_MODEL_TO_BTC_OPTIONS
|
|
161
161
|
|
|
162
162
|
is_run_all_tests = False
|
|
163
163
|
if is_run_all_tests:
|
|
@@ -204,8 +204,8 @@ class LogSVPricer(ModelPricer):
|
|
|
204
204
|
volvol=params.volvol,
|
|
205
205
|
vol_backbone_etas=params.get_vol_backbone_etas(ttms=option_chain.ttms))
|
|
206
206
|
model_vols = option_chain.compute_model_ivols_from_chain_data(model_prices=option_prices_ttm)
|
|
207
|
-
print(f"option_prices_ttm\n{option_prices_ttm}")
|
|
208
|
-
print(f"model_vols\n{model_vols}")
|
|
207
|
+
# print(f"option_prices_ttm\n{option_prices_ttm}")
|
|
208
|
+
# print(f"model_vols\n{model_vols}")
|
|
209
209
|
|
|
210
210
|
else:
|
|
211
211
|
raise NotImplementedError(f"{calibration_engine}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/examples/run_heston_sv_pricer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/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.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/factor_hjm/rate_core.py
RENAMED
|
File without changes
|
{stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/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
|
|
File without changes
|
|
File without changes
|
{stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/logsv/affine_expansion.py
RENAMED
|
File without changes
|
{stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/stochvolmodels/pricers/logsv/logsv_params.py
RENAMED
|
File without changes
|
{stochvolmodels-1.0.27 → stochvolmodels-1.0.29}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|