@@ -2,8 +2,10 @@ use std::f64::consts::FRAC_1_PI;
22
33use impl_new_derive:: ImplNew ;
44use implied_vol:: implied_black_volatility;
5+ use nalgebra:: Complex ;
56use num_complex:: Complex64 ;
67use quadrature:: double_exponential;
8+ use rand_distr:: num_traits:: ConstOne ;
79
810use crate :: quant:: {
911 r#trait:: { PricerExt , TimeExt } ,
@@ -58,11 +60,11 @@ impl PricerExt for HestonPricer {
5860 let tau = self . tau ( ) . unwrap_or ( 1.0 ) ;
5961
6062 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) ,
6668 ]
6769 }
6870
@@ -154,38 +156,108 @@ impl HestonPricer {
154156 /// https://www.sciencedirect.com/science/article/abs/pii/S0377221717304460
155157
156158 /// 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
159161 }
160162
161163 /// 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 {
163165 ( ( 2.0 * self . kappa / self . sigma . powi ( 2 ) ) * self . D_ ( tau)
164166 - self . kappa * self . rho * tau * Complex64 :: i ( ) * self . u ( 1 ) / self . sigma )
165167 . re
166168 }
167169
168170 /// 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
171177 }
172178
173179 /// 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 )
178186 . re
179187 }
180188
181189 /// 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 ) )
186196 . re
187197 }
188198
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+
189261 pub ( self ) fn xi ( & self ) -> Complex64 {
190262 self . kappa - self . sigma * self . rho * Complex64 :: i ( ) * self . u ( 1 )
191263 }
@@ -195,10 +267,6 @@ impl HestonPricer {
195267 . sqrt ( )
196268 }
197269
198- pub ( self ) fn dd_dsigma ( & self ) -> Complex64 {
199- ( self . sigma * ( self . u ( 1 ) + Complex64 :: i ( ) * self . u ( 1 ) ) ) / self . d_ ( )
200- }
201-
202270 pub ( self ) fn A1 ( & self , tau : f64 ) -> Complex64 {
203271 ( self . u ( 1 ) . powi ( 2 ) + Complex64 :: i ( ) * self . u ( 1 ) ) * ( self . d_ ( ) * tau / 2.0 ) . sinh ( )
204272 }
@@ -212,19 +280,12 @@ impl HestonPricer {
212280 self . A1 ( tau) / self . A2 ( tau)
213281 }
214282
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-
222283 pub ( self ) fn B ( & self , tau : f64 ) -> Complex64 {
223284 ( self . d_ ( ) * ( self . kappa * tau / 2.0 ) . exp ( ) ) / ( self . v0 * self . A2 ( tau) )
224285 }
225286
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 ( )
228289 }
229290}
230291
0 commit comments