Implementation:Avhz RustQuant Bachelier Model
| Knowledge Sources | |
|---|---|
| Domains | Option_Pricing, Normal_Model, Quantitative_Finance |
| Last Updated | 2026-02-07 19:00 GMT |
Overview
Concrete tool for Bachelier (1900) normal model option pricing provided by the RustQuant library.
Description
The Bachelier struct implements the Bachelier (normal) option pricing model. Unlike the Black-Scholes model which assumes log-normal asset price dynamics, the Bachelier model assumes that the underlying price follows an arithmetic Brownian motion (normal distribution). This makes it particularly suitable for pricing options on assets that can take negative values, such as interest rate spreads or commodity spreads.
The model computes the standard normal variable d = (F - K) / (v * sqrt(T)) and applies a discount factor df = exp(-r * T).
The implementation provides a comprehensive set of methods:
Pricing:
call_price/put_price-- European option prices using the normal distribution CDF and PDF.atm_price-- At-the-money option price:v * sqrt(T / (2 * pi)).
Implied Volatility:
call_iv/put_iv-- Closed-form implied normal volatility using a rational function approximation with precomputed Chebyshev coefficients (arrays A[8] and B[9]).atm_vol-- ATM implied volatility:price * sqrt(2 * pi / T).
Greeks:
delta-- N(d) for calls; N(d) - 1 for puts.gamma-- N'(d) / (v * sqrt(T)). Same for calls and puts.vega-- sqrt(T) * N'(d). Same for calls and puts.theta-- -v * N'(d) / (2 * sqrt(T)). Same for calls and puts.
Usage
Use the Bachelier model for pricing options on underlyings with normal (additive) dynamics, particularly in interest rate markets (e.g., swaptions, caplets when rates are near zero or negative), or when quoting implied normal volatility. It is also used as a benchmark model for spread options.
Code Reference
Source Location
- Repository: RustQuant
- File: crates/RustQuant_models/src/bachelier.rs
- Lines: 1-233
Signature
#[derive(Debug, Clone, Serialize, Deserialize, Copy)]
pub struct Bachelier {
f: f64, // Forward price
r: f64, // Risk-free rate
v: f64, // Normal volatility
}
impl Bachelier {
pub fn new(f: f64, r: f64, v: f64) -> Self;
pub fn price(&self, k: f64, t: f64, option_type: TypeFlag) -> f64;
pub fn atm_price(&self, t: f64) -> f64;
pub fn atm_vol(&self, price: f64, t: f64) -> f64;
pub fn iv(&self, price: f64, k: f64, t: f64, option_type: TypeFlag) -> f64;
pub fn delta(&self, k: f64, t: f64, option_type: TypeFlag) -> f64;
pub fn gamma(&self, k: f64, t: f64, option_type: TypeFlag) -> f64;
pub fn vega(&self, k: f64, t: f64, option_type: TypeFlag) -> f64;
pub fn theta(&self, k: f64, t: f64, option_type: TypeFlag) -> f64;
}
Import
use RustQuant::models::Bachelier;
use RustQuant::instruments::TypeFlag;
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| f | f64 |
Yes | Forward price of the underlying. |
| r | f64 |
Yes | Risk-free interest rate for discounting. |
| v | f64 |
Yes | Normal (absolute) volatility. |
| k | f64 |
Yes (pricing/greeks) | Strike price of the option. |
| t | f64 |
Yes (pricing/greeks) | Time to maturity in years. |
| option_type | TypeFlag |
Yes (pricing/greeks) | Call or Put. |
| price | f64 |
Yes (iv) | Observed option price for implied volatility computation. |
Outputs
| Name | Type | Description |
|---|---|---|
| price | f64 |
European option price under the normal model. |
| iv | f64 |
Implied normal volatility. |
| delta | f64 |
Option delta. |
| gamma | f64 |
Option gamma. |
| vega | f64 |
Option vega. |
| theta | f64 |
Option theta. |
Usage Examples
use RustQuant::models::Bachelier;
use RustQuant::instruments::TypeFlag;
// Bachelier model for a forward at 100 with 5% rate and 20 bps normal vol
let model = Bachelier::new(100.0, 0.05, 20.0);
// Price a 1-year European call at strike 100
let call_price = model.price(100.0, 1.0, TypeFlag::Call);
let put_price = model.price(100.0, 1.0, TypeFlag::Put);
// ATM price shortcut
let atm = model.atm_price(1.0);
// Greeks
let delta = model.delta(100.0, 1.0, TypeFlag::Call);
let gamma = model.gamma(100.0, 1.0, TypeFlag::Call);
let vega = model.vega(100.0, 1.0, TypeFlag::Call);
let theta = model.theta(100.0, 1.0, TypeFlag::Call);
// Implied normal volatility from an observed price
let iv = model.iv(call_price, 100.0, 1.0, TypeFlag::Call);