1use 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)]
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 #[serde(skip_serializing_if = "Option::is_none")]
103 pub std_err: Option<f64>,
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub deltas: Option<Vec<f64>>,
107 #[serde(skip_serializing_if = "Option::is_none")]
109 pub vegas: Option<Vec<f64>>,
110 pub error: Option<String>
111}
112
113pub fn dN(x: f64) -> f64 {
115 let t = -0.5 * x * x;
116 t.exp() / (SQRT_2 * PI.sqrt())
117}
118
119pub fn N(x: f64) -> f64 {
121 0.5 * (1.0 + erf(x / SQRT_2))
122}
123
124pub 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 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