@@ -2,8 +2,10 @@ use std::f64::consts::FRAC_1_PI;
2
2
3
3
use impl_new_derive:: ImplNew ;
4
4
use implied_vol:: implied_black_volatility;
5
+ use nalgebra:: Complex ;
5
6
use num_complex:: Complex64 ;
6
7
use quadrature:: double_exponential;
8
+ use rand_distr:: num_traits:: ConstOne ;
7
9
8
10
use crate :: quant:: {
9
11
r#trait:: { PricerExt , TimeExt } ,
@@ -58,11 +60,11 @@ impl PricerExt for HestonPricer {
58
60
let tau = self . tau ( ) . unwrap_or ( 1.0 ) ;
59
61
60
62
vec ! [
61
- self . dC_dv0 ( tau) ,
62
- self . dC_dtheta ( tau) ,
63
- self . dC_drho ( tau) ,
64
- self . dC_dkappa ( tau) ,
65
- self . dC_dsigma ( tau) ,
63
+ self . h1 ( tau) ,
64
+ self . h2 ( tau) ,
65
+ self . h3 ( tau) ,
66
+ self . h4 ( tau) ,
67
+ self . h5 ( tau) ,
66
68
]
67
69
}
68
70
@@ -154,38 +156,108 @@ impl HestonPricer {
154
156
/// https://www.sciencedirect.com/science/article/abs/pii/S0377221717304460
155
157
156
158
/// Partial derivative of the C function with respect to the v0 parameter
157
- pub ( crate ) fn dC_dv0 ( & self , tau : f64 ) -> f64 {
158
- ( - self . A ( tau) / self . v0 ) . re
159
+ pub ( crate ) fn h1 ( & self , tau : f64 ) -> f64 {
160
+ - ( self . A ( tau) / self . v0 ) . re
159
161
}
160
162
161
163
/// Partial derivative of the C function with respect to the theta parameter
162
- pub ( crate ) fn dC_dtheta ( & self , tau : f64 ) -> f64 {
164
+ pub ( crate ) fn h2 ( & self , tau : f64 ) -> f64 {
163
165
( ( 2.0 * self . kappa / self . sigma . powi ( 2 ) ) * self . D_ ( tau)
164
166
- self . kappa * self . rho * tau * Complex64 :: i ( ) * self . u ( 1 ) / self . sigma )
165
167
. re
166
168
}
167
169
168
170
/// Partial derivative of the C function with respect to the rho parameter
169
- pub ( crate ) fn dC_drho ( & self , tau : f64 ) -> f64 {
170
- ( -self . kappa * self . theta * tau * Complex64 :: i ( ) * self . u ( 1 ) / self . sigma ) . re
171
+ pub ( crate ) fn h3 ( & self , tau : f64 ) -> f64 {
172
+ ( -self . dA_drho ( tau)
173
+ + ( ( 2.0 * self . kappa * self . theta ) / ( self . sigma . powi ( 2 ) * self . d_ ( ) ) )
174
+ * ( self . dd__drho ( ) - ( self . d_ ( ) / self . A2 ( tau) ) * self . dA2_drho ( tau) )
175
+ - ( self . kappa * self . theta * tau * Complex64 :: i ( ) * self . u ( 1 ) ) / self . sigma )
176
+ . re
171
177
}
172
178
173
179
/// Partial derivative of the C function with respect to the kappa parameter
174
- pub ( crate ) fn dC_dkappa ( & self , tau : f64 ) -> f64 {
175
- ( 2.0 * self . theta * self . D_ ( tau) / self . sigma . powi ( 2 )
176
- + ( ( 2.0 * self . kappa * self . theta ) / self . sigma . powi ( 2 ) * self . B ( tau) ) * self . dB_dkappa ( tau)
177
- - ( self . theta * self . rho * tau * Complex64 :: i ( ) * self . u ( 1 ) / self . sigma ) )
180
+ pub ( crate ) fn h4 ( & self , tau : f64 ) -> f64 {
181
+ ( ( 1.0 / ( self . sigma * Complex64 :: i ( ) * self . u ( 1 ) ) ) * self . dA_drho ( tau)
182
+ + ( ( 2.0 * self . theta ) / self . sigma . powi ( 2 ) ) * self . D_ ( tau)
183
+ + ( ( 2.0 * self . kappa * self . theta ) / ( self . sigma . powi ( 2 ) * self . B ( tau) ) )
184
+ * self . dB_dkappa ( tau)
185
+ - ( self . theta * self . rho * tau * Complex64 :: i ( ) * self . u ( 1 ) ) / self . sigma )
178
186
. re
179
187
}
180
188
181
189
/// Partial derivative of the C function with respect to the sigma parameter
182
- pub ( crate ) fn dC_dsigma ( & self , tau : f64 ) -> f64 {
183
- ( ( -4.0 * self . kappa * self . theta / self . sigma . powi ( 3 ) ) * self . D_ ( tau)
184
- + ( ( 2.0 * self . kappa * self . theta ) / ( self . sigma . powi ( 2 ) * self . d_ ( ) ) ) * self . dd_dsigma ( )
185
- + self . kappa * self . theta * self . rho * tau * Complex64 :: i ( ) * self . u ( 1 ) / self . sigma . powi ( 2 ) )
190
+ pub ( crate ) fn h5 ( & self , tau : f64 ) -> f64 {
191
+ ( -self . dA_dsigma ( tau) - ( ( 4.0 * self . kappa * self . theta ) / self . sigma . powi ( 3 ) ) * self . D_ ( tau)
192
+ + ( ( 2.0 * self . kappa * self . theta ) / ( self . sigma . powi ( 2 ) * self . d_ ( ) ) )
193
+ * ( self . dd__dsigma ( ) - ( self . d_ ( ) / self . A2 ( tau) ) * self . dA2_dsigma ( tau) )
194
+ + ( self . kappa * self . theta * self . rho * tau * Complex64 :: i ( ) * self . u ( 1 ) )
195
+ / self . sigma . powi ( 2 ) )
186
196
. re
187
197
}
188
198
199
+ // helpers derivates
200
+ pub ( self ) fn dxi_drho ( & self ) -> Complex64 {
201
+ -self . sigma * Complex64 :: i ( ) * self . u ( 1 )
202
+ }
203
+
204
+ pub ( self ) fn dd__drho ( & self ) -> Complex64 {
205
+ -( self . xi ( ) * self . sigma * Complex64 :: i ( ) * self . u ( 1 ) ) / self . d_ ( )
206
+ }
207
+
208
+ pub ( self ) fn dA1_drho ( & self , tau : f64 ) -> Complex64 {
209
+ -( ( Complex64 :: i ( )
210
+ * self . u ( 1 )
211
+ * ( self . u ( 1 ) . powi ( 2 ) + Complex64 :: i ( ) * self . u ( 1 ) )
212
+ * tau
213
+ * self . xi ( )
214
+ * self . sigma )
215
+ / ( 2.0 * self . d_ ( ) )
216
+ * ( self . d_ ( ) * tau / 2.0 ) . cosh ( ) )
217
+ }
218
+
219
+ pub ( self ) fn dA2_drho ( & self , tau : f64 ) -> Complex64 {
220
+ ( ( self . dxi_drho ( ) * ( 2.0 + self . xi ( ) * tau) ) / ( 2.0 * self . d_ ( ) * self . v0 ) )
221
+ * ( self . xi ( ) * ( self . d_ ( ) * tau / 2.0 ) . cosh ( ) + self . d_ ( ) * ( self . d_ ( ) * tau / 2.0 ) . sinh ( ) )
222
+ }
223
+
224
+ pub ( self ) fn dA_drho ( & self , tau : f64 ) -> Complex64 {
225
+ ( 1.0 / self . A2 ( tau) ) * self . dA1_drho ( tau) - ( self . A ( tau) / self . A2 ( tau) ) * self . dA2_drho ( tau)
226
+ }
227
+
228
+ pub ( self ) fn dd__dsigma ( & self ) -> Complex64 {
229
+ ( self . rho / self . sigma - 1.0 / self . xi ( ) ) * self . dd__drho ( )
230
+ + ( self . sigma * self . u ( 1 ) . powi ( 2 ) / self . d_ ( ) )
231
+ }
232
+
233
+ pub ( self ) fn dA1_dsigma ( & self , tau : f64 ) -> Complex64 {
234
+ ( ( ( self . u ( 1 ) . powi ( 2 ) + Complex64 :: i ( ) * self . u ( 1 ) ) * tau) / 2.0 )
235
+ * self . dd__dsigma ( )
236
+ * ( self . d_ ( ) * tau / 2.0 ) . cosh ( )
237
+ }
238
+
239
+ pub ( self ) fn dA2_dsigma ( & self , tau : f64 ) -> Complex64 {
240
+ ( self . rho / self . sigma ) * self . dA2_drho ( tau)
241
+ - ( ( 2.0 + tau * self . xi ( ) ) / ( self . v0 * tau * self . xi ( ) * Complex64 :: i ( ) * self . u ( 1 ) ) )
242
+ * self . dA1_drho ( tau)
243
+ + ( self . sigma * tau * self . A1 ( tau) ) / ( 2.0 * self . v0 )
244
+ }
245
+
246
+ pub ( self ) fn dA_dsigma ( & self , tau : f64 ) -> Complex64 {
247
+ ( 1.0 / self . A2 ( tau) ) * self . dA1_dsigma ( tau)
248
+ - ( self . A ( tau) / self . A2 ( tau) ) * self . dA2_dsigma ( tau)
249
+ }
250
+
251
+ pub ( self ) fn dB_drho ( & self , tau : f64 ) -> Complex64 {
252
+ ( ( self . kappa * tau / 2.0 ) . exp ( ) / self . v0 )
253
+ * ( ( 1.0 / self . A2 ( tau) ) * self . dd__drho ( )
254
+ - ( self . d_ ( ) / self . A2 ( tau) . powi ( 2 ) ) * self . dA2_drho ( tau) )
255
+ }
256
+
257
+ pub ( self ) fn dB_dkappa ( & self , tau : f64 ) -> Complex64 {
258
+ ( Complex64 :: i ( ) / ( self . sigma * self . u ( 1 ) ) ) * self . dB_drho ( tau) + ( self . B ( tau) * tau) / 2.0
259
+ }
260
+
189
261
pub ( self ) fn xi ( & self ) -> Complex64 {
190
262
self . kappa - self . sigma * self . rho * Complex64 :: i ( ) * self . u ( 1 )
191
263
}
@@ -195,10 +267,6 @@ impl HestonPricer {
195
267
. sqrt ( )
196
268
}
197
269
198
- pub ( self ) fn dd_dsigma ( & self ) -> Complex64 {
199
- ( self . sigma * ( self . u ( 1 ) + Complex64 :: i ( ) * self . u ( 1 ) ) ) / self . d_ ( )
200
- }
201
-
202
270
pub ( self ) fn A1 ( & self , tau : f64 ) -> Complex64 {
203
271
( self . u ( 1 ) . powi ( 2 ) + Complex64 :: i ( ) * self . u ( 1 ) ) * ( self . d_ ( ) * tau / 2.0 ) . sinh ( )
204
272
}
@@ -212,19 +280,12 @@ impl HestonPricer {
212
280
self . A1 ( tau) / self . A2 ( tau)
213
281
}
214
282
215
- pub ( self ) fn D_ ( & self , tau : f64 ) -> Complex64 {
216
- ( self . d_ ( ) / self . v0 ) . ln ( ) + ( self . kappa - self . d_ ( ) / 2.0 ) * tau
217
- - ( ( ( self . d_ ( ) + self . xi ( ) ) / ( 2.0 * self . v0 ) )
218
- + ( ( self . d_ ( ) - self . xi ( ) ) / ( 2.0 * self . v0 ) ) * ( -self . d_ ( ) * tau) . exp ( ) )
219
- . ln ( )
220
- }
221
-
222
283
pub ( self ) fn B ( & self , tau : f64 ) -> Complex64 {
223
284
( self . d_ ( ) * ( self . kappa * tau / 2.0 ) . exp ( ) ) / ( self . v0 * self . A2 ( tau) )
224
285
}
225
286
226
- pub ( self ) fn dB_dkappa ( & self , tau : f64 ) -> Complex64 {
227
- ( self . d_ ( ) * tau * ( self . kappa * tau / 2.0 ) . exp ( ) ) / ( 2.0 * self . v0 * self . A2 ( tau ) )
287
+ pub ( self ) fn D_ ( & self , tau : f64 ) -> Complex64 {
288
+ self . B ( tau) . ln ( )
228
289
}
229
290
}
230
291
0 commit comments