feat(itofin-py): expose moving cap/floor surfaces and extrapolation - #631
Merged
Conversation
This adds the floating-reference-date constructors and extrapolation controls needed by the optionlet stripping pipeline. Partially discharges #627: the `capfloortermvol.rs` / `CapFloorTermVolSurface` site listed there is done here. It was not optional polish - without it the #623 pass is unbuildable, since the adapter reads its settlement days back off the term-vol surface. What remains under #627 is the two `ConstantSwaptionVolatility` and two `ConstantOptionletVolatility` moving forms. **Moving CapFloorTermVolSurface constructors:** * Added `moving` and `moving_with_quotes` static methods to `CapFloorTermVolSurface`, whose reference date floats `settlement_days` off the evaluation date, over fixed volatilities or the caller's quotes. * These carry the settlement days `StrippedOptionletAdapter` reads back off the stripper; a fixed-reference surface has none and fails the adapter with "settlement days not provided for this instance" (`strippedoptionletadapter.rs:87` -> `optionletstripper.rs:241` -> `termstructures/mod.rs:227`). * Updated the type stubs and module docs to reflect that all four core constructors are now exposed; the stale "not exposed" claims are gone rather than re-pointed. **Optionlet volatility extrapolation:** * Added `allows_extrapolation`, `enable_extrapolation`, and `disable_extrapolation` to the optionlet volatility surface, since a stripped surface ends at its last optionlet fixing and a cap whose own last caplet fixes there queries the boundary. **Docs:** * The deferred moving constant optionlet constructors keep their deferral and now cite #627.
This pull request adds Python bindings for the cap/floor optionlet stripping stack, closing the volatility loop from market cap term volatilities to a caplet surface. **New optionlet stripping facades:** * Added `PyOptionletStripper1` that bootstraps caplet volatilities out of a `CapFloorTermVolSurface` and an `Euribor` index, exposing `switch_strike` and `atm_optionlet_rates` queries. Stripping is lazy and cached, and the `Normal` volatility type fails at the strip. * Added `PyStrippedOptionletAdapter`, extending `PyOptionletVolatilityStructure`, which serves the stripper's caplet grid as an interpolated volatility surface so a `BlackCapFloorEngine` reprices the quoted caps. * Registered both classes in the `termstructures` module and dropped the now-used `dead_code` allow on `PyCapFloorTermVolSurface::inner`. **Type stubs:** * Added `OptionletStripper1` and `StrippedOptionletAdapter` definitions to `termstructures.pyi`, documenting the moving-surface requirement, discount and frequency fallbacks, and the extrapolation caveat.
Add a new test file `crates/itofin-py/tests/test_optionlet_stripping.py` to validate optionlet stripping behavior. Closes #623
Extend the cap/floor term vol tests to exercise the two moving constructors alongside the pinned ones, so a transposed grid cannot hide behind the flat fixture the stripping oracle relies on. **Cap/floor term vol surface**: * Add `_moving_matrix_surface` and `_moving_quote_surface` fixtures at zero settlement days, pinning their reference date to the evaluation date via a shared `SETTINGS` on `REFERENCE`. * Parametrize node recovery over all four constructors and the quote bump test over both quote forms. **Optionlet stripping**: * Thread an `optionlet_frequency` argument through `_stripper` and add a test proving a 1Y override on a 6M index halves the caplet count, confirming the argument reaches the core rather than being dropped by the facade. * Strengthen the anti-tautology guard assertion message to explain why a non-zero worst round-trip error proves the stripped vols differ from the flat input. close #623
benbenbang
enabled auto-merge (rebase)
July 27, 2026 05:27
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 #623