Boutquin.OptionPricing.Examples
1.0.0
dotnet add package Boutquin.OptionPricing.Examples --version 1.0.0
NuGet\Install-Package Boutquin.OptionPricing.Examples -Version 1.0.0
<PackageReference Include="Boutquin.OptionPricing.Examples" Version="1.0.0" />
<PackageVersion Include="Boutquin.OptionPricing.Examples" Version="1.0.0" />
<PackageReference Include="Boutquin.OptionPricing.Examples" />
paket add Boutquin.OptionPricing.Examples --version 1.0.0
#r "nuget: Boutquin.OptionPricing.Examples, 1.0.0"
#:package Boutquin.OptionPricing.Examples@1.0.0
#addin nuget:?package=Boutquin.OptionPricing.Examples&version=1.0.0
#tool nuget:?package=Boutquin.OptionPricing.Examples&version=1.0.0
Boutquin.OptionPricing
Boutquin.OptionPricing is a concept-first, model-oriented C# library that maps the full conceptual arc of Black-Scholes and Beyond: Option Pricing Models into a clean, testable, modular codebase. It is designed as a companion to your reading of the book — every package corresponds to a chapter group, every model carries the assumptions stated in the text, and every example traces the progression from closed-form pricing through tree methods to calibrated implied surfaces.
The library depends on Boutquin.Analytics for all curve infrastructure: discount factors, forward rates, dividend curves, and carry. This keeps the option-pricing layer free from data-fetching and bootstrapping concerns. A flat-curve helper is provided for quick exploration; a bootstrapped curve from the NY Fed or Bank of Canada fixtures is one call away for production-grade discounting.
The design is production-grade in engineering terms — strict code quality, full test coverage, documented XML API surface — while remaining concept-first in scope. This is not a trading system or a brokerage integration. It is a reference implementation: the kind you study alongside a textbook and then use as the starting point for your own pricing work.
What You Will Learn
Working through this codebase alongside Black-Scholes and Beyond gives practical exposure to:
- why risk-neutral pricing works and how the discount curve enters the Black-Scholes formula via
OptionMarketDatarather than a scalar rate, - how binomial trees converge to Black-Scholes as steps increase, and where American exercise breaks that convergence,
- how to invert a model price to recover implied volatility — and why bisection, Newton-Raphson, and secant solvers behave differently near the boundary,
- how a smile surface is constructed from market quotes and what butterfly/calendar arbitrage constraints enforce,
- how implied binomial trees (Rubinstein) and implied volatility trees (Derman-Kani) fit a calibrated surface and price path-dependent instruments like barriers.
Book-To-Code Map
| Book chapter group | Package |
|---|---|
| Instruments, arbitrage, parity | Domain, Analytics |
| Probability and distributions | Numerics |
| Geometric Brownian motion, Black-Scholes derivation | Analytics |
| Hedging interpretation | Analytics |
| Binomial trees | Trees |
| American exercise and tree pricing | Trees |
| Implied volatility and smile | Calibration |
| Implied volatility trees (Derman-Kani) | Calibration |
| Implied binomial trees (Rubinstein) | Calibration |
| Barrier options in the presence of the smile | Exotics |
Packages
Packages are organized in dependency order, from foundational contracts through advanced models.
Contracts
The foundational contracts all other packages depend on. Downstream code that only consumes prices and Greeks will typically reference only this group.
| Package | Description |
|---|---|
Boutquin.OptionPricing.Abstractions |
Generic pricing, Greek, calibration, and diagnostic interfaces |
Boutquin.OptionPricing.Domain |
Option contracts (EuropeanOption, AmericanOption, BarrierOption), OptionMarketData, result types (PriceResult, GreekSet) |
Vanilla Pricing Models
Closed-form and tree-based pricing for European and American options.
| Package | Description |
|---|---|
Boutquin.OptionPricing.Analytics |
BlackScholesPricer, BlackScholesGreeks, BlackScholesDividendPricer, DeltaHedgeSimulator, put-call parity and risk-neutral valuation |
Boutquin.OptionPricing.Trees |
CRR, Jarrow-Rudd, and flexible binomial tree builders; EuropeanTreePricer, AmericanTreePricer; Arrow-Debreu state prices |
Smile, Calibration, And Exotics
Surface fitting, implied tree calibration, and barrier pricing.
| Package | Description |
|---|---|
Boutquin.OptionPricing.Calibration |
ImpliedVolatilitySolver, smile slice and surface builders, QuoteArbitrageValidator, Rubinstein ImpliedBinomialTreeCalibrator, Derman-Kani ImpliedVolatilityTreeCalibrator, calibration diagnostics |
Boutquin.OptionPricing.Exotics |
BarrierTreePricer (flat vol), SmileAwareBarrierPricer (surface), barrier parity, Broadie-Glasserman-Kou monitoring adjustments |
Examples And Delivery
| Package | Description |
|---|---|
Boutquin.OptionPricing.BlackScholesAndBeyond |
Book-aligned executable tracing all eleven chapter groups in Black-Scholes and Beyond (Chriss). CLI: --chapter <n> runs a single chapter; default runs all. |
Boutquin.OptionPricing.Examples |
Infrastructure-focused executable for six examples covering bootstrapped curves, term-structure Greeks, multi-curve borrow cost, diagnostic gating, and live market data pricing. CLI: --example <id> runs a single example. |
Boutquin.OptionPricing.Examples.Shared |
Shared class library consumed by both executables: MarketHelpers (flat and bootstrapped market construction) and SimulationHelpers (normal sampling for hedging simulation). |
Boutquin.OptionPricing.Benchmarks |
BenchmarkDotNet performance suite |
Model Assumptions
Black-Scholes
- lognormal underlying with constant volatility
- risk-free rate, dividend yield, and borrow cost derived from
OptionMarketDatacurves - cost-of-carry includes borrow rate: effective yield = q + b, so the forward is F = S × exp(−(q+b)T) / exp(−rT)
- European exercise only
- zero-time-to-expiry returns intrinsic value with a
Successstatus
CRR binomial tree
- recombining tree with flat volatility and flat discount rate
- optional flat continuous dividend yield
- American exercise evaluated at each node via early-exercise comparison
- converges to Black-Scholes as step count increases
Implied binomial tree (Rubinstein)
- fits to a market volatility surface via Arrow-Debreu state prices
- recombining tree with state-dependent risk-neutral probabilities
- single flat discount curve for time value
Implied volatility tree (Derman-Kani)
- fits to a market volatility surface via implied local volatilities
- forward induction to build tree; backward induction to price
- single flat discount curve for time value
Validation Invariants
Tests enforce the following relationships across model families:
- put-call parity holds to within tolerance for all European pricers
- American put value is always ≥ European put value at the same inputs
- CRR tree price converges toward Black-Scholes as step count increases
- implied volatility round-trip: invert model price, re-price, recover original price to tolerance
- butterfly and calendar arbitrage are absent from valid smile surface inputs
Quick Start
Installation
dotnet add package Boutquin.OptionPricing.Domain
dotnet add package Boutquin.OptionPricing.Analytics
dotnet add package Boutquin.OptionPricing.Trees
Price a European Call (flat-curve market)
OptionMarketData requires a discount curve. For exploration, wrap a constant rate in FlatDiscountCurve from Boutquin.Analytics.Curves:
using Boutquin.Analytics.Abstractions.Identifiers;
using Boutquin.Analytics.Curves.Discounting;
using Boutquin.OptionPricing.Analytics.BlackScholes;
using Boutquin.OptionPricing.Domain.Contracts;
using Boutquin.OptionPricing.Domain.Enums;
using Boutquin.OptionPricing.Domain.Market;
DateOnly valuationDate = DateOnly.FromDateTime(DateTime.Today);
var discountCurve = new FlatDiscountCurve(
new CurveName("USD-OIS"), valuationDate, CurrencyCode.USD, riskFreeRate: 0.03);
var dividendCurve = new FlatDiscountCurve(
new CurveName("DIVIDEND"), valuationDate, CurrencyCode.USD, riskFreeRate: 0.01);
var market = new OptionMarketData(valuationDate, spot: 100m, flatVolatility: 0.20, discountCurve, dividendCurve);
var option = new EuropeanOption(CallPut.Call, strike: 100m, valuationDate.AddMonths(6));
var result = new BlackScholesPricer().Price(option, market);
Console.WriteLine($"Call price: {result.Price:F4}");
Price with a Bootstrapped Curve (Fixture Data)
For deterministic testing, use FixtureData.CreatePipeline() — pre-built market data for USD, CAD, GBP, EUR with no network calls:
using Boutquin.Analytics.Abstractions.Identifiers;
using Boutquin.Analytics.Recipes;
using Boutquin.Analytics.Recipes.Testing;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddAnalytics(); // registers CurveBuilder, calibrator, conventions
services.AddSingleton<IDataPipeline>(FixtureData.CreatePipeline()); // deterministic fixture data
services.AddLogging();
var sp = services.BuildServiceProvider();
var builder = sp.GetRequiredService<CurveBuilder>();
var recipe = StandardCurveRecipes.UsdSofrDiscount();
var snapshot = await builder.BuildAsync(recipe, new DateOnly(2026, 4, 9));
// Verify bootstrap quality before pricing
double maxError = snapshot.Diagnostics.Repricing.Max(r => r.AbsoluteError);
if (maxError > 1e-6)
throw new InvalidOperationException($"Curve failed quality gate: {maxError:E2}");
var market = OptionMarketData.FromCurveGroup(
snapshot.CurveGroup, new CurrencyCode("USD"), spot: 100m, flatVolatility: 0.20);
Price with Real Market Data
For live data from public sources, replace FixtureData.CreatePipeline() with the real Boutquin.MarketData pipeline. Source adapters from Boutquin.MarketData.Adapter fetch EOD data from free public APIs:
| Source | Data | Adapter Package |
|---|---|---|
| NY Fed | SOFR fixings | MarketData.Adapter.NewYorkFed |
| US Treasury | Par yields (2Y-30Y) | MarketData.Adapter.UsTreasury |
| Bank of Canada | CORRA fixings, zero curves | MarketData.Adapter.BankOfCanada |
| Bank of England | SONIA fixings | MarketData.Adapter.BankOfEngland |
| ECB | ESTR fixings | MarketData.Adapter.Ecb |
| CME | SOFR futures settlements | MarketData.Adapter.Cme |
using Boutquin.Analytics.Abstractions.Curves;
using Boutquin.Analytics.Abstractions.Identifiers;
using Boutquin.Analytics.Recipes;
using Boutquin.MarketData.Abstractions.Calendars;
using Boutquin.MarketData.Adapter.NewYorkFed;
using Boutquin.MarketData.Adapter.UsTreasury;
using Boutquin.MarketData.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
var services = new ServiceCollection();
services.AddAnalytics(); // CurveBuilder, calibrator, reference data
services.AddMarketDataKernel(); // IDataPipeline with transport, L1/L2 caching, normalization
services.AddMarketDataNewYorkFed(); // SOFR overnight fixings from NY Fed Markets API
services.AddMarketDataUsTreasury(); // Treasury par yields (2Y-30Y)
services.AddLogging(b => b.AddConsole().SetMinimumLevel(LogLevel.Warning));
var sp = services.BuildServiceProvider();
var builder = sp.GetRequiredService<CurveBuilder>();
var calendar = sp.GetRequiredService<IBusinessCalendar>();
// EOD data is published after market close — use previous business day
DateOnly valuationDate = calendar.Advance(DateOnly.FromDateTime(DateTime.Today), -1);
var snapshot = await builder.BuildAsync(StandardCurveRecipes.UsdSofrDiscount(), valuationDate);
// Verify bootstrap quality before pricing
double maxError = snapshot.Diagnostics.Repricing.Max(r => r.AbsoluteError);
if (maxError > 1e-4)
throw new InvalidOperationException($"Curve failed quality gate: {maxError:E2}");
var market = OptionMarketData.FromCurveGroup(
snapshot.CurveGroup, new CurrencyCode("USD"), 100m, 0.20d, new BenchmarkName("SOFR"));
// Now price with the latest available real discount curve
// Provenance shows data source and actual business date
foreach (var prov in snapshot.Provenance.DistinctBy(p => p.Dataset))
Console.WriteLine($"{prov.Dataset}: {prov.RetrievalMode} via {prov.Provider} [{prov.Freshness} {prov.DataDate}]");
// DATE_ROLLBACK warnings surface when data date != valuation date
foreach (var issue in snapshot.DataIssues.Where(i => i.Code == "DATE_ROLLBACK"))
Console.WriteLine($"[{issue.Severity}] {issue.Message}");
This is Example 15 in the Examples project. The data flow is: StandardCurveRecipes defines which data to fetch → CurveBuilder calls IDataPipeline → adapters fetch from NY Fed and Treasury APIs → rates are extracted and passed to the bootstrap calibrator → calibrated curves are returned in a CurveSnapshot with full provenance and data-quality issues.
Each DataProvenance record indicates whether data was retrieved via "api" (live fetch), "snapshot" (L2 disk cache), or "cache" (L1 memory), along with the actual DataDate of the underlying data. When the data date differs from the requested valuation date (e.g., requesting Monday's data before EOD publication), adapter and node layers emit DATE_ROLLBACK warnings. Issues are persisted through the L2 cache so they are visible on cached replays. Consecutive runs hit the L2 disk cache and skip HTTP calls.
Architecture
Boutquin.OptionPricing is organized in four dependency tiers:
- Contracts —
Abstractions,Domain: stable contracts, option types, and result objects. The only tier downstream pricing consumers need to reference directly. Numerical primitives (root-finding, interpolation, distributions) are provided byBoutquin.Numerics. - Vanilla Pricing Models —
Analytics,Trees: closed-form Black-Scholes, full Greeks, put-call parity, CRR/JR/flexible binomial trees, American exercise. - Smile, Calibration, And Exotics —
Calibration,Exotics: implied volatility inversion, smile surface construction, Rubinstein and Derman-Kani implied tree calibration, barrier pricing with flat-vol and smile-aware pricers. - Examples And Delivery —
BlackScholesAndBeyond,Examples,Examples.Shared,Benchmarks: book-aligned chapter walkthroughs, infrastructure-focused examples, shared helpers, and performance benchmarks.
Dependencies flow in one direction: Exotics and Calibration depend on Trees and Analytics; all depend on Contracts and Numerics. Boutquin.OptionPricing depends on Boutquin.Analytics for curve abstractions — the dependency never flows in reverse.
See docs/curve-layer.md for the Analytics dependency design and docs/repository-map.md for per-package navigation guidance.
Directory Structure
Boutquin.OptionPricing/
├── src/ # Source projects (9)
│ ├── Boutquin.OptionPricing.Abstractions/ # Core interfaces and payoff contracts
│ ├── Boutquin.OptionPricing.Domain/ # Option contracts, market data, result types
│ ├── Boutquin.OptionPricing.Analytics/ # Black-Scholes pricer, Greeks, hedging
│ ├── Boutquin.OptionPricing.Trees/ # Binomial tree pricing (CRR, JR, flexible)
│ ├── Boutquin.OptionPricing.Calibration/ # Implied vol, smile surface, implied trees
│ ├── Boutquin.OptionPricing.Exotics/ # Barrier and exotic options
│ ├── Boutquin.OptionPricing.BlackScholesAndBeyond/ # Book-aligned chapter examples
│ ├── Boutquin.OptionPricing.Examples/ # Infrastructure-focused examples
│ └── Boutquin.OptionPricing.Examples.Shared/ # Shared market construction helpers
├── tests/ # Test projects (10)
│ ├── Boutquin.OptionPricing.Domain.Tests/ # Domain contracts and market data
│ ├── Boutquin.OptionPricing.Analytics.Tests/ # Black-Scholes and Greeks
│ ├── Boutquin.OptionPricing.Trees.Tests/ # Binomial tree pricing
│ ├── Boutquin.OptionPricing.Calibration.Tests/ # Implied vol and calibration
│ ├── Boutquin.OptionPricing.Exotics.Tests/ # Barrier option tests
│ ├── Boutquin.OptionPricing.PropertyTests/ # Property-based tests (put-call parity, convergence)
│ ├── Boutquin.OptionPricing.IntegrationTests/ # End-to-end integration
│ ├── Boutquin.OptionPricing.Tests.Verification/ # Cross-language reference vectors
│ └── Boutquin.OptionPricing.ArchitectureTests/ # Dependency enforcement
├── benchmarks/
│ └── Boutquin.OptionPricing.Benchmarks/ # BenchmarkDotNet suite
├── docs/ # Architecture and usage documentation
└── .github/ # CI/CD workflows
Documentation
| Document | Description |
|---|---|
| docs/repository-map.md | Per-package descriptions with external dependency and test structure |
| docs/curve-layer.md | Market curve integration design: why OptionMarketData uses curve objects |
Contributing
Contributions are welcome! Please read the contributing guidelines first.
Reporting Bugs
If you find a bug, please report it by opening an issue on the Issues page with:
- A clear and descriptive title
- Steps to reproduce the issue
- Expected and actual behavior
- Screenshots or code snippets, if applicable
Contributing Code
- Fork the repository and clone locally
- Create a feature branch:
git checkout -b feature-name - Make your changes following the style guides
- Commit with clear messages:
git commit -m "Add feature X" - Push and open a pull request
Disclaimer
Boutquin.OptionPricing is open-source software provided under the Apache 2.0 License. It is a general-purpose library intended for educational and research purposes.
This software does not constitute financial advice. The option pricing, volatility, and risk analysis tools are provided as-is for research and development. Before using any financial calculations in production, consult with qualified professionals who understand your specific requirements and regulatory obligations.
License
This project is licensed under the Apache 2.0 License -- see the LICENSE file for details.
Contact
For inquiries, please open an issue or reach out via GitHub Discussions.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Boutquin.MarketData.Adapter.NewYorkFed (>= 1.0.2)
- Boutquin.MarketData.Adapter.UsTreasury (>= 1.0.2)
- Boutquin.MarketData.DependencyInjection (>= 1.0.1)
- Boutquin.OptionPricing.Analytics (>= 1.0.0)
- Boutquin.OptionPricing.Examples.Shared (>= 1.0.0)
- Microsoft.Extensions.DependencyInjection (>= 10.0.6)
- Microsoft.Extensions.Logging (>= 10.0.6)
- Microsoft.Extensions.Logging.Console (>= 10.0.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 103 | 4/17/2026 |