Commit 18de062
authored
* feat(pricing): add Black-76 model for options on futures and forwards
Implement Black-76 closed-form pricing for European options on futures,
forwards, swaptions, and caps/floors. Core formulas:
- d1 = [ln(F/K) + σ²T/2] / (σ√T)
- d2 = d1 - σ√T
- Call: e^(-rT) * [F*N(d1) - K*N(d2)]
- Put: e^(-rT) * [K*N(-d2) - F*N(-d1)]
Key differences vs Black-Scholes:
- Input is forward price F (not spot S)
- No carry term (F already incorporates all carry)
- Unified discount factor e^(-rT) on both legs
Changes:
- src/pricing/black_76.rs: kernel + trait + 20 unit tests
- src/greeks/utils.rs: calculate_d_values_black_76 helper (b=0 drift)
- src/pricing/mod.rs: module documentation and exports
- src/pricing/unified.rs: PricingEngine::ClosedFormBlack76 variant + dispatch
- examples/examples_pricing/: new workspace crate with runnable demo
- Cargo.toml: workspace members (alphabetical sort)
Tests validate:
- Hull canonical reference (F=K=20, ATM)
- Put-call parity across ATM/ITM/OTM scenarios
- Equivalence to BS-Merton with S=F*e^(-rT), q=0
- Monotonicity in forward price
- Short side sign negation
- Quantity invariance
- Unsupported types (American, Bermuda, exotics)
All tests pass; clippy/fmt/build clean.
* docs(pricing): list Black-76 in lib.rs/pricing module guides
Adds Black-76 to the file inventory in `src/lib.rs::Pricing Models`,
extends the pricing-models mermaid with a `Forward-Priced` subgraph
mapping `black_76 -> {Future, Forward}`, and lists Black-76 in the
`pricing/mod.rs` Model Selection Guidelines and Performance
Considerations sections.
* fix(pricing): add #[non_exhaustive] to PricingEngine enum for semver compatibility
The new ClosedFormBlack76 variant was flagged as a semver-breaking change
because PricingEngine is a public exhaustive enum. Mark it #[non_exhaustive]
to signal that future variants are possible, and add a catch-all _ pattern
to price_option dispatch.
* release(0.17.0): bump major + address copilot review
Bumps the crate version to 0.17.0 because the 0.16.x → main diff
introduces two semver-breaking changes: `PricingEngine` is now
`#[non_exhaustive]` and `PricingEngine::ClosedFormBlack76` shifts the
implicit discriminant of `PricingEngine::MonteCarlo` from 1 to 2
(flagged by `cargo-semver-checks`).
Also addresses the three Copilot review comments on PR #398:
- pricing/mod.rs: reword the Black-76 module description so it lists
"options on" futures / forwards / commodity futures rather than the
underlyings themselves.
- pricing/unified.rs: extend the `price_option` `# Errors` docstring to
cover Black-76 (`MethodError` for zero-vol / non-finite,
`UnsupportedOptionType` for non-European inputs).
- greeks/utils.rs: compute `expiration_date.get_years()?` once in
`calculate_d_values_black_76` and reuse the value for both `d1` and
`d2`.
Also drops the now-unreachable `_` arm in `price_option` (intra-crate
matches see all variants regardless of `#[non_exhaustive]`), which was
failing the `lint` job, and updates the version references in
`src/lib.rs` and `CHANGELOG.md`.
1 parent c7cfd85 commit 18de062
86 files changed
Lines changed: 1334 additions & 20 deletions
File tree
- Draws/Simulation
- examples
- examples_curves/Draws/Curves
- examples_metrics/Draws/Metrics
- examples_pricing
- src/bin
- examples_simulation/Draws/Simulation
- src
- greeks
- pricing
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
10 | 47 | | |
11 | 48 | | |
12 | 49 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
104 | 109 | | |
| 110 | + | |
105 | 111 | | |
106 | 112 | | |
107 | | - | |
| 113 | + | |
108 | 114 | | |
109 | | - | |
110 | 115 | | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | 116 | | |
116 | 117 | | |
117 | 118 | | |
| |||
Large diffs are not rendered by default.
Loading
Loading
Loading
0 commit comments