stochvolmodels 1.0.21__tar.gz → 1.0.22__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.21 → stochvolmodels-1.0.22}/PKG-INFO +1 -1
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/pyproject.toml +1 -1
- stochvolmodels-1.0.21/stochvolmodels/my_papers/forward_var/calibrate_forward_var.py +0 -115
- stochvolmodels-1.0.21/stochvolmodels/my_papers/il_hedging/README.md +0 -8
- stochvolmodels-1.0.21/stochvolmodels/my_papers/il_hedging/logsv_figures.py +0 -61
- stochvolmodels-1.0.21/stochvolmodels/my_papers/il_hedging/run_logsv_for_il_payoff.py +0 -150
- stochvolmodels-1.0.21/stochvolmodels/my_papers/inverse_options/README.md +0 -10
- stochvolmodels-1.0.21/stochvolmodels/my_papers/inverse_options/compare_net_delta.py +0 -168
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/README.md +0 -13
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/article_figures.py +0 -325
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/calibrations.py +0 -198
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/compare_admis_reg.py +0 -128
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/model_fit_to_options_timeseries.py +0 -253
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/moments_vol_qvar.py +0 -240
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/ode_sol_in_time.py +0 -308
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/steady_state_pdf.py +0 -251
- stochvolmodels-1.0.21/stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift/vol_drift.py +0 -82
- stochvolmodels-1.0.21/stochvolmodels/my_papers/risk_premia/check_kernel.py +0 -20
- stochvolmodels-1.0.21/stochvolmodels/my_papers/risk_premia/gmm_slides.py +0 -501
- stochvolmodels-1.0.21/stochvolmodels/my_papers/risk_premia/q_kernel.py +0 -53
- stochvolmodels-1.0.21/stochvolmodels/my_papers/t_distribution/illustrations.py +0 -197
- stochvolmodels-1.0.21/stochvolmodels/my_papers/t_distribution/market_data_fit.py +0 -66
- stochvolmodels-1.0.21/stochvolmodels/my_papers/t_distribution/mc_pricer_with_kernel.py +0 -97
- stochvolmodels-1.0.21/stochvolmodels/my_papers/volatility_models/README.md +0 -10
- stochvolmodels-1.0.21/stochvolmodels/my_papers/volatility_models/article_figures.py +0 -216
- stochvolmodels-1.0.21/stochvolmodels/my_papers/volatility_models/autocorr_fit.py +0 -236
- stochvolmodels-1.0.21/stochvolmodels/my_papers/volatility_models/load_data.py +0 -64
- stochvolmodels-1.0.21/stochvolmodels/my_papers/volatility_models/ss_distribution_fit.py +0 -327
- stochvolmodels-1.0.21/stochvolmodels/my_papers/volatility_models/vol_beta.py +0 -60
- stochvolmodels-1.0.21/stochvolmodels/utils/__init__.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/LICENSE.txt +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/README.md +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/__init__.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/data/__init__.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/data/fetch_option_chain.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/data/option_chain.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/data/test_option_chain.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/examples/quick_run_lognormal_sv_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/examples/run_gmm_fit.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/examples/run_heston.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/examples/run_heston_sv_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/examples/run_lognormal_sv_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/examples/run_pricing_options_on_qvar.py +0 -0
- {stochvolmodels-1.0.21/stochvolmodels/my_papers → stochvolmodels-1.0.22/stochvolmodels/pricers}/__init__.py +0 -0
- {stochvolmodels-1.0.21/stochvolmodels/pricers → stochvolmodels-1.0.22/stochvolmodels/pricers/analytic}/__init__.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/analytic/bachelier.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/analytic/bsm.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/analytic/tdist.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/gmm_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/hawkes_jd_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/heston_pricer.py +0 -0
- {stochvolmodels-1.0.21/stochvolmodels/pricers/analytic → stochvolmodels-1.0.22/stochvolmodels/pricers/logsv}/__init__.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/logsv/affine_expansion.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/logsv/logsv_params.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/logsv/vol_moments_ode.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/logsv_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/model_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/pricers/tdist_pricer.py +0 -0
- {stochvolmodels-1.0.21/stochvolmodels/pricers/logsv → stochvolmodels-1.0.22/stochvolmodels/tests}/__init__.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/tests/bsm_mgf_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/tests/qv_pricer.py +0 -0
- {stochvolmodels-1.0.21/stochvolmodels/tests → stochvolmodels-1.0.22/stochvolmodels/utils}/__init__.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/utils/config.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/utils/funcs.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/utils/mc_payoffs.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/utils/mgf_pricer.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/utils/plots.py +0 -0
- {stochvolmodels-1.0.21 → stochvolmodels-1.0.22}/stochvolmodels/utils/var_swap_pricer.py +0 -0
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# packages
|
|
2
|
-
import numpy as np
|
|
3
|
-
import pandas as pd
|
|
4
|
-
import matplotlib.pyplot as plt
|
|
5
|
-
from enum import Enum
|
|
6
|
-
|
|
7
|
-
import qis
|
|
8
|
-
|
|
9
|
-
# project
|
|
10
|
-
import stochvolmodels as sv
|
|
11
|
-
from stochvolmodels.pricers.logsv_pricer import LogSVPricer, LogsvModelCalibrationType
|
|
12
|
-
from stochvolmodels.pricers.logsv.vol_moments_ode import fit_model_vol_backbone_to_varswaps
|
|
13
|
-
from stochvolmodels import LogSvParams
|
|
14
|
-
from stochvolmodels.utils.funcs import set_seed
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class UnitTests(Enum):
|
|
18
|
-
VARSWAP_FIT = 1
|
|
19
|
-
CALIBRATE_4PARAM_MODEL = 2
|
|
20
|
-
CALIBRATE_VARSWAP_PARAM_MODEL = 3
|
|
21
|
-
COMPARE_MODEL_VOLS_TO_MC = 4
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def run_unit_test(unit_test: UnitTests):
|
|
25
|
-
|
|
26
|
-
set_seed(24)
|
|
27
|
-
|
|
28
|
-
logsv_pricer = LogSVPricer()
|
|
29
|
-
option_chain = sv.get_btc_test_chain_data()
|
|
30
|
-
|
|
31
|
-
local_path = "C://Users//artur//OneDrive//My Papers//MyPresentations//Crypto Vols Tartu. Zurich. Aug 2022//figures//"
|
|
32
|
-
|
|
33
|
-
if unit_test == UnitTests.VARSWAP_FIT:
|
|
34
|
-
btc_log_params = LogSvParams(sigma0=0.7118361434192538, theta=0.7118361434192538,
|
|
35
|
-
kappa1=2.214702576955766, kappa2=2.18028273418397, beta=0.0,
|
|
36
|
-
volvol=0.921487415907961)
|
|
37
|
-
btc_log_params = LogSvParams(sigma0=0.88, theta=0.88,
|
|
38
|
-
kappa1=2.214702576955766, kappa2=2.18028273418397, beta=0.0,
|
|
39
|
-
volvol=0.921487415907961)
|
|
40
|
-
|
|
41
|
-
vars_swaps = option_chain.get_slice_varswap_strikes()
|
|
42
|
-
vars_swaps1 = pd.Series(np.square(option_chain.get_chain_atm_vols()), index=option_chain.ttms)
|
|
43
|
-
vars_swaps = np.maximum(vars_swaps, vars_swaps1)
|
|
44
|
-
|
|
45
|
-
vol_backbone = fit_model_vol_backbone_to_varswaps(log_sv_params=btc_log_params,
|
|
46
|
-
varswap_strikes=vars_swaps,
|
|
47
|
-
verbose=True)
|
|
48
|
-
btc_log_params.set_vol_backbone(vol_backbone=vol_backbone)
|
|
49
|
-
|
|
50
|
-
logsv_pricer = LogSVPricer()
|
|
51
|
-
logsv_pricer.plot_model_ivols_vs_bid_ask(option_chain=option_chain,
|
|
52
|
-
params=btc_log_params)
|
|
53
|
-
|
|
54
|
-
elif unit_test == UnitTests.CALIBRATE_4PARAM_MODEL:
|
|
55
|
-
params0 = LogSvParams(sigma0=0.8, theta=1.0, kappa1=2.21, kappa2=2.18, beta=0.15, volvol=2.0)
|
|
56
|
-
fitted_params = LogSvParams(sigma0=0.8626, theta=1.0417, kappa1=2.21, kappa2=2.18, beta=0.13, volvol=1.6286)
|
|
57
|
-
btc_calibrated_params = fitted_params
|
|
58
|
-
"""
|
|
59
|
-
btc_calibrated_params = logsv_pricer.calibrate_model_params_to_chain(option_chain=option_chain,
|
|
60
|
-
params0=params0,
|
|
61
|
-
model_calibration_type=LogsvModelCalibrationType.PARAMS4,
|
|
62
|
-
constraints_type=sv.ConstraintsType.INVERSE_MARTINGALE)
|
|
63
|
-
"""
|
|
64
|
-
print(btc_calibrated_params)
|
|
65
|
-
fig = logsv_pricer.plot_model_ivols_vs_bid_ask(option_chain=option_chain,
|
|
66
|
-
params=btc_calibrated_params)
|
|
67
|
-
qis.save_fig(fig=fig, file_name='four_param_model_fit', local_path=local_path)
|
|
68
|
-
|
|
69
|
-
elif unit_test == UnitTests.CALIBRATE_VARSWAP_PARAM_MODEL:
|
|
70
|
-
params0 = LogSvParams(sigma0=0.85, theta=0.85, kappa1=2.21, kappa2=2.18, beta=0.15, volvol=1.5)
|
|
71
|
-
fitted_params = LogSvParams(sigma0=0.85, theta=1.0, kappa1=2.21, kappa2=2.18, beta=0.24, volvol=1.14)
|
|
72
|
-
btc_calibrated_params = logsv_pricer.calibrate_model_params_to_chain(
|
|
73
|
-
option_chain=option_chain,
|
|
74
|
-
params0=params0,
|
|
75
|
-
params_min=LogSvParams(sigma0=0.1, theta=0.1, kappa1=0.25, kappa2=0.25, beta=0.0, volvol=1.5),
|
|
76
|
-
model_calibration_type=LogsvModelCalibrationType.PARAMS_WITH_VARSWAP_FIT,
|
|
77
|
-
constraints_type=sv.ConstraintsType.INVERSE_MARTINGALE)
|
|
78
|
-
print(btc_calibrated_params)
|
|
79
|
-
|
|
80
|
-
fig = logsv_pricer.plot_model_ivols_vs_bid_ask(option_chain=option_chain,
|
|
81
|
-
params=btc_calibrated_params)
|
|
82
|
-
qis.save_fig(fig=fig, file_name='backbone_model_fit', local_path=local_path)
|
|
83
|
-
|
|
84
|
-
elif unit_test == UnitTests.COMPARE_MODEL_VOLS_TO_MC:
|
|
85
|
-
uniform_chain_data = sv.OptionChain.to_uniform_strikes(obj=option_chain, num_strikes=31)
|
|
86
|
-
is_varswap = True
|
|
87
|
-
if is_varswap:
|
|
88
|
-
fitted_params = LogSvParams(sigma0=0.85, theta=.85, kappa1=2.21, kappa2=2.18, beta=0.24, volvol=1.14)
|
|
89
|
-
varswap_strikes = option_chain.get_slice_varswap_strikes(floor_with_atm_vols=True)
|
|
90
|
-
fitted_params.set_vol_backbone(vol_backbone=fit_model_vol_backbone_to_varswaps(log_sv_params=fitted_params,
|
|
91
|
-
varswap_strikes=varswap_strikes))
|
|
92
|
-
else:
|
|
93
|
-
fitted_params = LogSvParams(sigma0=0.8626, theta=1.0417, kappa1=2.21, kappa2=2.18, beta=0.13, volvol=1.6286)
|
|
94
|
-
|
|
95
|
-
logsv_pricer.plot_model_ivols_vs_mc(option_chain=uniform_chain_data,
|
|
96
|
-
params=fitted_params,
|
|
97
|
-
nb_path=100000)
|
|
98
|
-
|
|
99
|
-
logsv_pricer.plot_comp_mma_inverse_options_with_mc(option_chain=uniform_chain_data,
|
|
100
|
-
params=fitted_params,
|
|
101
|
-
nb_path=100000)
|
|
102
|
-
|
|
103
|
-
plt.show()
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if __name__ == '__main__':
|
|
107
|
-
|
|
108
|
-
unit_test = UnitTests.CALIBRATE_VARSWAP_PARAM_MODEL
|
|
109
|
-
|
|
110
|
-
is_run_all_tests = False
|
|
111
|
-
if is_run_all_tests:
|
|
112
|
-
for unit_test in UnitTests:
|
|
113
|
-
run_unit_test(unit_test=unit_test)
|
|
114
|
-
else:
|
|
115
|
-
run_unit_test(unit_test=unit_test)
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
This module contains analysis for paper
|
|
2
|
-
[Unified Approach for Hedging Impermanent Loss of Liquidity Provision](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4887298)
|
|
3
|
-
by Artur Sepp, Alexander Lipton, and Vladimir Lucic
|
|
4
|
-
|
|
5
|
-
All figures in the paper are produced by unittests in
|
|
6
|
-
https://github.com/ArturSepp/StochVolModels/blob/main/my_papers/il_hedging/run_logsv_for_il_payoff.py
|
|
7
|
-
|
|
8
|
-
See the description of data and analysis in the paper.
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
run few unit test to illustrate implementation of log-normal sv model analytics
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import numpy as np
|
|
6
|
-
import matplotlib.pyplot as plt
|
|
7
|
-
import seaborn as sns
|
|
8
|
-
from enum import Enum
|
|
9
|
-
|
|
10
|
-
from stochvolmodels import LogSVPricer, LogSvParams, OptionChain
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def plot_skews():
|
|
14
|
-
logsv_pricer = LogSVPricer()
|
|
15
|
-
option_chain = OptionChain.get_uniform_chain(ttms=np.array([14.0/365.0]),
|
|
16
|
-
ids=np.array(['2w']),
|
|
17
|
-
strikes=np.linspace(0.6, 1.4, 21))
|
|
18
|
-
|
|
19
|
-
# define parameters for bootstrap
|
|
20
|
-
sigma0 = 0.5
|
|
21
|
-
params_dict = {'beta=-1': LogSvParams(sigma0=sigma0, theta=sigma0, kappa1=5.0, kappa2=5.0, beta=-1, volvol=1.0),
|
|
22
|
-
'beta=0': LogSvParams(sigma0=sigma0, theta=sigma0, kappa1=5.0, kappa2=5.0, beta=0.0, volvol=1.4),
|
|
23
|
-
'beta=1': LogSvParams(sigma0=sigma0, theta=sigma0, kappa1=5.0, kappa2=5.0, beta=1.0, volvol=1.0)}
|
|
24
|
-
|
|
25
|
-
params_dict = {
|
|
26
|
-
'volvol=1.0': LogSvParams(sigma0=sigma0, theta=sigma0, kappa1=2.21, kappa2=2.18, beta=0.0, volvol=1.0),
|
|
27
|
-
'volvol=2.0': LogSvParams(sigma0=sigma0 - 0.005, theta=sigma0 - 0.005, kappa1=2.21, kappa2=2.18, beta=0.0,
|
|
28
|
-
volvol=2.0),
|
|
29
|
-
'volvol=3.0': LogSvParams(sigma0=sigma0 - 0.01, theta=sigma0 - 0.01, kappa1=2.21, kappa2=2.18, beta=0.0,
|
|
30
|
-
volvol=3.0)}
|
|
31
|
-
|
|
32
|
-
# get slice for illustration
|
|
33
|
-
option_slice = option_chain.get_slice(id='2w')
|
|
34
|
-
logsv_pricer.plot_model_slices_in_params(option_slice=option_slice,
|
|
35
|
-
params_dict=params_dict)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class UnitTests(Enum):
|
|
39
|
-
PLOT_SKEWS = 1
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def run_unit_test(unit_test: UnitTests):
|
|
43
|
-
|
|
44
|
-
if unit_test == UnitTests.PLOT_SKEWS:
|
|
45
|
-
with sns.axes_style("darkgrid"):
|
|
46
|
-
fig, axs = plt.subplots(3, 1, figsize=(10, 7))
|
|
47
|
-
plot_skews()
|
|
48
|
-
|
|
49
|
-
plt.show()
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if __name__ == '__main__':
|
|
53
|
-
|
|
54
|
-
unit_test = UnitTests.PLOT_SKEWS
|
|
55
|
-
|
|
56
|
-
is_run_all_tests = False
|
|
57
|
-
if is_run_all_tests:
|
|
58
|
-
for unit_test in UnitTests:
|
|
59
|
-
run_unit_test(unit_test=unit_test)
|
|
60
|
-
else:
|
|
61
|
-
run_unit_test(unit_test=unit_test)
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
computation of il payoff under log sv
|
|
3
|
-
"""
|
|
4
|
-
import numpy as np
|
|
5
|
-
import matplotlib.pyplot as plt
|
|
6
|
-
from numba import njit
|
|
7
|
-
from enum import Enum
|
|
8
|
-
|
|
9
|
-
# stochvolmodels pricers
|
|
10
|
-
from stochvolmodels import (get_transform_var_grid,
|
|
11
|
-
vanilla_slice_pricer_with_mgf_grid,
|
|
12
|
-
digital_slice_pricer_with_mgf_grid,
|
|
13
|
-
compute_integration_weights,
|
|
14
|
-
ExpansionOrder,
|
|
15
|
-
get_expansion_n,
|
|
16
|
-
compute_logsv_a_mgf_grid,
|
|
17
|
-
LogSvParams)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def logsv_il_pricer(params: LogSvParams,
|
|
21
|
-
ttm: float,
|
|
22
|
-
p1: float, # can price on range of forwards
|
|
23
|
-
p0: float,
|
|
24
|
-
pa: float,
|
|
25
|
-
pb: float,
|
|
26
|
-
is_stiff_solver: bool = False,
|
|
27
|
-
expansion_order: ExpansionOrder = ExpansionOrder.SECOND,
|
|
28
|
-
vol_scaler: float = None,
|
|
29
|
-
notional: float = 1000000
|
|
30
|
-
) -> float:
|
|
31
|
-
"""
|
|
32
|
-
price il using bsm mgf
|
|
33
|
-
"""
|
|
34
|
-
# starting values
|
|
35
|
-
if vol_scaler is None: # for calibrations we fix one vol_scaler so the grid is not affected by v0
|
|
36
|
-
vol_scaler = params.sigma0 * np.sqrt(np.minimum(np.min(ttm), 0.5 / 12.0))
|
|
37
|
-
|
|
38
|
-
# for vanilla call and put
|
|
39
|
-
phi_grid, psi_grid, theta_grid = get_transform_var_grid(vol_scaler=vol_scaler,
|
|
40
|
-
real_phi=-0.4)
|
|
41
|
-
a_t0 = np.zeros((phi_grid.shape[0], get_expansion_n(expansion_order)), dtype=np.complex128)
|
|
42
|
-
|
|
43
|
-
a_t0, log_mgf_grid = compute_logsv_a_mgf_grid(ttm=ttm,
|
|
44
|
-
phi_grid=phi_grid,
|
|
45
|
-
psi_grid=psi_grid,
|
|
46
|
-
theta_grid=theta_grid,
|
|
47
|
-
a_t0=a_t0,
|
|
48
|
-
expansion_order=expansion_order,
|
|
49
|
-
is_stiff_solver=is_stiff_solver,
|
|
50
|
-
**params.to_dict())
|
|
51
|
-
|
|
52
|
-
vanilla_option_prices = vanilla_slice_pricer_with_mgf_grid(log_mgf_grid=log_mgf_grid,
|
|
53
|
-
phi_grid=phi_grid,
|
|
54
|
-
forward=p1,
|
|
55
|
-
strikes=np.array([pa, pb]),
|
|
56
|
-
optiontypes=np.array(['P', 'C']),
|
|
57
|
-
discfactor=1.0)
|
|
58
|
-
bsm_put, bsm_call = vanilla_option_prices[0], vanilla_option_prices[1]
|
|
59
|
-
|
|
60
|
-
digital_options = digital_slice_pricer_with_mgf_grid(log_mgf_grid=log_mgf_grid,
|
|
61
|
-
phi_grid=phi_grid,
|
|
62
|
-
forward=p1,
|
|
63
|
-
strikes=np.array([pa, pb]),
|
|
64
|
-
optiontypes=np.array(['P', 'C']),
|
|
65
|
-
discfactor=1.0)
|
|
66
|
-
digital_put, digital_call = digital_options[0], digital_options[1]
|
|
67
|
-
|
|
68
|
-
square_root = square_root_payoff_pricer_with_mgf_grid(log_mgf_grid=log_mgf_grid,
|
|
69
|
-
phi_grid=phi_grid,
|
|
70
|
-
forward=p1,
|
|
71
|
-
pa=pa,
|
|
72
|
-
pb=pb,
|
|
73
|
-
discfactor=1.0)
|
|
74
|
-
|
|
75
|
-
sp0 = np.sqrt(p0)
|
|
76
|
-
spa = np.sqrt(pa)
|
|
77
|
-
spb = np.sqrt(pb)
|
|
78
|
-
|
|
79
|
-
linear = sp0*(p1/p0+1.0)
|
|
80
|
-
|
|
81
|
-
payoff = -2.0*square_root + linear + \
|
|
82
|
-
(1.0 / spa) * bsm_put - (1.0 / spb) * bsm_call \
|
|
83
|
-
-2.0 * spa * digital_put -2.0 * spb * digital_call
|
|
84
|
-
|
|
85
|
-
notional0 = 1.0 / (2.0*sp0-p0/spb-spa)
|
|
86
|
-
payoff = - (notional0*notional)*payoff
|
|
87
|
-
return payoff
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
logsv_il_pricer_vector = np.vectorize(logsv_il_pricer, doc='Vectorized `logsv_il_pricer`')
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@njit(cache=False, fastmath=True)
|
|
94
|
-
def square_root_payoff_pricer_with_mgf_grid(log_mgf_grid: np.ndarray,
|
|
95
|
-
phi_grid: np.ndarray,
|
|
96
|
-
forward: float,
|
|
97
|
-
pa: float,
|
|
98
|
-
pb: float,
|
|
99
|
-
discfactor: float = 1.0,
|
|
100
|
-
is_simpson: bool = True
|
|
101
|
-
) -> np.ndarray:
|
|
102
|
-
"""
|
|
103
|
-
generic function for pricing digital options on the spot given the mgf grid
|
|
104
|
-
mgf in x is function defined on log-price transform phi grids
|
|
105
|
-
transform variable is phi_grid = real_phi + i*p
|
|
106
|
-
grid can be non-uniform
|
|
107
|
-
we can use either positive or negative phi_real but not
|
|
108
|
-
"""
|
|
109
|
-
dp = compute_integration_weights(var_grid=phi_grid, is_simpson=is_simpson)
|
|
110
|
-
|
|
111
|
-
x = np.log(forward)
|
|
112
|
-
xa = np.log(pa)
|
|
113
|
-
xb = np.log(pb)
|
|
114
|
-
p_payoff = (np.exp( (phi_grid+0.5)*xb - phi_grid*x) - np.exp((phi_grid+0.5)*xa - phi_grid*x))
|
|
115
|
-
p_payoff = (dp / np.pi) * p_payoff / (phi_grid+0.5)
|
|
116
|
-
option_price = discfactor * np.nansum(np.real(p_payoff*np.exp(log_mgf_grid)))
|
|
117
|
-
return option_price
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class UnitTests(Enum):
|
|
121
|
-
COMPUTE_MODEL_PRICES = 1
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def run_unit_test(unit_test: UnitTests):
|
|
125
|
-
|
|
126
|
-
# define model params
|
|
127
|
-
params = LogSvParams(sigma0=0.4861785891939535, theta=0.6176006871606874, kappa1=1.955809653686808, kappa2=1.978367101612294, beta=-0.26916969112829325, volvol=3.265815229306317)
|
|
128
|
-
|
|
129
|
-
if unit_test == UnitTests.COMPUTE_MODEL_PRICES:
|
|
130
|
-
payoff = logsv_il_pricer(params=params,
|
|
131
|
-
ttm=10.0/365.0,
|
|
132
|
-
p1=2200.0,
|
|
133
|
-
p0=2200.0,
|
|
134
|
-
pa=2000.0,
|
|
135
|
-
pb=2400.0)
|
|
136
|
-
print(payoff)
|
|
137
|
-
|
|
138
|
-
plt.show()
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if __name__ == '__main__':
|
|
142
|
-
|
|
143
|
-
unit_test = UnitTests.COMPUTE_MODEL_PRICES
|
|
144
|
-
|
|
145
|
-
is_run_all_tests = False
|
|
146
|
-
if is_run_all_tests:
|
|
147
|
-
for unit_test in UnitTests:
|
|
148
|
-
run_unit_test(unit_test=unit_test)
|
|
149
|
-
else:
|
|
150
|
-
run_unit_test(unit_test=unit_test)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
This module contains analysis for paper
|
|
2
|
-
[Valuation and Hedging of Cryptocurrency Inverse Options](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4606748) by Artur Sepp and Vladimir Lucic
|
|
3
|
-
|
|
4
|
-
Comparision of net deltas in the paper are generated using
|
|
5
|
-
```python
|
|
6
|
-
compare_net_delta.py
|
|
7
|
-
```
|
|
8
|
-
https://github.com/ArturSepp/StochVolModels/tree/main/my_papers/inverse_options
|
|
9
|
-
|
|
10
|
-
See the description of data and analysis in the paper.
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import pandas as pd
|
|
3
|
-
import matplotlib.pyplot as plt
|
|
4
|
-
import seaborn as sns
|
|
5
|
-
import qis as qis
|
|
6
|
-
from enum import Enum
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from stochvolmodels import (compute_bsm_vanilla_grid_deltas,
|
|
10
|
-
compute_bsm_forward_grid_prices,
|
|
11
|
-
compute_bsm_vanilla_price,
|
|
12
|
-
compute_bsm_vanilla_delta)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def compare_net_deltas(ttm: float,
|
|
16
|
-
forward: float,
|
|
17
|
-
vol: float,
|
|
18
|
-
strike_level: float = 1.0,
|
|
19
|
-
optiontype: str = 'C',
|
|
20
|
-
ax: plt.Subplot = None,
|
|
21
|
-
**kwargs
|
|
22
|
-
):
|
|
23
|
-
|
|
24
|
-
spot_drid = np.linspace(0.7*forward, 1.3*forward, 1000)
|
|
25
|
-
strike = strike_level * forward
|
|
26
|
-
|
|
27
|
-
option_prices = compute_bsm_forward_grid_prices(ttm=ttm, forwards=spot_drid, strike=strike, vol=vol, optiontype=optiontype)
|
|
28
|
-
option_deltas = compute_bsm_vanilla_grid_deltas(ttm=ttm, forwards=spot_drid, strike=strike, vol=vol, optiontype=optiontype)
|
|
29
|
-
option_net_delta = option_deltas - option_prices / spot_drid
|
|
30
|
-
option_deltas = pd.Series(option_deltas, index=spot_drid, name='Black Delta')
|
|
31
|
-
option_net_delta = pd.Series(option_net_delta, index=spot_drid, name='Net Delta')
|
|
32
|
-
deltas = pd.concat([option_deltas, option_net_delta], axis=1)
|
|
33
|
-
|
|
34
|
-
qis.plot_line(df=deltas,
|
|
35
|
-
xvar_format='{:,.0f}',
|
|
36
|
-
ylabel='BTC price',
|
|
37
|
-
ax=ax,
|
|
38
|
-
**kwargs)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def compare_pnl(ttm: float,
|
|
42
|
-
forward: float,
|
|
43
|
-
vol: float,
|
|
44
|
-
strike_level: float = 1.0,
|
|
45
|
-
optiontype: str = 'C',
|
|
46
|
-
is_btc_pnl: bool = True,
|
|
47
|
-
ax: plt.Subplot = None,
|
|
48
|
-
**kwargs
|
|
49
|
-
):
|
|
50
|
-
|
|
51
|
-
spot_drid = np.linspace(0.7*forward, 1.3*forward, 10000)
|
|
52
|
-
returns_grid = spot_drid / forward - 1.0
|
|
53
|
-
strike = strike_level*forward
|
|
54
|
-
|
|
55
|
-
option_price0 = compute_bsm_vanilla_price(ttm=ttm, forward=forward, strike=strike, vol=vol, optiontype=optiontype)
|
|
56
|
-
option_delta0 = compute_bsm_vanilla_delta(ttm=ttm, forward=forward, strike=strike, vol=vol, optiontype=optiontype)
|
|
57
|
-
option_net_delta0 = option_delta0 - option_price0 / forward
|
|
58
|
-
|
|
59
|
-
# price return
|
|
60
|
-
inverse_price_return = (spot_drid-forward) / spot_drid
|
|
61
|
-
dt = 1.0 / 365.0
|
|
62
|
-
option_prices = compute_bsm_forward_grid_prices(ttm=ttm-dt, forwards=spot_drid, strike=strike, vol=vol, optiontype=optiontype)
|
|
63
|
-
option_pnl_btc = (option_price0/forward - option_prices/spot_drid)
|
|
64
|
-
|
|
65
|
-
# black p&l
|
|
66
|
-
pnl_btc = option_pnl_btc + option_delta0 * inverse_price_return
|
|
67
|
-
if not is_btc_pnl:
|
|
68
|
-
pnl_btc = pnl_btc * spot_drid
|
|
69
|
-
pnl_btc_positive = spot_drid[pnl_btc >= 0.0]
|
|
70
|
-
lower_be = pnl_btc_positive[0] / forward - 1.0
|
|
71
|
-
upper_be = pnl_btc_positive[-1] / forward - 1.0
|
|
72
|
-
pnl_btc = pd.Series(pnl_btc, index=returns_grid, name=f"Black Delta: breakevens=({lower_be:0.2%}, {upper_be:0.2%})")
|
|
73
|
-
|
|
74
|
-
# net p&l
|
|
75
|
-
pnl_btc_net_delta = option_pnl_btc + option_net_delta0 * inverse_price_return
|
|
76
|
-
if not is_btc_pnl:
|
|
77
|
-
pnl_btc_net_delta = pnl_btc_net_delta * spot_drid
|
|
78
|
-
pnl_btc_net_delta_positive = spot_drid[pnl_btc_net_delta >= 0.0]
|
|
79
|
-
lower_be = pnl_btc_net_delta_positive[0] / forward - 1.0
|
|
80
|
-
upper_be = pnl_btc_net_delta_positive[-1] / forward - 1.0
|
|
81
|
-
pnl_btc_net_delta = pd.Series(pnl_btc_net_delta, index=returns_grid, name=f"Net Delta : breakevens=({lower_be:0.2%}, {upper_be:0.2%})")
|
|
82
|
-
|
|
83
|
-
pnls = pd.concat([pnl_btc, pnl_btc_net_delta], axis=1)
|
|
84
|
-
|
|
85
|
-
if is_btc_pnl:
|
|
86
|
-
ylabel = 'BTC P&L'
|
|
87
|
-
yvar_format = '{:,.2f}'
|
|
88
|
-
else:
|
|
89
|
-
ylabel = 'USD P&L'
|
|
90
|
-
yvar_format = '{:,.0f}'
|
|
91
|
-
|
|
92
|
-
qis.plot_line(df=pnls,
|
|
93
|
-
xvar_format='{:,.1%}',
|
|
94
|
-
yvar_format=yvar_format,
|
|
95
|
-
ylabel=ylabel,
|
|
96
|
-
xlabel='BTC % change',
|
|
97
|
-
ax=ax,
|
|
98
|
-
**kwargs)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class UnitTests(Enum):
|
|
102
|
-
DELTA_COMP = 1
|
|
103
|
-
PNL_COMP = 2
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def run_unit_test(unit_test: UnitTests):
|
|
107
|
-
|
|
108
|
-
LOCAL_PATH = "C://Users//artur//OneDrive//My Papers//Working Papers//Crypto Options. Zurich. Oct 2022//FinalFigures//"
|
|
109
|
-
|
|
110
|
-
kwargs = dict(fontsize=14, framealpha=0.9)
|
|
111
|
-
|
|
112
|
-
ttm = 7.0 / 365.0
|
|
113
|
-
|
|
114
|
-
if unit_test == UnitTests.DELTA_COMP:
|
|
115
|
-
|
|
116
|
-
with sns.axes_style("darkgrid"):
|
|
117
|
-
fig, axs = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True)
|
|
118
|
-
compare_net_deltas(ttm=ttm, forward=50000, vol=0.6, optiontype='C',
|
|
119
|
-
strike_level=1.0,
|
|
120
|
-
title='(A) Call Delta for K=100%*S_0',
|
|
121
|
-
ax=axs[0],
|
|
122
|
-
**kwargs)
|
|
123
|
-
compare_net_deltas(ttm=ttm, forward=50000, vol=0.6, optiontype='P',
|
|
124
|
-
strike_level=1.0,
|
|
125
|
-
title='(B) Put Delta for K=100%*S_0',
|
|
126
|
-
ax=axs[1],
|
|
127
|
-
**kwargs)
|
|
128
|
-
|
|
129
|
-
is_save = True
|
|
130
|
-
if is_save:
|
|
131
|
-
qis.save_fig(fig, file_name='delta_comp', local_path=LOCAL_PATH)
|
|
132
|
-
qis.save_fig(fig, file_name='delta_comp', file_type=qis.FileTypes.EPS, dpi=1200, local_path=LOCAL_PATH)
|
|
133
|
-
|
|
134
|
-
elif unit_test == UnitTests.PNL_COMP:
|
|
135
|
-
|
|
136
|
-
with sns.axes_style("darkgrid"):
|
|
137
|
-
fig, axs = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True)
|
|
138
|
-
compare_pnl(ttm=ttm, forward=50000, vol=0.6, optiontype='C',
|
|
139
|
-
title='(A) ATM Call K=100%*F_0',
|
|
140
|
-
y_limits=(-0.3, 0.05),
|
|
141
|
-
ax=axs[0],
|
|
142
|
-
**kwargs)
|
|
143
|
-
compare_pnl(ttm=ttm, forward=50000, vol=0.6, optiontype='C',
|
|
144
|
-
title='(B) ITM Call K=90%*F_0',
|
|
145
|
-
strike_level=0.9,
|
|
146
|
-
is_btc_pnl=True,
|
|
147
|
-
y_limits=(-0.3, 0.05),
|
|
148
|
-
ax=axs[1],
|
|
149
|
-
**kwargs)
|
|
150
|
-
|
|
151
|
-
is_save = True
|
|
152
|
-
if is_save:
|
|
153
|
-
qis.save_fig(fig, file_name='pnl_comp', local_path=LOCAL_PATH)
|
|
154
|
-
qis.save_fig(fig, file_name='pnl_comp', file_type=qis.FileTypes.EPS, dpi=1200, local_path=LOCAL_PATH)
|
|
155
|
-
|
|
156
|
-
plt.show()
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if __name__ == '__main__':
|
|
160
|
-
|
|
161
|
-
unit_test = UnitTests.DELTA_COMP
|
|
162
|
-
|
|
163
|
-
is_run_all_tests = False
|
|
164
|
-
if is_run_all_tests:
|
|
165
|
-
for unit_test in UnitTests:
|
|
166
|
-
run_unit_test(unit_test=unit_test)
|
|
167
|
-
else:
|
|
168
|
-
run_unit_test(unit_test=unit_test)
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
This module contains analysis for paper
|
|
2
|
-
[Log-normal Stochastic Volatility Model with Quadratic Drift](https://www.worldscientific.com/doi/10.1142/S0219024924500031)
|
|
3
|
-
by Artur Sepp and Parviz Rakhmonov
|
|
4
|
-
|
|
5
|
-
See the description of data and analysis in the paper.
|
|
6
|
-
|
|
7
|
-
Figures in the paper are generated using unittests in
|
|
8
|
-
```python
|
|
9
|
-
article_figures.py
|
|
10
|
-
```
|
|
11
|
-
https://github.com/ArturSepp/StochVolModels/blob/main/my_papers/logsv_model_wtih_quadratic_drift/article_figures.py
|
|
12
|
-
|
|
13
|
-
See the description of data and analysis in the paper.
|