use crate::{constants::*, Inputs, OptionType};
use num_traits::NumCast;
use statrs::distribution::{ContinuousCDF, Normal};
pub fn calc_d1d2(inputs: &Inputs) -> Result<(f32, f32), String> {
let sigma = inputs
.sigma
.ok_or("Expected Some(f32) for self.sigma, received None")?;
let numd1 =
(inputs.s / inputs.k).ln() + (inputs.r - inputs.q + (sigma.powi(2)) / 2.0) * inputs.t;
let den = sigma * (inputs.t.sqrt());
let d1 = numd1 / den;
let d2 = d1 - den;
Ok((d1, d2))
}
pub fn calc_nd1nd2(inputs: &Inputs) -> Result<(f32, f32), String> {
let nd1nd2 = {
let d1d2 = calc_d1d2(inputs)?;
let n: Normal = Normal::new(N_MEAN as f64, N_STD_DEV as f64).unwrap();
let num_cast_err: String = "Failed to cast f64 to f32".into();
match inputs.option_type {
OptionType::Call => (
NumCast::from(n.cdf(NumCast::from(d1d2.0).ok_or(&num_cast_err)?))
.ok_or(&num_cast_err)?,
NumCast::from(n.cdf(NumCast::from(d1d2.1).ok_or(&num_cast_err)?))
.ok_or(&num_cast_err)?,
),
OptionType::Put => (
NumCast::from(n.cdf(NumCast::from(-d1d2.0).ok_or(&num_cast_err)?))
.ok_or(&num_cast_err)?,
NumCast::from(n.cdf(NumCast::from(-d1d2.1).ok_or(&num_cast_err)?))
.ok_or(&num_cast_err)?,
),
}
};
Ok(nd1nd2)
}
pub fn calc_npdf(x: f32) -> f32 {
let d: f32 = (x - N_MEAN) / N_STD_DEV;
(-HALF * d * d).exp() / (SQRT_2PI * N_STD_DEV)
}
pub fn calc_nprimed1(inputs: &Inputs) -> Result<f32, String> {
let (d1, _) = calc_d1d2(&inputs)?;
let nprimed1 = calc_npdf(d1);
Ok(nprimed1)
}
pub fn calc_nprimed2(inputs: &Inputs) -> Result<f32, String> {
let (_, d2) = calc_d1d2(&inputs)?;
let nprimed2 = calc_npdf(d2);
Ok(nprimed2)
}