@@ -10,6 +10,9 @@ use crate::{
1010 stochastic:: { process:: poisson:: Poisson , Sampling } ,
1111} ;
1212
13+ /// CGMY Stochastic Volatility process
14+ ///
15+ /// https://www.econstor.eu/bitstream/10419/239493/1/175133161X.pdf
1316#[ derive( ImplNew ) ]
1417pub struct SVCGMY {
1518 /// Positive jump rate lambda_plus (corresponds to G)
@@ -18,19 +21,19 @@ pub struct SVCGMY {
1821 pub lambda_minus : f64 , // M
1922 /// Jump activity parameter alpha (corresponds to Y), with 0 < alpha < 2
2023 pub alpha : f64 ,
21- ///
24+ /// Mean reversion rate
2225 pub kappa : f64 ,
23- ///
26+ /// Long-term volatility
2427 pub eta : f64 ,
25- ///
28+ /// Volatility of volatility
2629 pub zeta : f64 ,
2730 ///
2831 pub rho : f64 ,
2932 /// Number of time steps
3033 pub n : usize ,
3134 /// Jumps
3235 pub j : usize ,
33- ///
36+ /// Initial value
3437 pub x0 : Option < f64 > ,
3538 /// Initial value
3639 pub v0 : Option < f64 > ,
@@ -45,80 +48,74 @@ impl Sampling<f64> for SVCGMY {
4548 let mut rng = rand:: thread_rng ( ) ;
4649
4750 let t_max = self . t . unwrap_or ( 1.0 ) ;
48- let dt = self . t . unwrap_or ( 1.0 ) / ( self . n - 1 ) as f64 ;
49- let mut x = Array1 :: < f64 > :: zeros ( self . n ) ;
50- x[ 0 ] = self . x0 . unwrap_or ( 0.0 ) ;
51-
52- let C = ( gamma ( 2.0 - self . alpha )
53- * ( self . lambda_plus . powf ( self . alpha - 2.0 ) + self . lambda_minus . powf ( self . alpha - 2.0 ) ) )
54- . powi ( -1 ) ;
55- let c = ( 2.0 * self . kappa ) / ( ( 1.0 - ( -self . kappa * dt) . exp ( ) ) * self . zeta . powi ( 2 ) ) ;
51+ let dt = t_max / ( self . n - 1 ) as f64 ;
5652
53+ let mut x = Array1 :: < f64 > :: zeros ( self . n ) ;
5754 let mut v = Array1 :: < f64 > :: zeros ( self . n ) ;
55+ let mut y = Array1 :: < f64 > :: zeros ( self . n ) ;
56+
57+ x[ 0 ] = self . x0 . unwrap_or ( 0.0 ) ;
5858 v[ 0 ] = self . v0 . unwrap_or ( 0.0 ) ;
5959
60+ let C = 1.0
61+ / ( gamma ( 2.0 - self . alpha )
62+ * ( self . lambda_plus . powf ( self . alpha - 2.0 ) + self . lambda_minus . powf ( self . alpha - 2.0 ) ) ) ;
63+ let c = ( 2.0 * self . kappa ) / ( ( 1.0 - ( -self . kappa * dt) . exp ( ) ) * self . zeta . powi ( 2 ) ) ;
6064 let df = 4.0 * self . kappa * self . eta / self . zeta . powi ( 2 ) ;
6165
66+ // Volatilitás folyamat generálása
6267 for i in 1 ..self . n {
6368 let ncp = 2.0 * c * v[ i - 1 ] * ( -self . kappa * dt) . exp ( ) ;
6469 let xi = non_central_chi_squared:: sample ( df, ncp, & mut rng) ;
65-
6670 v[ i] = xi / ( 2.0 * c) ;
6771 }
6872
6973 let U = Array1 :: < f64 > :: random ( self . j , Uniform :: new ( 0.0 , 1.0 ) ) ;
70- let E = Array1 :: < f64 > :: random ( self . j , Exp :: new ( 1.0 ) . unwrap ( ) ) ;
71- let E_ = Array1 :: < f64 > :: random ( self . j , Exp :: new ( 1.0 ) . unwrap ( ) ) ;
74+ let E = Array1 :: random ( self . j , Exp :: new ( 1.0 ) . unwrap ( ) ) ;
7275 let P = Poisson :: new ( 1.0 , Some ( self . j ) , None , None ) ;
73- let mut P = P . sample ( ) ;
74-
75- for ( idx, p) in P . iter_mut ( ) . enumerate ( ) {
76- * p = * p + E_ [ idx] ;
77- }
76+ let P = P . sample ( ) ;
77+ let tau = Array1 :: < f64 > :: random ( self . j , Uniform :: new ( 0.0 , 1.0 ) ) * t_max;
7878
79- let tau = Array1 :: < f64 > :: random ( self . j , Uniform :: new ( 0.0 , t_max) ) ;
8079 let mut c_tau = Array1 :: < f64 > :: zeros ( self . j ) ;
81-
82- for j in 1 ..self . j {
83- let mut c_tau_ = 0.0 ;
84- for i in 1 ..self . n {
85- let t_1 = ( i - 1 ) as f64 * dt;
86- let t = i as f64 * dt;
87-
88- if t_1 < tau[ j] && tau[ j] <= t {
89- c_tau_ += v[ i - 1 ]
90- }
91- }
92-
93- c_tau[ j] = C * c_tau_;
80+ for ( idx, tau_j) in tau. iter ( ) . enumerate ( ) {
81+ let k = ( ( tau_j / dt) . ceil ( ) as usize ) . min ( self . n - 1 ) ;
82+ let v_k = if k == 0 { v[ 0 ] } else { v[ k - 1 ] } ;
83+ c_tau[ idx] = C * v_k;
9484 }
95- println ! ( "{:?}" , c_tau ) ;
85+
9686 for i in 1 ..self . n {
97- let b = -( ( v[ i]
98- * ( self . lambda_plus . powf ( self . alpha - 1.0 ) - self . lambda_minus . powf ( self . alpha - 1.0 ) ) )
99- / ( ( 1.0 - self . alpha )
100- * ( self . lambda_plus . powf ( self . alpha - 2.0 ) + self . lambda_minus . powf ( self . alpha ) - 2.0 ) ) ) ;
87+ let numerator = v[ i - 1 ]
88+ * ( self . lambda_plus . powf ( self . alpha - 1.0 ) - self . lambda_minus . powf ( self . alpha - 1.0 ) ) ;
89+ let denominator = ( 1.0 - self . alpha )
90+ * ( self . lambda_plus . powf ( self . alpha - 2.0 ) + self . lambda_minus . powf ( self . alpha - 2.0 ) ) ;
91+ let b = -numerator / denominator;
10192
10293 let mut jump_component = 0.0 ;
94+
10395 let t_1 = ( i - 1 ) as f64 * dt;
10496 let t = i as f64 * dt;
10597
106- for j in 1 ..self . j {
107- let v_j = if rng. gen_bool ( 0.5 ) {
108- self . lambda_plus
109- } else {
110- -self . lambda_minus
111- } ;
112-
113- let term1 = ( ( self . alpha * P [ j] ) / ( 2.0 * c_tau[ j] * t_max) ) . powf ( -1.0 / self . alpha ) ;
114- let term2 = E [ j] * U [ j] . powf ( 1.0 / self . alpha ) / v_j. abs ( ) ;
115- let jump_size =
116- term1. min ( term2) * ( v_j / v_j. abs ( ) ) * if tau[ j] > t_1 && tau[ j] < t { 1.0 } else { 0.0 } ;
117-
118- jump_component += jump_size;
98+ for j in 0 ..self . j {
99+ if tau[ j] > t_1 && tau[ j] <= t {
100+ let v_j = if rng. gen_bool ( 0.5 ) {
101+ self . lambda_plus
102+ } else {
103+ -self . lambda_minus
104+ } ;
105+
106+ let term1 = ( ( self . alpha * P [ j] ) / ( 2.0 * c_tau[ j] * t_max) ) . powf ( -1.0 / self . alpha ) ;
107+ let term2 = E [ j] * U [ j] . powf ( 1.0 / self . alpha ) / v_j. abs ( ) ;
108+ let min_term = term1. min ( term2) ;
109+ let jump_size = min_term * ( v_j / v_j. abs ( ) ) ;
110+ jump_component += jump_size;
111+ }
119112 }
120113
121- x[ i] = x[ i - 1 ] + jump_component + b * dt + self . rho * v[ i - 1 ] ;
114+ y[ i] = y[ i - 1 ] + jump_component + b * dt;
115+ }
116+
117+ for i in 0 ..self . n {
118+ x[ i] = y[ i] + self . rho * v[ i] ;
122119 }
123120
124121 x
@@ -135,8 +132,10 @@ impl Sampling<f64> for SVCGMY {
135132
136133#[ cfg( test) ]
137134mod tests {
135+ use ndarray:: Axis ;
136+
138137 use super :: * ;
139- use crate :: { plot_1d, stochastic:: N } ;
138+ use crate :: { plot_1d, plot_nd , stochastic:: N } ;
140139
141140 #[ test]
142141 fn svcgmy_length_equals_n ( ) {
@@ -188,7 +187,7 @@ mod tests {
188187 0.0711 ,
189188 0.3443 ,
190189 -2.0280 ,
191- 100 ,
190+ 1000 ,
192191 1024 ,
193192 Some ( -0.25 ) ,
194193 Some ( 0.0064 ) ,
@@ -197,4 +196,24 @@ mod tests {
197196 ) ;
198197 plot_1d ! ( svcgmy. sample( ) , "SVCGMY Process" ) ;
199198 }
199+
200+ #[ test]
201+ fn svcgmy_plot_multi ( ) {
202+ let svcgmy = SVCGMY :: new (
203+ 25.46 ,
204+ 4.604 ,
205+ 0.52 ,
206+ 1.003 ,
207+ 0.0711 ,
208+ 0.3443 ,
209+ -2.0280 ,
210+ 1000 ,
211+ 1024 ,
212+ Some ( -0.25 ) ,
213+ Some ( 0.0064 ) ,
214+ Some ( 1.0 ) ,
215+ Some ( 10 ) ,
216+ ) ;
217+ plot_nd ! ( svcgmy. sample_par( ) , "SVCGMY Process" ) ;
218+ }
200219}
0 commit comments