feat(volatility): add year-on-year inflation optionlet volatility - #852
Merged
Conversation
Add a new `inflation` module under the volatility term structures with year-on-year optionlet volatility surfaces. This introduces support for inflation-linked option pricing volatility. **New volatility structures:** * Added `ConstantYoYOptionletVolatility` for a flat year-on-year optionlet volatility term structure. * Added `YoYOptionletVolatilitySurface` for a full year-on-year optionlet volatility surface. * Wired the new `inflation` module into the volatility module and re-exported the new public types.
This pull request adds a test module for the constant YoY inflation optionlet volatility surface, verifying the date arithmetic and behaviour described in QuantLib's `inflationcapfloor.cpp`. **Test coverage:** * Verifies the base date snaps to the start of the publication period when the index is not interpolated, and stays on the exact lagged date when it is. * Checks that total variance accrues over the lag handed to `time_from_base` rather than the surface's own lag. * Confirms the volatility is flat across dates and strikes and stays live to its underlying quote, firing observers on relink. * Ensures dates before the base date and strikes off the domain are rejected, and that enabling extrapolation lifts the strike bound.
Extend `YoYInflationCouponPricer` with default-erroring `caplet_rate` and `floorlet_rate` methods, so a swaplet-only pricer refuses every optionlet while a `CappedFlooredYoYInflationCoupon` can query them from a pricer that carries an optionlet volatility surface. Add the `yoyinflationoptionletpricer` module and export `YoYInflationOptionletCouponPricer` and `YoYOptionletDistribution`, the vol-dependent pricer that prices the intrinsic case and knows the surface whose base date decides whether a coupon is determined. Update the module docs to reflect that the vol-dependent pricers landed with `#838` rather than being deferred.
Introduce a new `CappedFlooredYoYInflationCoupon` type in the cashflows module and expose it through the module's public API.
This adds cap and floor support to the year-on-year inflation leg builder, completing the deferred `CappedFlooredYoYInflationCoupon` branch. **Builder cap and floor support:** * Added `with_caps`, `with_caps_per_coupon`, `with_floors`, and `with_floors_per_coupon` to `YoYInflationLeg`, storing per-coupon cap and floor rates that broadcast the last entry over remaining coupons. * Split coupon construction into a shared `raw_coupons` helper, exposing plain coupons through `coupons` and wrapped ones through the new `capped_floored_coupons`, with `build` erasing whichever the cap and floor lists select. * Withheld the default swaplet pricer once a cap or floor is set, since a capped coupon needs a pricer carrying an optionlet volatility that the caller installs. * Validated that cap and floor lists do not exceed the schedule periods. **Pricer installation:** * Added the `AttachYoYInflationPricer` trait and `set_yoy_coupon_pricer` free function so a plain or capped/floored leg can be priced the same way without downcasting an erased `Leg`. **Tests:** * Added coverage for a capped leg withholding the default pricer and broadcasting its caps, installing a pricer across a capped leg, and rejecting an oversized cap list.
Added a new test module `capflooredyoyinflationcoupon_oracle` and registered it in the cashflows module under `#[cfg(test)]` to validate the capped/floored year-on-year inflation coupon behavior.
Add oracle tests for the capped/floored YoY inflation coupon pricer, verifying its behavior across every optionlet distribution. * A determined coupon (fixing on or before the surface base date) pays its exact intrinsic optionlet with no volatility read. * A live coupon prices under its own distribution, routing to the matching Black, unit-displaced, or Bachelier formula with the surface implied standard deviation, and each distribution yields a distinct rate so the fixture can tell them apart. * A negative gearing floors a capped coupon, striking the floorlet at the de-spread, de-geared level swapped in from the cap argument rather than the argument itself. close #838
Explain in the constant YoY optionlet vol surface why the C++ `VolatilityType` and `displacement` constructor arguments are omitted rather than accepted and ignored. The coupon pricer names its own distribution, so omitting these prevents a caller from silently quoting a normal volatility and being priced lognormally. They return with the optionlet strippers and cap/floor engines that read them (#851).
Extend the negative-gearing floor test to check that the capped/floored YoY inflation coupon wrapper exposes the underlying's nominal, accrual dates and payment date, and that `amount` accrues the capped rate over them - the path an erased `Leg` reaches, previously untested. Also clarify the inflation volatility module docs on why the trait carries no time-based queries, citing the C++ source lines and noting the unused raw `volatility(Time, Rate)` the port omits.
benbenbang
enabled auto-merge (rebase)
August 11, 2026 07:48
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
close #838