2
2
from . import sv_abc as sv
3
3
from . import bsm
4
4
5
+ #### Use of RN generation spawn:
6
+ # 0: simulation of variance (gamma/ncx2/normal)
5
7
6
8
class GarchUncorrBaroneAdesi2004 (sv .SvABC ):
7
9
"""
@@ -15,9 +17,10 @@ class GarchUncorrBaroneAdesi2004(sv.SvABC):
15
17
"""
16
18
17
19
model_type = "GarchDiff"
20
+ var_process = True
18
21
order = 2
19
22
20
- def avgvar_mv (self , var0 , texp ):
23
+ def avgvar_mv (self , texp , var0 ):
21
24
"""
22
25
Mean and variance of the average variance given V(0) = var0.
23
26
Eqs. (12)-(13) in Barone-Adesi et al. (2005)
@@ -63,7 +66,7 @@ def price(self, strike, spot, texp, cp=1):
63
66
if not np .isclose (self .rho , 0.0 ):
64
67
print (f"Pricing ignores rho = { self .rho } ." )
65
68
66
- avgvar , var = self .avgvar_mv (self .sigma , texp )
69
+ avgvar , var = self .avgvar_mv (texp , self .sigma )
67
70
68
71
m_bs = bsm .Bsm (np .sqrt (avgvar ), intr = self .intr , divr = self .divr )
69
72
price = m_bs .price (strike , spot , texp , cp )
@@ -103,7 +106,7 @@ def set_num_params(self, n_path=10000, dt=0.05, rn_seed=None, antithetic=True, s
103
106
super ().set_num_params (n_path , dt , rn_seed , antithetic )
104
107
self .scheme = scheme
105
108
106
- def var_step_euler (self , var_0 , dt , milstein = True ):
109
+ def vol_step_euler (self , dt , var_0 , milstein = True ):
107
110
"""
108
111
Euler/Milstein Schemes:
109
112
v_(t+dt) = v_t + mr * (theta - v_t) * dt + vov * v_t Z * sqrt(dt) + (vov^2/2) v_t (Z^2-1) dt
@@ -115,8 +118,7 @@ def var_step_euler(self, var_0, dt, milstein=True):
115
118
Returns: Variance path (time, path) including the value at t=0
116
119
"""
117
120
118
- zz = self .rv_normal ()
119
-
121
+ zz = self .rv_normal (spawn = 0 )
120
122
var_t = var_0 + self .mr * (self .theta - var_0 )* dt + self .vov * var_0 * np .sqrt (dt )* zz
121
123
if milstein :
122
124
var_t += (self .vov ** 2 / 2 )* var_0 * dt * (zz ** 2 - 1 )
@@ -138,64 +140,69 @@ def var_step_log(self, log_var_0, dt):
138
140
Returns: Variance path (time, path) including the value at t=0
139
141
"""
140
142
141
- zz = self .rv_normal ()
143
+ zz = self .rv_normal (spawn = 0 )
142
144
143
145
log_var_t = log_var_0 + (self .mr * self .theta * np .exp (- log_var_0 ) - self .mr - self .vov ** 2 / 2 )* dt \
144
146
+ self .vov * np .sqrt (dt )* zz
145
147
146
148
return log_var_t
147
149
148
- def cond_states (self , var_0 , texp ):
149
- tobs = self .tobs (texp )
150
- n_dt = len (tobs )
151
- dt = np .diff (tobs , prepend = 0 )
152
-
153
- # precalculate the Simpson's rule weight
154
- weight = np .ones (n_dt + 1 )
155
- weight [1 :- 1 :2 ] = 4
156
- weight [2 :- 1 :2 ] = 2
157
- weight /= weight .sum ()
158
-
159
- var_t = np .full (self .n_path , var_0 )
160
-
161
- mean_var = weight [0 ]* var_t
162
- mean_vol = weight [0 ]* np .sqrt (var_t )
163
- mean_inv_vol = weight [0 ]/ np .sqrt (var_t )
150
+ def cond_states_step (self , dt , var_0 ):
164
151
165
152
if self .scheme < 2 :
166
153
milstein = (self .scheme == 1 )
154
+ var_t = self .vol_step_euler (dt , var_0 , milstein = milstein )
167
155
168
- for i in range (n_dt ):
169
- var_t = self .var_step_euler (var_t , dt [i ], milstein = milstein )
170
- mean_var += weight [i + 1 ]* var_t
171
- vol_t = np .sqrt (var_t )
172
- mean_vol += weight [i + 1 ]* vol_t
173
- mean_inv_vol += weight [i + 1 ]/ vol_t
156
+ mean_var = (var_0 + var_t )/ 2
157
+ vol_0 = np .sqrt (var_0 )
158
+ vol_t = np .sqrt (var_t )
159
+ mean_vol = (vol_0 + vol_t )/ 2
160
+ mean_inv_vol = (1 / vol_0 + 1 / vol_t )/ 2
174
161
175
162
elif self .scheme == 2 :
176
- log_var_t = np .full (self .n_path , np .log (var_0 ))
177
- for i in range (n_dt ):
178
- # Euler scheme on Log(var)
179
- log_var_t = self .var_step_log (log_var_t , dt [i ])
180
- vol_t = np .exp (log_var_t / 2 )
181
- mean_var += weight [i + 1 ]* vol_t ** 2
182
- mean_vol += weight [i + 1 ]* vol_t
183
- mean_inv_vol += weight [i + 1 ]/ vol_t
163
+
164
+ log_var_t = self .var_step_log (np .log (var_0 ), dt )
165
+
166
+ vol_0 = np .sqrt (var_0 )
167
+ vol_t = np .exp (log_var_t / 2 )
168
+ var_t = vol_t ** 2
169
+
170
+ mean_var = (var_0 + var_t )/ 2
171
+ mean_vol = (vol_0 + vol_t )/ 2
172
+ mean_inv_vol = (1 / vol_0 + 1 / vol_t )/ 2
184
173
else :
185
174
raise ValueError (f'Invalid scheme: { self .scheme } ' )
186
175
187
- return vol_t , mean_var , mean_vol , mean_inv_vol
188
-
189
- def cond_spot_sigma (self , var_0 , texp ):
176
+ return var_t , mean_var , mean_vol , mean_inv_vol
190
177
191
- vol_final , mean_var , mean_vol , mean_inv_vol = self .cond_states (var_0 , texp )
178
+ def cond_spot_sigma (self , texp , var_0 ):
179
+ tobs = self .tobs (texp )
180
+ dt = np .diff (tobs , prepend = 0 )
181
+ n_dt = len (dt )
192
182
193
- spot_cond = 2 * (vol_final - np .sqrt (var_0 ))/ self .vov \
194
- - self .mr * self .theta * mean_inv_vol * texp / self .vov \
195
- + (self .mr / self .vov + self .vov / 4 )* mean_vol * texp \
196
- - self .rho * mean_var * texp / 2
183
+ var_t = np .full (self .n_path , var_0 )
184
+ avgvar = np .zeros (self .n_path )
185
+ avgvol = np .zeros (self .n_path )
186
+ avgivol = np .zeros (self .n_path )
187
+
188
+ for i in range (n_dt ):
189
+ var_t , avgvar_inc , avgvol_inc , avgivol_inc = self .cond_states_step (dt [i ], var_t )
190
+ avgvar += avgvar_inc * dt [i ]
191
+ avgvol += avgvol_inc * dt [i ]
192
+ avgivol += avgivol_inc * dt [i ]
193
+
194
+ avgvar /= texp
195
+ avgvol /= texp
196
+ avgivol /= texp
197
+
198
+ spot_cond = 2 * (np .sqrt (var_t ) - np .sqrt (var_0 )) / self .vov + \
199
+ (- self .mr * self .theta * avgivol / self .vov \
200
+ + (self .mr / self .vov + self .vov / 4 ) * avgvol - self .rho * avgvar / 2 ) * texp
197
201
np .exp (self .rho * spot_cond , out = spot_cond )
198
202
199
- sigma_cond = np .sqrt ((1.0 - self .rho ** 2 )/ var_0 * mean_var )
203
+ cond_sigma = np .sqrt ((1.0 - self .rho ** 2 )/ var_0 * avgvar )
204
+
205
+ return spot_cond , cond_sigma
200
206
201
- return spot_cond , sigma_cond
207
+ def return_var_realized (self , texp , cond ):
208
+ return None
0 commit comments