black_76/lib.rs
1//! Black-76 option pricing model: closed-form prices, Greeks, and implied
2//! volatility solver for futures and forward options.
3//!
4//! The Black-76 model (Fischer Black, *The Pricing of Commodity Contracts*,
5//! Journal of Financial Economics, 1976) prices European options on forward
6//! and futures contracts. Use it for Eurodollar options, FX forward options,
7//! commodity-futures options, and crypto perpetual-futures options where
8//! the underlying is a forward, not a spot.
9//!
10//! # Quick start
11//!
12//! ```
13//! use black_76::{call_price, solve_iv, SolverConfig};
14//!
15//! // Price an ATM call: F=100, K=100, T=1 year, sigma=20%, r=0
16//! let c = call_price(100.0, 100.0, 1.0, 0.20, 0.0);
17//! assert!((c - 7.9656).abs() < 1e-3);
18//!
19//! // Solve for implied volatility given a market price
20//! let cfg = SolverConfig::default();
21//! let result = solve_iv(7.9656, 100.0, 100.0, 1.0, 0.0, true, &cfg);
22//! assert!(result.converged);
23//! assert!((result.iv - 0.20).abs() < 1e-4);
24//! ```
25//!
26//! # Modules
27//!
28//! - [`pricing`]: closed-form Black-76 call/put prices, vega, intrinsic value.
29//! - [`iv_solver`]: Newton-Raphson with Brent's-method fallback.
30//! - [`greeks`]: analytical first-order Greeks (delta, gamma, vega, theta, rho).
31//! - [`inputs`]: [`BlackInputs`] / [`IvQuery`] typo-resistant, named-field wrappers.
32//! - [`types`]: `OptionType`, `SolverMethod`, `SolverResult`, `SolverStatus`, `InstrumentGreeks`.
33//! - [`config`]: `SolverConfig` (with builder) for tuning solver parameters.
34//! - [`vol_surface`] (feature `vol-surface`): per-expiry IV smile with linear interpolation.
35//! - [`digital`] (feature `digital`): risk-neutral probability extraction via call-spread replication and N(d2).
36//!
37//! # Feature flags
38//!
39//! - `serde`: adds `Serialize` / `Deserialize` derives on public types.
40//! - `vol-surface`: enables [`vol_surface`].
41//! - `digital`: enables [`digital`] (requires `vol-surface`).
42//!
43//! # Convergence checking
44//!
45//! [`iv_solver::solve_iv`] returns a [`SolverResult`] whose `converged: bool`
46//! field MUST be checked before consuming `iv`. Whenever the solver does not
47//! converge, `iv` is [`f64::NAN`] and [`SolverStatus`] reports the precise
48//! reason (non-finite input, near-expiry, below intrinsic, non-positive price,
49//! no root in `[iv_min, iv_max]`, vega-floor non-identifiability, or max
50//! iterations).
51//!
52//! # Equality and `NaN`
53//!
54//! The `f64`-bearing public types that derive [`PartialEq`] (e.g.
55//! [`BlackInputs`], [`SolverConfig`]) inherit IEEE-754 semantics, so a value
56//! holding a `NaN` is never equal to itself. This matters here because `NaN`
57//! is a first-class sentinel: the solver yields `iv = NaN` on every
58//! non-converged path. (Accordingly, [`SolverResult`] deliberately does *not*
59//! derive `PartialEq`.)
60
61#![cfg_attr(docsrs, feature(doc_cfg))]
62#![forbid(unsafe_code)]
63#![warn(missing_docs)]
64#![warn(rustdoc::broken_intra_doc_links)]
65// Black-76 uses standard single-letter math notation (f, k, t, r, sigma,
66// d1/d2, and a/b/c/d for the Brent iterates); spelling these out would reduce,
67// not improve, readability for anyone who knows the model.
68#![allow(clippy::many_single_char_names)]
69
70pub mod config;
71pub mod greeks;
72pub mod inputs;
73pub mod iv_solver;
74pub mod pricing;
75pub mod types;
76
77#[cfg(feature = "vol-surface")]
78#[cfg_attr(docsrs, doc(cfg(feature = "vol-surface")))]
79pub mod vol_surface;
80
81#[cfg(feature = "digital")]
82#[cfg_attr(docsrs, doc(cfg(feature = "digital")))]
83pub mod digital;
84
85// Curated top-level re-exports
86pub use config::SolverConfig;
87pub use greeks::compute_greeks;
88pub use inputs::{BlackInputs, IvQuery};
89pub use iv_solver::{solve_iv, solve_iv_triple};
90pub use pricing::{call_price, d1_d2, intrinsic_value, price, put_price, vega};
91pub use types::{InstrumentGreeks, OptionType, SolverMethod, SolverResult, SolverStatus};