Skip to content

feat(volatility): add year-on-year inflation optionlet volatility - #852

Merged
benbenbang merged 9 commits into
mainfrom
fable/838
Aug 11, 2026
Merged

feat(volatility): add year-on-year inflation optionlet volatility#852
benbenbang merged 9 commits into
mainfrom
fable/838

Conversation

@benbenbang

@benbenbang benbenbang commented Aug 11, 2026

Copy link
Copy Markdown
Owner
  • feat(volatility): add year-on-year inflation optionlet volatility
  • test(crates): add tests for constant YoY optionlet volatility
  • feat(cashflows): add caplet and floorlet rates to YoY pricer trait
  • feat(cashflows): add capped floored YoY inflation coupon
  • feat(cashflows): add caps and floors to YoY inflation leg
  • test(cashflows): add oracle tests for capfloored yoy inflation coupon
  • test(crates): cover capfloored yoy inflation coupon oracle pricing
  • docs(crates): document omitted VolatilityType and displacement params
  • test(cashflows): assert wrapper delegates face to underlying coupon

close #838

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
benbenbang enabled auto-merge (rebase) August 11, 2026 07:48
@github-actions github-actions Bot added the enhancement New feature or request label Aug 11, 2026
@benbenbang benbenbang changed the title fable/838 feat(volatility): add year-on-year inflation optionlet volatility Aug 11, 2026
@benbenbang
benbenbang merged commit 54485ba into main Aug 11, 2026
3 of 6 checks passed
@benbenbang
benbenbang deleted the fable/838 branch August 11, 2026 08:01
@benbenbang
benbenbang restored the fable/838 branch August 11, 2026 08:42
@benbenbang
benbenbang deleted the fable/838 branch August 11, 2026 08:44
@benbenbang
benbenbang restored the fable/838 branch August 11, 2026 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Inflation][YoY] Cap/floor YoY coupon: CappedFlooredYoYInflationCoupon + Black/Bachelier optionlet pricers

1 participant