quant_opts/
lib.rs

1//! High-performance Black–Scholes–Merton primitives for pricing European vanilla options,
2//! computing Greeks, and implied volatility.
3//!
4//! ## Quick start
5//! ```
6//! use quant_opts::{BlackScholes, MarketData, OptionStyle, OptionType, VanillaModel, VanillaOption};
7//!
8//! // Define an option and market snapshot
9//! let option = VanillaOption::new(OptionStyle::European, OptionType::Call, 100.0, 30.0 / 365.25);
10//! let market = MarketData::new(105.0, 0.03, 0.01);
11//! let sigma = 0.22;
12//!
13//! // Static API
14//! let price = BlackScholes::price(&option, &market, sigma).unwrap();
15//! let greeks = BlackScholes::greeks(&option, &market, sigma).unwrap();
16//!
17//! // Trait-based API
18//! let model = BlackScholes::new(sigma);
19//! let price_via_trait = model.price(&option, &market).unwrap();
20//! assert!((price - price_via_trait).abs() < 1e-12);
21//! ```
22//!
23//! More runnable examples live under `examples/`:
24//! - `cargo run --example pricing_and_greeks`
25//! - `cargo run --example implied_vol`
26//!
27//! Benchmark commands are documented in `README.md` and `docs/BENCHMARKING.md`.
28
29pub mod core;
30pub mod models;
31
32pub mod lets_be_rational;
33
34pub use core::{MarketData, OptionStyle, OptionType, VanillaOption};
35
36pub use models::{VanillaModel, black_scholes::BlackScholes};
37
38#[cfg(feature = "wrappers")]
39pub mod wrappers;
40
41#[cfg(target_arch = "wasm32")]
42mod wasm_api {
43    use wasm_bindgen::prelude::*;
44
45    use crate::{BlackScholes, MarketData, OptionStyle, OptionType, VanillaOption};
46
47    /// Price a European call via Black–Scholes (WASM binding).
48    #[wasm_bindgen]
49    pub fn price_call_bs(
50        spot: f64,
51        strike: f64,
52        maturity_years: f64,
53        rate: f64,
54        dividend_yield: f64,
55        vol: f64,
56    ) -> Result<f64, JsValue> {
57        let opt = VanillaOption::new(
58            OptionStyle::European,
59            OptionType::Call,
60            strike,
61            maturity_years,
62        );
63        let mkt = MarketData::new(spot, rate, dividend_yield);
64        BlackScholes::price(&opt, &mkt, vol).map_err(|e| JsValue::from_str(&e))
65    }
66
67    /// Dividend-adjusted rational implied volatility for a call.
68    #[wasm_bindgen]
69    pub fn rational_iv_bs(
70        observed_price: f64,
71        spot: f64,
72        strike: f64,
73        maturity_years: f64,
74        rate: f64,
75        dividend_yield: f64,
76    ) -> Result<f64, JsValue> {
77        let opt = VanillaOption::new(
78            OptionStyle::European,
79            OptionType::Call,
80            strike,
81            maturity_years,
82        );
83        let mkt = MarketData::new(spot, rate, dividend_yield);
84        BlackScholes::rational_implied_vol(observed_price, &opt, &mkt)
85            .map_err(|e| JsValue::from_str(&e))
86    }
87}
88
89pub(crate) const DAYS_PER_YEAR: f64 = 365.25;
90
91pub(crate) const A: f64 = 4.626_275_3e-1;
92pub(crate) const B: f64 = -1.168_519_2e-2;
93pub(crate) const C: f64 = 9.635_418_5e-4;
94pub(crate) const D: f64 = 7.535_022_5e-5;
95pub(crate) const _E: f64 = 1.424_516_45e-5;
96pub(crate) const F: f64 = -2.102_376_9e-5;