use num_complex::Complex64;
use super::Cumulants;
use super::FourierModelExt;
#[derive(Debug, Clone)]
pub struct HestonFourier {
pub v0: f64,
pub kappa: f64,
pub theta: f64,
pub sigma: f64,
pub rho: f64,
pub r: f64,
pub q: f64,
}
impl FourierModelExt for HestonFourier {
fn chf(&self, t: f64, xi: Complex64) -> Complex64 {
let i = Complex64::i();
let sigma2 = self.sigma * self.sigma;
let rsi = self.rho * self.sigma * i;
let d = ((self.kappa - rsi * xi).powi(2) + sigma2 * (i * xi + xi * xi)).sqrt();
let g = (self.kappa - rsi * xi - d) / (self.kappa - rsi * xi + d);
let exp_dt = (-d * t).exp();
let c_val = (self.kappa * self.theta / sigma2)
* ((self.kappa - rsi * xi - d) * t - 2.0 * ((1.0 - g * exp_dt) / (1.0 - g)).ln());
let d_val = ((self.kappa - rsi * xi - d) / sigma2) * (1.0 - exp_dt) / (1.0 - g * exp_dt);
(c_val + d_val * self.v0 + i * xi * (self.r - self.q) * t).exp()
}
fn cumulants(&self, t: f64) -> Cumulants {
let ekt = (-self.kappa * t).exp();
let c1 = (self.r - self.q) * t + (1.0 - ekt) * (self.theta - self.v0) / (2.0 * self.kappa)
- 0.5 * self.theta * t;
let c2 = self.sigma.powi(2) * t * self.theta / (2.0 * self.kappa);
Cumulants { c1, c2, c4: 0.0 }
}
}
#[derive(Debug, Clone)]
pub struct DoubleHestonFourier {
pub v1_0: f64,
pub kappa1: f64,
pub theta1: f64,
pub sigma1: f64,
pub rho1: f64,
pub v2_0: f64,
pub kappa2: f64,
pub theta2: f64,
pub sigma2: f64,
pub rho2: f64,
pub r: f64,
pub q: f64,
}
impl DoubleHestonFourier {
#[inline]
fn factor_cd(
kappa: f64,
theta: f64,
sigma: f64,
rho: f64,
t: f64,
xi: Complex64,
) -> (Complex64, Complex64) {
let i = Complex64::i();
let sigma2 = sigma * sigma;
let rsi = rho * sigma * i;
let d = ((kappa - rsi * xi).powi(2) + sigma2 * (i * xi + xi * xi)).sqrt();
let g = (kappa - rsi * xi - d) / (kappa - rsi * xi + d);
let exp_dt = (-d * t).exp();
let c_val = (kappa * theta / sigma2)
* ((kappa - rsi * xi - d) * t - 2.0 * ((1.0 - g * exp_dt) / (1.0 - g)).ln());
let d_val = ((kappa - rsi * xi - d) / sigma2) * (1.0 - exp_dt) / (1.0 - g * exp_dt);
(c_val, d_val)
}
}
impl FourierModelExt for DoubleHestonFourier {
fn chf(&self, t: f64, xi: Complex64) -> Complex64 {
let i = Complex64::i();
let (c1, d1) = Self::factor_cd(self.kappa1, self.theta1, self.sigma1, self.rho1, t, xi);
let (c2, d2) = Self::factor_cd(self.kappa2, self.theta2, self.sigma2, self.rho2, t, xi);
(c1 + c2 + d1 * self.v1_0 + d2 * self.v2_0 + i * xi * (self.r - self.q) * t).exp()
}
fn cumulants(&self, t: f64) -> Cumulants {
let ekt1 = (-self.kappa1 * t).exp();
let ekt2 = (-self.kappa2 * t).exp();
let int_v1 = self.theta1 * t + (self.v1_0 - self.theta1) * (1.0 - ekt1) / self.kappa1;
let int_v2 = self.theta2 * t + (self.v2_0 - self.theta2) * (1.0 - ekt2) / self.kappa2;
let c1 = (self.r - self.q) * t - 0.5 * (int_v1 + int_v2);
let c2 = int_v1 + int_v2;
Cumulants { c1, c2, c4: 0.0 }
}
}