stochvolmodels 1.0.6__tar.gz → 1.0.8__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.6 → stochvolmodels-1.0.8}/PKG-INFO +18 -2
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/README.md +17 -1
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/pyproject.toml +1 -1
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/__init__.py +35 -1
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/data/option_chain.py +1 -1
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/core/mgf_pricer.py +63 -13
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/hawkes_jd_pricer.py +7 -8
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/heston_pricer.py +7 -8
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/logsv_pricer.py +56 -21
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/tests/bsm_mgf_pricer.py +6 -7
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/LICENSE.txt +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/data/__init__.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/data/test_option_chain.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/__init__.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/core/__init__.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/core/bsm_pricer.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/core/config.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/core/mc_payoffs.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/core/normal_pricer.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/logsv/__init__.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/logsv/affine_expansion.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/logsv/vol_moments_ode.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/model_pricer.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/tests/__init__.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/tests/qv_pricer.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/utils/__init__.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/utils/funcs.py +0 -0
- {stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/utils/plots.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: stochvolmodels
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.8
|
|
4
4
|
Summary: Implementation of stochastic volatility models for option pricing
|
|
5
5
|
Home-page: https://github.com/ArturSepp/StochVolModels
|
|
6
6
|
License: LICENSE.txt
|
|
@@ -50,12 +50,28 @@ For the analytic implementation of stochastic volatility models, the package pro
|
|
|
50
50
|
1) Interface for analytical pricing of vanilla options using Fourier transform with closed-form solution for moment generating function
|
|
51
51
|
2) Interface for Monte-Carlo simulations of model dynamics
|
|
52
52
|
|
|
53
|
+
## Illustrations
|
|
54
|
+
|
|
55
|
+
As illustrations of different analytics, this packadge includes the computations and visualisations
|
|
56
|
+
for
|
|
57
|
+
|
|
58
|
+
1) Log-normal Stochastic Volatility Model with Quadratic Drift by Sepp A and Rakhmonov P, SSRN: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2522425
|
|
59
|
+
```python
|
|
60
|
+
stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
2) What is a robust stochastic volatility model by Sepp A and Rakhmonov P, SSRN: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4647027
|
|
65
|
+
```python
|
|
66
|
+
stochvolmodels/my_papers/volatility_models
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
|
|
53
70
|
## Installation
|
|
54
71
|
```python
|
|
55
72
|
pip install stochvolmodels
|
|
56
73
|
```
|
|
57
74
|
|
|
58
|
-
|
|
59
75
|
# Table of contents
|
|
60
76
|
1. [Model Interface](#introduction)
|
|
61
77
|
1. [Log-normal stochastic volatility model](#logsv)
|
|
@@ -11,12 +11,28 @@ For the analytic implementation of stochastic volatility models, the package pro
|
|
|
11
11
|
1) Interface for analytical pricing of vanilla options using Fourier transform with closed-form solution for moment generating function
|
|
12
12
|
2) Interface for Monte-Carlo simulations of model dynamics
|
|
13
13
|
|
|
14
|
+
## Illustrations
|
|
15
|
+
|
|
16
|
+
As illustrations of different analytics, this packadge includes the computations and visualisations
|
|
17
|
+
for
|
|
18
|
+
|
|
19
|
+
1) Log-normal Stochastic Volatility Model with Quadratic Drift by Sepp A and Rakhmonov P, SSRN: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2522425
|
|
20
|
+
```python
|
|
21
|
+
stochvolmodels/my_papers/logsv_model_wtih_quadratic_drift
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
2) What is a robust stochastic volatility model by Sepp A and Rakhmonov P, SSRN: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4647027
|
|
26
|
+
```python
|
|
27
|
+
stochvolmodels/my_papers/volatility_models
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
|
|
14
31
|
## Installation
|
|
15
32
|
```python
|
|
16
33
|
pip install stochvolmodels
|
|
17
34
|
```
|
|
18
35
|
|
|
19
|
-
|
|
20
36
|
# Table of contents
|
|
21
37
|
1. [Model Interface](#introduction)
|
|
22
38
|
1. [Log-normal stochastic volatility model](#logsv)
|
|
@@ -56,7 +56,7 @@ from stochvolmodels.pricers.logsv_pricer import (
|
|
|
56
56
|
LOGSV_BTC_PARAMS,
|
|
57
57
|
LogSVPricer,
|
|
58
58
|
LogSvParams,
|
|
59
|
-
|
|
59
|
+
LogsvModelCalibrationType,
|
|
60
60
|
ConstraintsType
|
|
61
61
|
)
|
|
62
62
|
|
|
@@ -92,6 +92,40 @@ from stochvolmodels.utils.plots import (
|
|
|
92
92
|
vol_slice_fit
|
|
93
93
|
)
|
|
94
94
|
|
|
95
|
+
|
|
96
|
+
from stochvolmodels.pricers.core.mgf_pricer import (
|
|
97
|
+
compute_integration_weights,
|
|
98
|
+
digital_slice_pricer_with_mgf_grid,
|
|
99
|
+
get_phi_grid,
|
|
100
|
+
get_psi_grid,
|
|
101
|
+
get_theta_grid,
|
|
102
|
+
get_transform_var_grid,
|
|
103
|
+
pdf_with_mgf_grid,
|
|
104
|
+
slice_pricer_with_mgf_grid_with_gamma,
|
|
105
|
+
slice_qvar_pricer_with_a_grid,
|
|
106
|
+
vanilla_slice_pricer_with_mgf_grid,
|
|
107
|
+
slice_pricer_with_mgf_grid_with_gamma,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
from stochvolmodels.pricers.logsv.affine_expansion import (
|
|
111
|
+
ExpansionOrder,
|
|
112
|
+
VariableType,
|
|
113
|
+
compute_logsv_a_mgf_grid,
|
|
114
|
+
func_a_ode_quadratic_terms,
|
|
115
|
+
func_rhs,
|
|
116
|
+
func_rhs_jac,
|
|
117
|
+
get_expansion_n,
|
|
118
|
+
get_init_conditions_a,
|
|
119
|
+
solve_a_ode_grid,
|
|
120
|
+
solve_analytic_ode_for_a,
|
|
121
|
+
solve_analytic_ode_for_a0,
|
|
122
|
+
solve_analytic_ode_grid_phi,
|
|
123
|
+
solve_ode_for_a,
|
|
124
|
+
compute_logsv_a_mgf_grid,
|
|
125
|
+
solve_a_ode_grid,
|
|
126
|
+
solve_ode_for_a,
|
|
127
|
+
)
|
|
128
|
+
|
|
95
129
|
from stochvolmodels.pricers.core.config import VariableType
|
|
96
130
|
|
|
97
131
|
from stochvolmodels.pricers.core.mc_payoffs import compute_mc_vars_payoff
|
|
@@ -272,4 +272,4 @@ class OptionChain:
|
|
|
272
272
|
strikes_ttms=List([strikes for _ in ttms]),
|
|
273
273
|
bid_ivs=List([flat_vol*np.ones_like(strikes) for _ in ttms]),
|
|
274
274
|
ask_ivs=List([flat_vol*np.ones_like(strikes) for _ in ttms]),
|
|
275
|
-
optiontypes_ttms=List([np.where(strikes >= forward, 'C', 'P') for forward in forwards]))
|
|
275
|
+
optiontypes_ttms=List([np.where(strikes >= forward, 'C', 'P') for forward in forwards]))
|
|
@@ -27,7 +27,10 @@ def get_phi_grid(is_spot_measure: bool = True,
|
|
|
27
27
|
else:
|
|
28
28
|
real_p = real_phi
|
|
29
29
|
else:
|
|
30
|
-
|
|
30
|
+
if real_phi is None:
|
|
31
|
+
real_p = 0.5
|
|
32
|
+
else:
|
|
33
|
+
real_p = real_phi
|
|
31
34
|
phi_grid = real_p + 1j * p
|
|
32
35
|
return phi_grid
|
|
33
36
|
|
|
@@ -109,18 +112,17 @@ def compute_integration_weights(var_grid: np.ndarray,
|
|
|
109
112
|
|
|
110
113
|
|
|
111
114
|
@njit(cache=False, fastmath=True)
|
|
112
|
-
def
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
) -> np.ndarray:
|
|
115
|
+
def vanilla_slice_pricer_with_mgf_grid(log_mgf_grid: np.ndarray,
|
|
116
|
+
phi_grid: np.ndarray,
|
|
117
|
+
forward: float,
|
|
118
|
+
strikes: np.ndarray,
|
|
119
|
+
optiontypes: np.ndarray,
|
|
120
|
+
discfactor: float = 1.0,
|
|
121
|
+
is_spot_measure: bool = True,
|
|
122
|
+
is_simpson: bool = True
|
|
123
|
+
) -> np.ndarray:
|
|
122
124
|
"""
|
|
123
|
-
generic function for pricing options on the spot given the mgf grid
|
|
125
|
+
generic function for pricing vanilla options on the spot given the mgf grid
|
|
124
126
|
mgf in x is function defined on log-price transform phi grids
|
|
125
127
|
transform variable is phi_grid = real_phi + i*p
|
|
126
128
|
grid can be non-uniform
|
|
@@ -128,7 +130,7 @@ def slice_pricer_with_mgf_grid(log_mgf_grid: np.ndarray,
|
|
|
128
130
|
p = np.imag(phi_grid)
|
|
129
131
|
dp = compute_integration_weights(var_grid=phi_grid, is_simpson=is_simpson)
|
|
130
132
|
|
|
131
|
-
if np.all(np.abs(np.real(phi_grid))
|
|
133
|
+
if np.all(np.equal(np.abs(np.real(phi_grid)), 0.5)): # optimized for phi = +/-0.5 + i*p
|
|
132
134
|
p_payoff = (dp / np.pi) / (p * p + 0.25) + 1j * 0.0 # add zero complex part for numba
|
|
133
135
|
else:
|
|
134
136
|
if is_spot_measure:
|
|
@@ -159,6 +161,54 @@ def slice_pricer_with_mgf_grid(log_mgf_grid: np.ndarray,
|
|
|
159
161
|
return option_prices
|
|
160
162
|
|
|
161
163
|
|
|
164
|
+
@njit(cache=False, fastmath=True)
|
|
165
|
+
def digital_slice_pricer_with_mgf_grid(log_mgf_grid: np.ndarray,
|
|
166
|
+
phi_grid: np.ndarray,
|
|
167
|
+
forward: float,
|
|
168
|
+
strikes: np.ndarray,
|
|
169
|
+
optiontypes: np.ndarray,
|
|
170
|
+
discfactor: float = 1.0,
|
|
171
|
+
is_simpson: bool = True
|
|
172
|
+
) -> np.ndarray:
|
|
173
|
+
"""
|
|
174
|
+
generic function for pricing digital options on the spot given the mgf grid
|
|
175
|
+
mgf in x is function defined on log-price transform phi grids
|
|
176
|
+
transform variable is phi_grid = real_phi + i*p
|
|
177
|
+
grid can be non-uniform
|
|
178
|
+
"""
|
|
179
|
+
dp = compute_integration_weights(var_grid=phi_grid, is_simpson=is_simpson)
|
|
180
|
+
|
|
181
|
+
# we can use positive or negative phi_real
|
|
182
|
+
if np.all(np.real(phi_grid) < 0.0): # use calls
|
|
183
|
+
is_all_calls = True
|
|
184
|
+
p_payoff = - (dp / np.pi) / (phi_grid) # for calls
|
|
185
|
+
else:
|
|
186
|
+
is_all_calls = False
|
|
187
|
+
p_payoff = (dp / np.pi) / (phi_grid) # for puts
|
|
188
|
+
|
|
189
|
+
log_strikes = np.log(forward/strikes)
|
|
190
|
+
option_prices = np.zeros_like(log_strikes)
|
|
191
|
+
for idx, (x, strike, type_) in enumerate(zip(log_strikes, strikes, optiontypes)):
|
|
192
|
+
# compute sum using trapesoidal rule
|
|
193
|
+
digital_option_price = np.nansum(np.real(p_payoff*np.exp(-x * phi_grid + log_mgf_grid)))
|
|
194
|
+
if type_ == 'C':
|
|
195
|
+
if is_all_calls:
|
|
196
|
+
price = digital_option_price
|
|
197
|
+
else:
|
|
198
|
+
price = 1.0 - digital_option_price
|
|
199
|
+
elif type_ == 'P':
|
|
200
|
+
if is_all_calls:
|
|
201
|
+
price = 1.0 - digital_option_price
|
|
202
|
+
else:
|
|
203
|
+
price = digital_option_price
|
|
204
|
+
else:
|
|
205
|
+
raise ValueError(f"not implemented")
|
|
206
|
+
|
|
207
|
+
option_prices[idx] = discfactor * price
|
|
208
|
+
|
|
209
|
+
return option_prices
|
|
210
|
+
|
|
211
|
+
|
|
162
212
|
#@njit(cache=False, fastmath=True)
|
|
163
213
|
def slice_pricer_with_mgf_grid_with_gamma(log_mgf_grid: np.ndarray,
|
|
164
214
|
phi_grid: np.ndarray,
|
|
@@ -365,14 +365,13 @@ def hawkesjd_chain_pricer(model_params: HawkesJDParams,
|
|
|
365
365
|
model_params=model_params)
|
|
366
366
|
|
|
367
367
|
if variable_type == VariableType.LOG_RETURN:
|
|
368
|
-
option_prices = mgfp.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
is_spot_measure=is_spot_measure)
|
|
368
|
+
option_prices = mgfp.vanilla_slice_pricer_with_mgf_grid(log_mgf_grid=log_mgf_grid,
|
|
369
|
+
phi_grid=phi_grid,
|
|
370
|
+
forward=forward,
|
|
371
|
+
strikes=strikes_ttm,
|
|
372
|
+
optiontypes=optiontypes_ttm,
|
|
373
|
+
discfactor=discfactor,
|
|
374
|
+
is_spot_measure=is_spot_measure)
|
|
376
375
|
else:
|
|
377
376
|
raise NotImplementedError
|
|
378
377
|
|
|
@@ -11,7 +11,7 @@ from numba.typed import List
|
|
|
11
11
|
from typing import Tuple
|
|
12
12
|
from enum import Enum
|
|
13
13
|
|
|
14
|
-
from stochvolmodels.pricers.core.mgf_pricer import get_transform_var_grid,
|
|
14
|
+
from stochvolmodels.pricers.core.mgf_pricer import get_transform_var_grid, vanilla_slice_pricer_with_mgf_grid
|
|
15
15
|
from stochvolmodels.pricers.model_pricer import ModelParams, ModelPricer
|
|
16
16
|
from stochvolmodels.data.option_chain import OptionChain
|
|
17
17
|
from stochvolmodels.data.test_option_chain import get_btc_test_chain_data
|
|
@@ -213,13 +213,12 @@ def heston_chain_pricer(v0: float,
|
|
|
213
213
|
a_t0=a_t0,
|
|
214
214
|
b_t0=b_t0)
|
|
215
215
|
|
|
216
|
-
option_prices =
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
optiontypes=optiontypes_ttm)
|
|
216
|
+
option_prices = vanilla_slice_pricer_with_mgf_grid(log_mgf_grid=log_mgf_grid,
|
|
217
|
+
phi_grid=phi_grid,
|
|
218
|
+
forward=forward,
|
|
219
|
+
discfactor=discfactor,
|
|
220
|
+
strikes=strikes_ttm,
|
|
221
|
+
optiontypes=optiontypes_ttm)
|
|
223
222
|
model_prices_ttms.append(option_prices)
|
|
224
223
|
ttm0 = ttm
|
|
225
224
|
|
|
@@ -29,9 +29,10 @@ from stochvolmodels.data.option_chain import OptionChain
|
|
|
29
29
|
from stochvolmodels.data.test_option_chain import get_btc_test_chain_data
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
class
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
class LogsvModelCalibrationType(Enum):
|
|
33
|
+
PARAMS4 = 1 # v0, theta, beta, volvol; kappa1, kappa2 are set externally
|
|
34
|
+
PARAMS5 = 2 # v0, theta, kappa1, beta, volvol
|
|
35
|
+
PARAMS6 = 3 # v0, theta, kappa1, kappa2, beta, volvol
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
class ConstraintsType(Enum):
|
|
@@ -59,8 +60,8 @@ class LogSvParams(ModelParams):
|
|
|
59
60
|
self.kappa2 = self.kappa1 / self.theta
|
|
60
61
|
|
|
61
62
|
def to_dict(self) -> Dict[str, Any]:
|
|
62
|
-
# return dict(sigma0=self.sigma0, theta=self.theta, kappa1=self.kappa1, kappa2=self.kappa2, beta=self.beta, volvol=self.volvol)
|
|
63
63
|
return asdict(self)
|
|
64
|
+
|
|
64
65
|
@property
|
|
65
66
|
def kappa(self) -> float:
|
|
66
67
|
return self.kappa1+self.kappa2*self.theta
|
|
@@ -220,10 +221,10 @@ class LogSVPricer(ModelPricer):
|
|
|
220
221
|
@timer
|
|
221
222
|
def calibrate_model_params_to_chain(self,
|
|
222
223
|
option_chain: OptionChain,
|
|
223
|
-
params0: LogSvParams
|
|
224
|
+
params0: LogSvParams,
|
|
224
225
|
is_vega_weighted: bool = True,
|
|
225
226
|
is_unit_ttm_vega: bool = False,
|
|
226
|
-
model_calibration_type:
|
|
227
|
+
model_calibration_type: LogsvModelCalibrationType = LogsvModelCalibrationType.PARAMS5,
|
|
227
228
|
constraints_type: ConstraintsType = ConstraintsType.UNCONSTRAINT,
|
|
228
229
|
**kwargs
|
|
229
230
|
) -> LogSvParams:
|
|
@@ -245,7 +246,39 @@ class LogSVPricer(ModelPricer):
|
|
|
245
246
|
else:
|
|
246
247
|
weights = np.ones_like(market_vols)
|
|
247
248
|
|
|
248
|
-
|
|
249
|
+
# implement different calibrato types
|
|
250
|
+
if model_calibration_type == LogsvModelCalibrationType.PARAMS4:
|
|
251
|
+
# fit: v0, theta, beta, volvol; kappa1, kappa2 is given with params0
|
|
252
|
+
if params0 is not None:
|
|
253
|
+
p0 = np.array([params0.sigma0, params0.theta, params0.beta, params0.volvol])
|
|
254
|
+
else:
|
|
255
|
+
p0 = np.array([0.8, 0.8, -0.2, 2.0])
|
|
256
|
+
bounds = ((0.01, 2.0), (0.01, 2.0), (-5.0, 3.0), (0.1, 10.0))
|
|
257
|
+
|
|
258
|
+
def objective(pars: np.ndarray, args: np.ndarray) -> float:
|
|
259
|
+
v0, theta, beta, volvol = pars[0], pars[1], pars[2], pars[3]
|
|
260
|
+
params = LogSvParams(sigma0=v0, theta=theta, kappa1=params0.kappa1,
|
|
261
|
+
kappa2=params0.kappa2, beta=beta, volvol=volvol)
|
|
262
|
+
model_vols = self.compute_model_ivols_for_chain(option_chain=option_chain, params=params,
|
|
263
|
+
vol_scaler=vol_scaler)
|
|
264
|
+
resid = np.nansum(weights * np.square(to_flat_np_array(model_vols) - market_vols))
|
|
265
|
+
return resid
|
|
266
|
+
|
|
267
|
+
def martingale_measure(pars: np.ndarray) -> float:
|
|
268
|
+
v0, theta, beta, volvol = pars[0], pars[1], pars[2], pars[3]
|
|
269
|
+
return params0.kappa2 - beta
|
|
270
|
+
|
|
271
|
+
def inverse_measure(pars: np.ndarray) -> float:
|
|
272
|
+
v0, theta, beta, volvol = pars[0], pars[1], pars[2], pars[3]
|
|
273
|
+
return params0.kappa2 - 2.0 * beta
|
|
274
|
+
|
|
275
|
+
def vol_4thmoment_finite(pars: np.ndarray) -> float:
|
|
276
|
+
v0, theta, beta, volvol = pars[0], pars[1], pars[2], pars[3]
|
|
277
|
+
vartheta2 = beta * beta + volvol * volvol
|
|
278
|
+
kappa = params0.kappa1 + params0.kappa2 * theta
|
|
279
|
+
return kappa - 1.5 * vartheta2
|
|
280
|
+
|
|
281
|
+
elif model_calibration_type == LogsvModelCalibrationType.PARAMS5:
|
|
249
282
|
# fit: v0, theta, kappa1, beta, volvol; kappa2 is mapped as kappa1 / theta
|
|
250
283
|
if params0 is not None:
|
|
251
284
|
p0 = np.array([params0.sigma0, params0.theta, params0.kappa1, params0.beta, params0.volvol])
|
|
@@ -275,11 +308,6 @@ class LogSVPricer(ModelPricer):
|
|
|
275
308
|
kappa = kappa1 + kappa2 * theta
|
|
276
309
|
return kappa - 1.5*vartheta2
|
|
277
310
|
|
|
278
|
-
def kurtosis_finite(pars: np.ndarray) -> float:
|
|
279
|
-
v0, theta, kappa1, beta, volvol = pars[0], pars[1], pars[2], pars[3], pars[4]
|
|
280
|
-
vartheta2 = beta*beta + volvol*volvol
|
|
281
|
-
return kappa1 - 1.5*vartheta2
|
|
282
|
-
|
|
283
311
|
else:
|
|
284
312
|
raise NotImplementedError(f"{model_calibration_type}")
|
|
285
313
|
|
|
@@ -320,7 +348,15 @@ class LogSVPricer(ModelPricer):
|
|
|
320
348
|
|
|
321
349
|
popt = res.x
|
|
322
350
|
|
|
323
|
-
if model_calibration_type ==
|
|
351
|
+
if model_calibration_type == LogsvModelCalibrationType.PARAMS4:
|
|
352
|
+
fit_params = LogSvParams(sigma0=popt[0],
|
|
353
|
+
theta=popt[1],
|
|
354
|
+
kappa1=params0.kappa1,
|
|
355
|
+
kappa2=params0.kappa2,
|
|
356
|
+
beta=popt[2],
|
|
357
|
+
volvol=popt[3])
|
|
358
|
+
|
|
359
|
+
elif model_calibration_type == LogsvModelCalibrationType.PARAMS5:
|
|
324
360
|
fit_params = LogSvParams(sigma0=popt[0],
|
|
325
361
|
theta=popt[1],
|
|
326
362
|
kappa1=popt[2],
|
|
@@ -481,14 +517,13 @@ def logsv_chain_pricer(params: LogSvParams,
|
|
|
481
517
|
**params.to_dict())
|
|
482
518
|
|
|
483
519
|
if variable_type == VariableType.LOG_RETURN:
|
|
484
|
-
option_prices = mgfp.
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
is_spot_measure=is_spot_measure)
|
|
520
|
+
option_prices = mgfp.vanilla_slice_pricer_with_mgf_grid(log_mgf_grid=log_mgf_grid,
|
|
521
|
+
phi_grid=phi_grid,
|
|
522
|
+
forward=forward,
|
|
523
|
+
strikes=strikes_ttm,
|
|
524
|
+
optiontypes=optiontypes_ttm,
|
|
525
|
+
discfactor=discfactor,
|
|
526
|
+
is_spot_measure=is_spot_measure)
|
|
492
527
|
|
|
493
528
|
elif variable_type == VariableType.Q_VAR:
|
|
494
529
|
option_prices = mgfp.slice_qvar_pricer_with_a_grid(log_mgf_grid=log_mgf_grid,
|
|
@@ -51,13 +51,12 @@ def bsm_slice_pricer(ttm: float,
|
|
|
51
51
|
|
|
52
52
|
if variable_type == VariableType.LOG_RETURN:
|
|
53
53
|
log_mgf_grid, phi_grid = compute_normal_mgf_grid(ttm=ttm, vol=vol, is_spot_measure=is_spot_measure)
|
|
54
|
-
bsm_prices = mgfp.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
is_spot_measure=is_spot_measure)
|
|
54
|
+
bsm_prices = mgfp.vanilla_slice_pricer_with_mgf_grid(log_mgf_grid=log_mgf_grid,
|
|
55
|
+
phi_grid=phi_grid,
|
|
56
|
+
forward=forward,
|
|
57
|
+
strikes=strikes,
|
|
58
|
+
optiontypes=optiontypes,
|
|
59
|
+
is_spot_measure=is_spot_measure)
|
|
61
60
|
bsm_ivols = infer_bsm_ivols_from_model_chain_prices(ttms=np.array([ttm]),
|
|
62
61
|
forwards=np.array([forward]),
|
|
63
62
|
discfactors=np.array([1.0]),
|
|
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
|
{stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/stochvolmodels/pricers/logsv/affine_expansion.py
RENAMED
|
File without changes
|
{stochvolmodels-1.0.6 → stochvolmodels-1.0.8}/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
|