implied_vol/builder/
implied_normal_volatility.rs1use 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})
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}