use super::calibrator::LevyCalibrator;
use crate::CalibrationLossScore;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LevyModelType {
VarianceGamma,
Nig,
Cgmy,
MertonJD,
Kou,
}
#[derive(Clone, Debug)]
pub struct MarketSlice {
pub strikes: Vec<f64>,
pub prices: Vec<f64>,
pub is_call: Vec<bool>,
pub t: f64,
}
impl MarketSlice {
pub fn from_dates(
strikes: Vec<f64>,
prices: Vec<f64>,
is_call: Vec<bool>,
eval: chrono::NaiveDate,
expiration: chrono::NaiveDate,
dcc: crate::calendar::DayCountConvention,
) -> Self {
let t = dcc.year_fraction(eval, expiration);
Self {
strikes,
prices,
is_call,
t,
}
}
}
#[derive(Clone, Debug)]
pub struct LevyParams {
pub values: Vec<f64>,
pub model_type: LevyModelType,
}
#[derive(Clone, Debug)]
pub struct LevyCalibrationResult {
pub params: Vec<f64>,
pub model_type: LevyModelType,
pub loss: CalibrationLossScore,
pub converged: bool,
pub iterations: usize,
}
#[derive(Clone, Debug)]
pub enum LevyModel {
VarianceGamma(crate::pricing::fourier::VarianceGammaFourier),
Nig(crate::pricing::fourier::NigFourier),
Cgmy(crate::pricing::fourier::CGMYFourier),
MertonJd(crate::pricing::fourier::MertonJDFourier),
Kou(crate::pricing::fourier::KouFourier),
}
impl crate::traits::ModelPricer for LevyModel {
fn price_call(&self, s: f64, k: f64, r: f64, q: f64, tau: f64) -> f64 {
match self {
LevyModel::VarianceGamma(m) => m.price_call(s, k, r, q, tau),
LevyModel::Nig(m) => m.price_call(s, k, r, q, tau),
LevyModel::Cgmy(m) => m.price_call(s, k, r, q, tau),
LevyModel::MertonJd(m) => m.price_call(s, k, r, q, tau),
LevyModel::Kou(m) => m.price_call(s, k, r, q, tau),
}
}
}
impl crate::traits::ToModel for LevyCalibrationResult {
type Model = LevyModel;
fn to_model(&self, r: f64, q: f64) -> Self::Model {
LevyCalibrationResult::to_model(self, r, q)
}
}
impl crate::traits::CalibrationResult for LevyCalibrationResult {
type Params = LevyParams;
fn rmse(&self) -> f64 {
self.loss.get(crate::LossMetric::Rmse)
}
fn params(&self) -> Self::Params {
LevyParams {
values: self.params.clone(),
model_type: self.model_type,
}
}
fn converged(&self) -> bool {
self.converged
}
fn loss_score(&self) -> Option<&crate::CalibrationLossScore> {
Some(&self.loss)
}
}
impl crate::traits::Calibrator for LevyCalibrator {
type InitialGuess = Vec<f64>;
type Params = LevyParams;
type Output = LevyCalibrationResult;
type Error = anyhow::Error;
fn calibrate(&self, initial: Option<Self::InitialGuess>) -> Result<Self::Output, Self::Error> {
Ok(self.solve(initial))
}
}
impl LevyCalibrationResult {
pub fn to_model(&self, r: f64, q: f64) -> LevyModel {
use crate::pricing::fourier::*;
let p = &self.params;
match self.model_type {
LevyModelType::VarianceGamma => LevyModel::VarianceGamma(VarianceGammaFourier {
sigma: p[0],
theta: p[1],
nu: p[2],
r,
q,
}),
LevyModelType::Nig => LevyModel::Nig(NigFourier {
alpha: p[0],
beta: p[1],
delta: p[2],
r,
q,
}),
LevyModelType::Cgmy => LevyModel::Cgmy(CGMYFourier {
c: p[0],
g: p[1],
m: p[2],
y: p[3],
r,
q,
}),
LevyModelType::MertonJD => LevyModel::MertonJd(MertonJDFourier {
sigma: p[0],
lambda: p[1],
mu_j: p[2],
sigma_j: p[3],
r,
q,
}),
LevyModelType::Kou => LevyModel::Kou(KouFourier {
sigma: p[0],
lambda: p[1],
p_up: p[2],
eta1: p[3],
eta2: p[4],
r,
q,
}),
}
}
}