Skip to content

Commit

Permalink
Update precision check for tests and README
Browse files Browse the repository at this point in the history
The precision check for the tests has been updated to use a multiple of `f64::EPSILON`.
The README also received updates including information about performance and precision.
  • Loading branch information
nakashima-hikaru committed Jan 21, 2024
1 parent c08a089 commit db619a3
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 18 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
[![Actions status](https://github.com/nakashima-hikaru/implied-vol/actions/workflows/ci.yaml/badge.svg)](https://github.com/nakashima-hikaru/implied-vol/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

More information about this crate can be found in the [crate documentation](https://docs.rs/implied-vol/0.2/implied_vol/).
More information about this crate can be found in
the [crate documentation](https://docs.rs/implied-vol/0.2/implied_vol/).

## About

Expand Down Expand Up @@ -32,7 +33,17 @@ analysis using Clippy lint. This library stands out by offering:
- Exceptional testability and maintainability due to its implementation in Rust.
- Unit tests aiding error checking.

And most importantly, `implied-vol` follows the original C++ implementations closely, maintaining the same output precision.
### Performance

Peter Jäckel, the author of the original paper, asserts that "the calculation of a single implied volatility is now down
to just under 270 nanoseconds" based on his machine's benchmark measurements. By examining the benchmark measurements
performed on this crate's [Github Actions](https://github.com/nakashima-hikaru/implied-vol/actions), it becomes clear
that comparable performance is being achieved.

### Precision

On our machine, the absolute error for both implied Black volatility and implied normal
volatility calculations is confirmed to be less than twice the machine epsilon in random tests.

Community contributions are always welcome!

Expand Down
10 changes: 5 additions & 5 deletions src/bachelier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ mod tests {
let q = true;
let sigma = implied_normal_volatility(price, f, k, t, q);
let reprice = bachelier(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}

Expand All @@ -169,7 +169,7 @@ mod tests {
let q = true;
let sigma = implied_normal_volatility(price, f, k, t, q);
let reprice = bachelier(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}

Expand All @@ -187,7 +187,7 @@ mod tests {
let q = true;
let sigma = implied_normal_volatility(price, f, k, t, q);
let reprice = bachelier(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}

Expand All @@ -206,7 +206,7 @@ mod tests {
let q = false;
let sigma = implied_normal_volatility(price, f, k, t, q);
let reprice = bachelier(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}

Expand All @@ -224,7 +224,7 @@ mod tests {
let q = false;
let sigma = implied_normal_volatility(price, f, k, t, q);
let reprice = bachelier(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}
}
14 changes: 7 additions & 7 deletions src/lets_be_rational.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ mod tests {
let q = true;
let sigma = implied_black_volatility(price, f, k, t, q);
let reprice = black(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-14);
assert!((price - reprice).abs() < 2.0 * f64::EPSILON * 100.0);
}
}

Expand All @@ -414,7 +414,7 @@ mod tests {
let q = false;
let sigma = implied_black_volatility(price, f, k, t, q);
let reprice = black(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-14);
assert!((price - reprice).abs() < 2.0 * f64::EPSILON * 100.0);
}
}

Expand All @@ -432,7 +432,7 @@ mod tests {
let q = true;
let sigma = implied_black_volatility(price, f, k, t, q);
let reprice = black(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}

Expand All @@ -450,7 +450,7 @@ mod tests {
let q = true;
let sigma = implied_black_volatility(price, f, k, t, q);
let reprice = black(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}

Expand All @@ -468,7 +468,7 @@ mod tests {
let q = true;
let sigma = implied_black_volatility(price, f, k, t, q);
let reprice = black(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}

Expand All @@ -487,7 +487,7 @@ mod tests {
let q = false;
let sigma = implied_black_volatility(price, f, k, t, q);
let reprice = black(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}

Expand All @@ -505,7 +505,7 @@ mod tests {
let q = false;
let sigma = implied_black_volatility(price, f, k, t, q);
let reprice = black(f, k, sigma, t, q);
assert!((price - reprice).abs() < 5e-16);
assert!((price - reprice).abs() <= 2.0 * f64::EPSILON);
}
}
}
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@
//! assert_eq!(black_vol, 0.07011701801482094);
//!
//! let price = calculate_european_option_price_by_black_scholes(100.0, 90.0, 0.07011701801482094, 30.0, true);
//! assert!((price - 20.0).abs() < 5e-16 * 20.0);
//! assert!((price - 20.0).abs()<= 2.0 * f64::EPSILON * 20.0);
//!
//! let normal_vol = implied_normal_volatility(20.0, 100.0, 90.0, 30.0, true);
//! assert_eq!(normal_vol, 6.614292466299764);
//!
//! let price = calculate_european_option_price_by_bachelier(100.0, 90.0, 6.614292466299764, 30.0, true);
//! assert!((price - 20.0).abs() < 5e-16 * 20.0);
//! assert!((price - 20.0).abs()<= 2.0 * f64::EPSILON * 20.0);
//! ```
mod erf_cody;
mod normal_distribution;
Expand Down Expand Up @@ -93,7 +93,7 @@ pub fn implied_black_volatility(option_price: f64, forward: f64, strike: f64, ex
/// ```
/// use implied_vol::calculate_european_option_price_by_black_scholes;
/// let price = calculate_european_option_price_by_black_scholes(100.0, 90.0, 0.07011701801482094, 30.0, true);
/// assert!((price - 20.0).abs() < 5e-16 * 20.0);
/// assert!((price - 20.0).abs()<= 2.0 * f64::EPSILON * 20.0);
/// ```
#[inline]
pub fn calculate_european_option_price_by_black_scholes(forward: f64, strike: f64, volatility: f64, expiry: f64, is_call: bool) -> f64 {
Expand Down Expand Up @@ -144,7 +144,7 @@ pub fn implied_normal_volatility(option_price: f64, forward: f64, strike: f64, e
/// ```
/// use implied_vol::calculate_european_option_price_by_bachelier;
/// let price = calculate_european_option_price_by_bachelier(100.0, 90.0, 6.614292466299764, 30.0, true);
/// assert!((price - 20.0).abs() < 5e-16 * 20.0);
/// assert!((price - 20.0).abs()<= 2.0 * f64::EPSILON * 20.0);
/// ```
#[inline]
pub fn calculate_european_option_price_by_bachelier(forward: f64, strike: f64, volatility: f64, expiry: f64, is_call: bool) -> f64 {
Expand Down

0 comments on commit db619a3

Please sign in to comment.