use super::types::VolatilityQuoteKind;
use crate::pricing::sabr::hagan_implied_vol;
use crate::traits::FloatExt;
pub trait VolatilityModel<T: FloatExt>: Send + Sync {
fn implied_volatility(&self, forward: T, strike: T, tau: T) -> T;
fn quote_kind(&self) -> VolatilityQuoteKind;
}
#[derive(Debug, Clone, Copy)]
pub struct BlackVolatility<T: FloatExt> {
pub sigma: T,
}
impl<T: FloatExt> BlackVolatility<T> {
pub fn new(sigma: T) -> Self {
Self { sigma }
}
}
impl<T: FloatExt> VolatilityModel<T> for BlackVolatility<T> {
fn implied_volatility(&self, _forward: T, _strike: T, _tau: T) -> T {
self.sigma
}
fn quote_kind(&self) -> VolatilityQuoteKind {
VolatilityQuoteKind::Lognormal
}
}
#[derive(Debug, Clone, Copy)]
pub struct BachelierVolatility<T: FloatExt> {
pub sigma: T,
}
impl<T: FloatExt> BachelierVolatility<T> {
pub fn new(sigma: T) -> Self {
Self { sigma }
}
}
impl<T: FloatExt> VolatilityModel<T> for BachelierVolatility<T> {
fn implied_volatility(&self, _forward: T, _strike: T, _tau: T) -> T {
self.sigma
}
fn quote_kind(&self) -> VolatilityQuoteKind {
VolatilityQuoteKind::Normal
}
}
#[derive(Debug, Clone, Copy)]
pub struct SabrVolatility<T: FloatExt> {
pub alpha: T,
pub beta: T,
pub nu: T,
pub rho: T,
}
impl<T: FloatExt> SabrVolatility<T> {
pub fn new(alpha: T, beta: T, nu: T, rho: T) -> Self {
Self {
alpha,
beta,
nu,
rho,
}
}
}
impl<T: FloatExt> VolatilityModel<T> for SabrVolatility<T> {
fn implied_volatility(&self, forward: T, strike: T, tau: T) -> T {
let sigma = hagan_implied_vol(
strike.to_f64().unwrap_or(0.0),
forward.to_f64().unwrap_or(0.0),
tau.to_f64().unwrap_or(0.0),
self.alpha.to_f64().unwrap_or(0.0),
self.beta.to_f64().unwrap_or(0.0),
self.nu.to_f64().unwrap_or(0.0),
self.rho.to_f64().unwrap_or(0.0),
);
T::from_f64_fast(sigma)
}
fn quote_kind(&self) -> VolatilityQuoteKind {
VolatilityQuoteKind::Lognormal
}
}
#[derive(Debug, Clone, Copy)]
pub struct ShiftedSabrVolatility<T: FloatExt> {
pub alpha: T,
pub beta: T,
pub nu: T,
pub rho: T,
pub shift: T,
}
impl<T: FloatExt> ShiftedSabrVolatility<T> {
pub fn new(alpha: T, beta: T, nu: T, rho: T, shift: T) -> Self {
Self {
alpha,
beta,
nu,
rho,
shift,
}
}
}
impl<T: FloatExt> VolatilityModel<T> for ShiftedSabrVolatility<T> {
fn implied_volatility(&self, forward: T, strike: T, tau: T) -> T {
let sigma = hagan_implied_vol(
(strike + self.shift).to_f64().unwrap_or(0.0),
(forward + self.shift).to_f64().unwrap_or(0.0),
tau.to_f64().unwrap_or(0.0),
self.alpha.to_f64().unwrap_or(0.0),
self.beta.to_f64().unwrap_or(0.0),
self.nu.to_f64().unwrap_or(0.0),
self.rho.to_f64().unwrap_or(0.0),
);
T::from_f64_fast(sigma)
}
fn quote_kind(&self) -> VolatilityQuoteKind {
VolatilityQuoteKind::Lognormal
}
}