Skip to main content

rustyqlib/core/
utils.rs

1//mod dis{
2use libm::erf;
3use std::f64::consts::{PI, SQRT_2};
4use serde::{Deserialize, Serialize};
5use crate::core::data_models::ProductData;
6
7#[derive(PartialEq,Clone,Debug)]
8pub enum ContractStyle {
9    European,
10    American,
11}
12
13#[derive(strum_macros::Display)]
14pub enum EngineType {
15    Analytical,
16    MonteCarlo,
17    Binomial,
18    FiniteDifference,
19    FFT,
20}
21pub trait Engine<I> {
22    fn npv(&self, instrument: &I) -> f64;
23}
24
25impl EngineType {
26    pub fn as_str(&self) -> &'static str {
27        match self {
28            EngineType::Analytical => "Analytical",
29            EngineType::MonteCarlo => "MonteCarlo",
30            EngineType::Binomial => "Binomial",
31            EngineType::FiniteDifference => "FiniteDifference",
32            EngineType::FFT => "FFT",
33        }
34    }
35}
36
37
38
39// #[derive(Clone,Debug,Deserialize,Serialize)]
40// pub struct MarketData {
41//     pub underlying_price:f64,
42//     pub option_type:Option<String>,
43//     pub strike_price:Option<f64>,
44//     pub volatility:Option<f64>,
45//     pub option_price:Option<f64>,
46//     pub risk_free_rate:Option<f64>,
47//     pub maturity:String,
48//     pub dividend: Option<f64>,
49//     pub simulation:Option<u64>,
50//     pub current_price:Option<f64>,
51//     pub notional: Option<f64>,
52//     pub long_short:Option<i32>,
53//     pub multiplier:Option<f64>,
54//     pub entry_price:Option<f64>,
55// }
56
57
58#[derive(Clone,Debug,Deserialize,Serialize)]
59pub struct RateData {
60    pub instrument: String,
61    pub currency: String,
62    pub start_date: String,
63    pub maturity_date: String,
64    pub valuation_date: String,
65    pub notional: f64,
66    pub fix_rate: f64,
67    pub day_count: String,
68    pub business_day_adjustment: i8,
69}
70
71#[derive(Clone,Debug,Deserialize,Serialize)]
72pub struct Contract {
73    pub action: String,
74    pub asset: String,
75    pub product_type: ProductData,
76    pub rate_data: Option<RateData>,
77}
78#[derive(Deserialize,Serialize)]
79pub struct CombinedContract{
80    pub contract: Contract,
81    pub output: ContractOutput
82}
83
84#[derive(Debug, Deserialize,Serialize)]
85pub struct Contracts {
86    pub asset: String,
87    pub contracts: Vec<Contract>,
88}
89#[derive(Debug, Deserialize,Serialize)]
90pub struct OutputJson {
91    pub contracts: Vec<String>,
92}
93#[derive(Deserialize,Serialize)]
94pub struct ContractOutput {
95    pub pv: f64,
96    pub delta: f64,
97    pub gamma: f64,
98    pub vega: f64,
99    pub theta: f64,
100    pub rho: f64,
101    /// Monte Carlo standard error of `pv` (None for deterministic engines).
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub std_err: Option<f64>,
104    /// Per-asset deltas for multi-asset (rainbow) products.
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub deltas: Option<Vec<f64>>,
107    /// Per-asset vegas for multi-asset (rainbow) products.
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub vegas: Option<Vec<f64>>,
110    pub error: Option<String>
111}
112
113/// Probability density function of a standard normal random variable x.
114pub fn dN(x: f64) -> f64 {
115    let t = -0.5 * x * x;
116    t.exp() / (SQRT_2 * PI.sqrt())
117}
118
119/// Cumulative distribution function of a standard normal random variable x.
120pub fn N(x: f64) -> f64 {
121    0.5 * (1.0 + erf(x / SQRT_2))
122}
123
124/// Inverse of the standard normal CDF (quantile function).
125///
126/// Acklam's rational approximation refined with one Halley step against the
127/// erf-based [`N`], giving close to machine precision. `p` must be in (0, 1);
128/// values outside return NaN.
129pub fn inv_N(p: f64) -> f64 {
130    if !(p > 0.0 && p < 1.0) {
131        return f64::NAN;
132    }
133    const A: [f64; 6] = [
134        -3.969683028665376e+01,
135        2.209460984245205e+02,
136        -2.759285104469687e+02,
137        1.383577518672690e+02,
138        -3.066479806614716e+01,
139        2.506628277459239e+00,
140    ];
141    const B: [f64; 5] = [
142        -5.447609879822406e+01,
143        1.615858368580409e+02,
144        -1.556989798598866e+02,
145        6.680131188771972e+01,
146        -1.328068155288572e+01,
147    ];
148    const C: [f64; 6] = [
149        -7.784894002430293e-03,
150        -3.223964580411365e-01,
151        -2.400758277161838e+00,
152        -2.549732539343734e+00,
153        4.374664141464968e+00,
154        2.938163982698783e+00,
155    ];
156    const D: [f64; 4] = [
157        7.784695709041462e-03,
158        3.224671290700398e-01,
159        2.445134137142996e+00,
160        3.754408661907416e+00,
161    ];
162    const P_LOW: f64 = 0.02425;
163
164    let tail = |q: f64| -> f64 {
165        (((((C[0] * q + C[1]) * q + C[2]) * q + C[3]) * q + C[4]) * q + C[5])
166            / ((((D[0] * q + D[1]) * q + D[2]) * q + D[3]) * q + 1.0)
167    };
168    let mut x = if p < P_LOW {
169        tail((-2.0 * p.ln()).sqrt())
170    } else if p <= 1.0 - P_LOW {
171        let q = p - 0.5;
172        let r = q * q;
173        (((((A[0] * r + A[1]) * r + A[2]) * r + A[3]) * r + A[4]) * r + A[5]) * q
174            / (((((B[0] * r + B[1]) * r + B[2]) * r + B[3]) * r + B[4]) * r + 1.0)
175    } else {
176        -tail((-2.0 * (1.0 - p).ln()).sqrt())
177    };
178    // one Halley refinement step
179    let e = N(x) - p;
180    let u = e * (2.0 * PI).sqrt() * (x * x / 2.0).exp();
181    x -= u / (1.0 + x * u / 2.0);
182    x
183}
184