Skip to main content

stochastic_rs_quant/
types.rs

1//! # Shared types
2//!
3//! Cross-cutting enums and result containers used across the quant crate:
4//! option taxonomy ([`OptionType`], [`OptionStyle`], [`Moneyness`]) and
5//! calibration loss metrics ([`LossMetric`], [`CalibrationLossScore`]).
6//!
7//! These types are also re-exported at the crate root for back-compat with
8//! v1 call-sites.
9
10use std::collections::HashMap;
11use std::fmt::Display;
12
13use crate::loss;
14
15/// Option type.
16#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
17pub enum OptionType {
18  #[default]
19  Call,
20  Put,
21}
22
23/// Option style.
24#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
25pub enum OptionStyle {
26  American,
27  #[default]
28  European,
29}
30
31/// Moneyness.
32#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
33pub enum Moneyness {
34  #[default]
35  DeepInTheMoney,
36  InTheMoney,
37  AtTheMoney,
38  OutOfTheMoney,
39  DeepOutOfTheMoney,
40}
41
42impl Display for Moneyness {
43  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44    match self {
45      Moneyness::DeepInTheMoney => write!(f, "Deep in the money"),
46      Moneyness::InTheMoney => write!(f, "In the money"),
47      Moneyness::AtTheMoney => write!(f, "At the money"),
48      Moneyness::OutOfTheMoney => write!(f, "Out of the money"),
49      Moneyness::DeepOutOfTheMoney => write!(f, "Deep out of the money"),
50    }
51  }
52}
53
54/// Individual loss metric selector.
55#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
56pub enum LossMetric {
57  Mae,
58  Mse,
59  Rmse,
60  Mpe,
61  Mape,
62  Mspe,
63  Rmspe,
64  Mre,
65  Mrpe,
66}
67
68impl LossMetric {
69  pub const ALL: [Self; 9] = [
70    Self::Mae,
71    Self::Mse,
72    Self::Rmse,
73    Self::Mpe,
74    Self::Mape,
75    Self::Mspe,
76    Self::Rmspe,
77    Self::Mre,
78    Self::Mrpe,
79  ];
80
81  fn compute(self, market: &[f64], model: &[f64]) -> f64 {
82    match self {
83      Self::Mae => loss::mae(market, model),
84      Self::Mse => loss::mse(market, model),
85      Self::Rmse => loss::rmse(market, model),
86      Self::Mpe => loss::mpe(market, model),
87      Self::Mape => loss::mape(market, model),
88      Self::Mspe => loss::mspe(market, model),
89      Self::Rmspe => loss::rmspe(market, model),
90      Self::Mre => loss::mre(market, model),
91      Self::Mrpe => loss::mrpe(market, model),
92    }
93  }
94}
95
96/// Holds calibration loss metrics as a `HashMap<LossMetric, f64>`.
97#[derive(Default, Debug, Clone)]
98pub struct CalibrationLossScore {
99  pub scores: HashMap<LossMetric, f64>,
100}
101
102impl CalibrationLossScore {
103  /// Compute all loss metrics.
104  pub fn compute(market: &[f64], model: &[f64]) -> Self {
105    Self::compute_selected(market, model, &LossMetric::ALL)
106  }
107
108  /// Compute only the selected metrics.
109  pub fn compute_selected(market: &[f64], model: &[f64], metrics: &[LossMetric]) -> Self {
110    let scores = metrics
111      .iter()
112      .map(|&m| (m, m.compute(market, model)))
113      .collect();
114    Self { scores }
115  }
116
117  /// Get a metric value. Returns 0.0 if not computed.
118  pub fn get(&self, metric: LossMetric) -> f64 {
119    self.scores.get(&metric).copied().unwrap_or(0.0)
120  }
121}