implied_vol/builder/
implied_normal_volatility.rs

1use crate::{SpecialFn, lets_be_rational};
2use bon::Builder;
3
4#[derive(Builder)]
5#[builder(const, derive(Clone, Debug),
6finish_fn(name = build_unchecked,
7doc{
8/// Build without performing any validation.
9///
10/// This constructor constructs the `ImpliedNormalVolatility` directly from
11/// the builder's fields and does **not** check for NaNs, infinities, or
12/// sign constraints. Use only when you are certain the inputs are valid
13/// or when you want to avoid the cost of runtime validation.
14})
15)]
16pub struct ImpliedNormalVolatility {
17    forward: f64,
18    strike: f64,
19    expiry: f64,
20    is_call: bool,
21    option_price: f64,
22}
23
24impl<S: implied_normal_volatility_builder::IsComplete> ImpliedNormalVolatilityBuilder<S> {
25    pub const fn build(self) -> Option<ImpliedNormalVolatility> {
26        let implied_normal_volatility = self.build_unchecked();
27        if !implied_normal_volatility.forward.is_finite() {
28            return None;
29        }
30        if !implied_normal_volatility.strike.is_finite() {
31            return None;
32        }
33        if !(implied_normal_volatility.expiry >= 0.0_f64) {
34            return None;
35        }
36        if !(implied_normal_volatility.option_price >= 0.0_f64)
37            || implied_normal_volatility.option_price.is_infinite()
38        {
39            return None;
40        }
41        Some(implied_normal_volatility)
42    }
43}
44
45impl ImpliedNormalVolatility {
46    #[must_use]
47    #[inline(always)]
48    pub fn calculate<SpFn: SpecialFn>(&self) -> Option<f64> {
49        if self.is_call {
50            lets_be_rational::bachelier_impl::implied_normal_volatility_input_unchecked::<SpFn, true>(
51                self.option_price,
52                self.forward,
53                self.strike,
54                self.expiry,
55            )
56        } else {
57            lets_be_rational::bachelier_impl::implied_normal_volatility_input_unchecked::<SpFn, false>(
58                self.option_price,
59                self.forward,
60                self.strike,
61                self.expiry,
62            )
63        }
64    }
65}