Interest Rate & FX Derivative Pricing — Multi-Curve / Hull-White / Black-Bachelier / SABR Family Price interest rate and FX derivatives (IRS, swaptions, caps/floors, FX forwards, cross-currency swaps, FRAs, inflation swaps) for ALM and hedge program valuation.
Family-level model covering interest rate derivative pricing under a multi-curve framework (separate discount and projection curves). Optionality is priced by SABR-fed Black-76 (lognormal) / Bachelier (normal) market models; SABR (Hagan) supplies the smile-consistent implied vol that feeds the swaption/rate-option pricers. Inflation swaps use real vs nominal curve decomposition. FX derivatives use covered interest rate parity and cross-currency basis. Implementations: 7 FinView L1 + 4 Gold Copy L1 challengers. (Name corrected per RAT-132-v1.0.0 COND-001, 2026-06-06: at that time no Hull-White short-rate engine was implemented. RAT-132-v1.0.1 build (INV-006, Decision 053 1L #2434, 2026-06-08): a real Hull-White 1-factor short-rate engine `finview.L1.hull_white_1f` was built — no-arbitrage term-structure model calibrated to the canonical curve by construction (exact A/B affine refit), with analytic ZCB-option / Jamshidian-swaption pricing and a HW-vs-Bachelier challenger lane — so "Hull-White" is restored to the family name. The engine's a/sigma vol params are exogenous/uncalibrated; its OPTION outputs are non-production until calibration lands, the curve/bond analytics are production. See production_scope.)
Inputs, processing, outputs
- data sources
- DS-001 · DS-002 · DS-003 · DS-005 · DS-013 · DS-031 · DS-058
- assumptions
- A-050, A-051, A-052, A-053, A-054, A-284, A-285
- engines
-
finview.L1.irs_pricer
finview.L1.hull_white_1f
finview.L1.swaption_pricer
finview.L1.rate_option_pricer
finview.L1.inflation_swap_pricer
finview.L1.fx_forward_pricer
finview.L1.xccy_swap_pricer
goldcopy.L1.swap_pricer
goldcopy.L1.swaption_pricer
goldcopy.L1.fra_pricer
goldcopy.L1.fx_swap_pricer
- contracts
- ir_fx_derivative_pricing_v1
- upstream
- M-136 · M-137
- dimensions
- D2 · D4
Production Scope (RAT-132-v1.0.0 COND-002 — read first)
Not all members are production-ready. The optionality and cross-currency members rest on uncalibrated placeholder inputs (A-054 FX correlation is default-zero; DS-058 swaption-vol / FX-basis source is
planned, with the strike-grid swaption IV history a structural paid-only gap — CME DataMine barred by DR-007). Per Decision 053 §4 these inputs are not fabricated; instead the affected members are scoped non-production until calibration lands.
| Member | Status | Why |
|---|---|---|
finview.L1.irs_pricer (IRS) |
production | Multi-curve; no FX-corr / vol-surface dependence |
finview.L1.inflation_swap_pricer |
production | Real/nominal curve decomposition |
finview.L1.fx_forward_pricer (FX fwd) |
production | Covered-interest parity point estimate (no A-054 dependence) |
finview.L0.curve_builder (curve spine) |
production | Bootstrap / multi-curve construction |
finview.L1.hull_white_1f (HW 1F bond/curve analytics) |
production | Calibrated to the canonical curve by construction (exact A/B affine refit); independent of a,σ |
finview.L1.hull_white_1f (HW 1F option outputs) |
non-production (under_development) | a (A-284) / σ (A-285) exogenous & uncalibrated; DS-058 strike-grid IV is the DR-007 paid-only gap |
finview.L1.swaption_pricer |
non-production (under_development) | Uncalibrated vol surface (DS-058 planned) |
finview.L1.rate_option_pricer (caps/floors) |
non-production (under_development) | Same uncalibrated vol surface (DS-058 planned) |
finview.L1.xccy_swap_pricer (xccy) |
non-production (under_development) | Depends on A-054 FX correlation, currently default-zero |
The non-production members re-promote via 2L re-review once A-054 is calibrated
and/or DS-058 is sourced (tracked under PL-07 / WS3). The mirror of this table
lives in model_registry.yaml::M-132.production_scope. The swaption snapshot below
is retained as an illustrative (non-production) example, clearly labelled.
Methodology
M-132 is the interest-rate and FX derivative pricing family (Tier 2). It
prices linear rate products, cross-currency products, FX forwards, and the
optionality layered on top of them. The family is FinView-resident: every
engine lives under finview.L0/finview.L1 in [redacted],
and there is no InsModel-side implementation — the InsModel virtual-env merely
re-runs the same FinView source (confirmed reproducible below).
Multi-curve discounting (the foundation)
All members share one discounting spine. Curves are bootstrapped from par
instruments by finview.L0.curve_builder
(finlib/curve_builder.py::bootstrap_sofr_curve and build_sofr_curve):
- Maturities ≤ 1Y are stripped as simple money-market instruments
(
df = 1 / (1 + cT)); maturities > 1Y are stripped by sequential semi-annual coupon bootstrapping, treating each input as a par rate. - Zero rates are continuously compounded (
z = -ln(df)/T); inter-tenor forward rates are computed from adjacent discount-factor ratios. - Interpolation is log-linear on discount factors by default, with an
optional PCHIP (monotone cubic Hermite) mode that produces smooth,
non-oscillating forwards (
_interpolate_df,interpolate_curve).
The multi-curve framework proper is the CurveSet dataclass
(finview.L0.curve_set): it holds separate Treasury, OIS/SOFR discount,
and SOFR projection curves plus rating-keyed credit-spread curves, with
graceful fallback to the Treasury curve when a discount or projection curve
is absent (has_multi_curve, get_discount_dfs, get_projection_fwds).
This is the OIS-discounting / forward-projection separation that post-LIBOR
rate pricing requires: the float leg is projected off the projection curve
while cashflows are discounted off the OIS curve.
Family members (engines)
| Engine | File | Product | Key outputs |
|---|---|---|---|
finview.L1.irs_pricer |
derivatives/irs_pricer.py |
Vanilla fixed-vs-float IRS | fair_value, fixed/float leg PV, dv01, key_rate_dv01 |
finview.L1.hull_white_1f |
derivatives/hull_white_1f.py |
Hull-White 1F short-rate term-structure | instantaneous_forward, zero_bond_price, caplet/floorlet, swaption (Jamshidian), theta_implied |
finview.L1.swaption_pricer |
derivatives/swaption_pricer.py |
European swaption | premium, forward_swap_rate, annuity, delta, vega |
finview.L1.rate_option_pricer |
derivatives/rate_option_pricer.py |
Caps/floors/rate options | premium, delta, gamma, vega, theta |
finview.L1.inflation_swap_pricer |
derivatives/inflation_swap_pricer.py |
Zero-coupon/year-on-year inflation swap | fair_value, breakeven_rate, real/nominal dv01 |
finview.L1.fx_forward_pricer |
derivatives/fx_forward_pricer.py |
FX forward (covered-interest parity) | fair_value, fair_forward, dv01_domestic/foreign |
finview.L1.xccy_swap_pricer |
derivatives/xccy_swap_pricer.py |
Cross-currency basis swap | npv, domestic/foreign leg PV, fx_delta, dv01 |
finview.L0.curve_builder / curve_set |
curve_builder.py |
Multi-curve construction | discount/zero/forward arrays, CurveSet |
finview.L?.vol_surface (SABR/SVI) |
vol_surface.py |
Vol surface for optionality | sabr_implied_vol, calibrate_sabr, SABRSurface |
Gold-copy challengers exist for the derivative engines
(finlib/gold_test_derivatives.py, finlib/gold_test_derivatives frozen
reference values, e.g. CME_ERIS_10Y) and provide an independent cross-check
lane for the IRS/futures math.
Representative pricer in detail — vanilla IRS (IRSPricer)
The cleanest-running, most load-bearing member is the vanilla interest-rate
swap, so it is the snapshot exemplar. IRSPricer.compute_fair_value:
- Builds the semi-annual payment grid to maturity (
_payment_times). - Discounts each payment time off the input curve, re-deriving zero rates
from the discount factors and re-interpolating (
_discount_at). - Fixed leg PV =
N · c · Δt · Σ df(tᵢ). - Float leg PV =
N · Δt · Σ fwd(tᵢ) · df(tᵢ)when a projection forward curve is supplied (the multi-curve path); otherwise it collapses to the single-curve par identityN · (1 − df_last). - DV01 is computed by full reprice under a parallel +1bp bump of zero
and forward rates (
_compute_dv01) — a genuine bump-and-reprice, not a closed-form approximation. - Key-rate DV01 bumps each of the {1,2,5,10,20,30}Y buckets with a
triangular weighting kernel (
_compute_key_rate_dv01,_triangle_weight) and reprices, giving the bucketed rate exposure.
The par swap rate and the annuity are emitted directly by
compute_fair_value. The engine builds the annuity as Δt · Σ df(tᵢ) and the
par rate as float_leg_pv / (N · annuity) — the rate that zeroes the swap — and
returns both, exposing par_rate, its consumer-facing alias par_swap_rate,
and annuity in the result dict (irs_pricer.py lines 18, 86–95, sha
22d4662, FinView #92, 2026-06-04). The snapshot reads these straight from
the engine output rather than re-deriving them; the contract's declared
outputs and the returned dict now agree.
Hull-White / SABR for optionality
Optionality is priced two ways in-repo:
SwaptionPricercomputes the forward par swap rate and the annuity off the curve, then applies either Black-76 (lognormal) or Bachelier (normal) to the forward, returning premium, delta and vega. This is the standard market-model swaption, reusing the swap annuity rather than re-deriving swap math.- SABR (Hagan's approximation) lives in
vol_surface.py(sabr_implied_vol(F, K, T, alpha, beta, rho, nu),calibrate_sabr,SABRSurface). It produces the smile-consistent implied vol at a given strike that would feed the Black/Bachelier swaption — i.e. SABR supplies the vol surface, the swaption pricer consumes it. The snapshot shows the ATM SABR lognormal vol alongside the Bachelier-priced swaption to make the surface→pricer handoff explicit. - Hull-White 1-factor short-rate engine (
finview.L1.hull_white_1f,derivatives/hull_white_1f.py, INV-006 1L build #2434, 2026-06-08) models the short rate asdr = [θ(t) − a·r] dt + σ dW. The time-dependent driftθ(t)is implied by the exact A(t,T)/B(t,T) affine reconstruction so thatP_hw(0,T) ≡ P_market(0,T)by construction — i.e. the model is calibrated to the canonical curve by identity, making it a genuine no-arbitrage term-structure model rather than a comment reference. It derives the instantaneous forwardf(0,t) = −d/dt ln P(0,t)analytically from the pchip log-DF interpolant (NOT curve_builder's discrete simpleforward_rates[]— the forward-curve fix mandated by the 1L design review). It prices a European ZCB option analytically (HW bond-option formula), hence caplets/floorlets, and a European swaption via the Jamshidian (1989) decomposition (solve forr*that makes the coupon bond hit the strike; decompose into a portfolio of ZCB options). The analytic prices are independently verified against an exact-transition Monte-Carlo simulator in the test suite. The HW analytic swaption is cross-checked against the existing Bachelier swaption — the family's first genuine cross-model challenger lane for optionality (documented soft, non-gated tolerance because a,σ are uncalibrated).a(A-284) andσ(A-285) are exogenous, caller-supplied, uncalibrated inputs (literature-typical defaults a=0.03, σ=0.01); the bond/curve analytics are exact (production) and the option outputs are non-production until calibration lands (DS-058 strike-grid swaption IV is the paid-only DR-007 gap). See Limitations 1 and the Production Scope table.
Key Assumptions and Their Justification
| Assumption | Value / choice | Where | Justification |
|---|---|---|---|
| Discount curve | SOFR/OIS bootstrap from par yields | bootstrap_sofr_curve |
Post-LIBOR OIS discounting is the market standard for collateralised rate books. |
| Projection curve | SOFR forward curve, separable from discount | CurveSet.get_projection_fwds |
Multi-curve separation of projection vs discount is mandatory post-2008/post-LIBOR. |
| Compounding | Continuous (z = -ln(df)/T) |
curve_builder.py |
Internally consistent, convention-free; converted to discrete only at leg level. |
| Coupon frequency | Semi-annual fixed and float | IRSPricer(payment_frequency=2) |
USD swap-market convention for fixed legs; matches the bootstrap grid. |
| Interpolation | Log-linear on DFs (PCHIP optional) | _interpolate_df, interpolate_curve |
Log-linear keeps forwards positive; PCHIP available where smooth forwards matter. |
| Day-count | Uniform act/act assumed (Δt = 1/freq) | _payment_times |
Stated simplification in the curve_builder governance docstring; see Limitation 2. |
| Swaption vol model | Bachelier (normal) default, Black-76 optional | SwaptionPricer(vol_type=...) |
Normal vols dominate the low/negative-rate swaption market; lognormal available. |
| Smile model | SABR β = 0.5 (CEV), Hagan approx | sabr_implied_vol, calibrate_sabr |
β = 0.5 is the standard rates default; Hagan is the industry closed-form smile. |
| DV01 / KR-DV01 | Full bump-and-reprice, ±1bp, triangular KR weights | _compute_dv01, _compute_key_rate_dv01 |
Reprice-based risk is exact for the model; triangular KR kernel is the desk standard. |
Prose. The discounting assumptions are the post-LIBOR consensus: OIS/SOFR
discounting with a separable projection curve. The two material modelling
choices a validator should scrutinise are (a) the uniform day-count
shortcut (Δt = 1/frequency rather than true accrual fractions), which the
curve_builder docstring itself flags, and (b) the absence of a convexity
adjustment for any futures-derived calibration point. Neither is hidden;
both are documented in code and carried into Limitations. The vol assumptions
(Bachelier default + SABR β=0.5) are deliberately the low-rate-regime
defaults, which is correct for a USD swaption book.
Output Snapshot
Run via python scripts/model_snapshots.py M-132. The snap_M_132() provider
resides in InsModel (ecosystem/InsModel/Models/scripts/model_snapshots.py)
and path-inserts FinView ([redacted]) before importing the
finlib engines — the model is FinView-resident but the snapshot harness is
InsModel-side (BV-032 cross-repo pattern). It re-runs IRSPricer and
SwaptionPricer against a frozen par curve. The IRS/swaption/curve engines are
regression-asserted by
tests/test_irs_pricer.py, tests/test_swaption_pricer.py, and
tests/test_curve_builder.py (34 passed at capture).
Instrument: 5-year pay-fixed vanilla IRS, $10,000,000 notional, semi-annual, fixed at 4.50% (deliberately off-market) on a frozen upward-sloping SOFR/Treasury par curve (4.30% → 4.45% across 3M→30Y).
| output | value | meaning |
|---|---|---|
| npv / fair_value | -$212,990.86 | pay-fixed @4.50% is out-of-the-money vs ~4.03% market → negative MV |
| fixed_leg_pv | $2,020,142.05 | PV of the 4.50% fixed coupons |
| float_leg_pv | $1,807,151.19 | PV of the projected SOFR float coupons |
| par_swap_rate | 4.0255% | fixed rate that zeroes the swap; emitted directly by the engine (par_swap_rate alias of par_rate) |
| dv01 (parallel +1bp) | $4,544.54 | MV change per 1bp parallel curve shift (bump-and-reprice) |
| key_rate_dv01 [1Y / 2Y / 5Y] | $964.88 / $1,823.46 / $1,511.33 | bucketed exposure; mass concentrated at 2Y–5Y as expected for a 5Y swap |
| swaption 1Yx5Y payer, K=4.00% | optionality layer (Bachelier, 75bp normal vol) | |
| forward_swap_rate | 4.0071% | forward par rate of the 5Y swap starting in 1Y |
| annuity (per $1) | 4.315015 | PV of $1/period over the underlying 5Y tenor |
| premium | $130,650.91 | swaption premium |
| delta / vega | 2.1739 / $17,213,642.22 | annuity-scaled forward delta; vega per 100% vol |
| sabr_atm_lognormal_vol (illustrative) | 7.5898% | SABR(α=1.5%,β=0.5,ρ=-0.25,ν=0.40) ATM vol that would feed Black-76 |
Prose. The signs and magnitudes are internally coherent: an off-market
pay-fixed swap struck ~47bp above the 4.03% par rate carries a negative MV
of roughly -$213k, which is close to DV01 × (4.50% − 4.0255%) × 10000 ≈
$4,545 × 47.45 ≈ -$215k, i.e. the NPV reconciles with the reported DV01 to
within bootstrap/interpolation curvature. The key-rate DV01 correctly places
exposure in the 2Y–5Y buckets and zero beyond 10Y (a 5Y swap has no 10Y+
sensitivity). The swaption's forward par rate (4.0071%) matches the spot par
rate to a few bp, as expected on a gently-sloped curve, and the premium is
consistent with a near-ATM 1Yx5Y payer at 75bp normal vol. The SABR ATM vol
is shown as an illustrative surface input — it parametrises the smile that
would supply the Black-76 vol, not a calibrated production surface.
Captured 2026-06-04 · deterministic, no live data.
Limitations and Known Gaps
- Hull-White 1F is implemented but its vol parameters are uncalibrated
(INV-006, 2026-06-08). A real Hull-White 1-factor short-rate engine
(
finview.L1.hull_white_1f) is now built and bound to M-132 (resolving the prior "not implemented" gap). It is calibrated to the canonical curve by construction (exact A/B refit; the curve/bond analytics are production), but its mean-reversiona(A-284) and short-rate volσ(A-285) are exogenous, caller-supplied, and NOT calibrated to market swaption vols — the DS-058 strike-grid swaption IV history is the structural paid-only DR-007 gap (CME DataMine barred). Per Decision 053 §4 these are explicit documented inputs, not default-zero fabrication. Consequently the engine's option outputs are scoped non-production (illustrative until a,σ calibration lands; same honest pattern as the swaption member), while the bond/curve analytics are exact. The HW-vs-Bachelier swaption cross-check is therefore a soft, non-gated sanity/challenger lane, not a pass/fail on absolute price. Single-factor HW cannot fit the full vol surface/smile (that stays SABR's job) and is Gaussian (admits negative rates — acceptable for the post-LIBOR USD regime, consistent with the family's Bachelier default). Multi-curve basis inside HW is out of scope for v1 (uses the single discount curve). Genuinely multi-factor / Bermudan-callable term-structure needs remain future work. - Uniform day-count. Accrual fractions are taken as
1/frequencyrather than true act/360, act/365, or 30/360 day-count fractions. Thecurve_buildergovernance docstring states this ("uniform day-count convention (actual/actual assumed)"). It introduces small accrual bias on stub and broken-dated trades. - No convexity adjustment. The curve builder applies no convexity
adjustment for any futures-based calibration input (also stated in the
curve_builderdocstring). Futures-strip calibration would be biased at the long end without it. - Par rate / annuity engine emission — RESOLVED (2026-06-04). Previously
IRSPricer.compute_fair_valuedid not returnpar_rate/annuitydespite their appearing in theENGINE_CONTRACToutputs list, so the snapshot re-derived them. This contract/implementation mismatch was resolved by FinView #92 (sha22d4662):compute_fair_valuenow returnspar_rate, thepar_swap_ratealias, andannuitydirectly (irs_pricer.pylines 18, 86–95), and the snapshot reads them from the engine output. No open gap. - SABR surface is illustrative, not calibrated end-to-end in the pricer.
sabr_implied_volproduces a smile-consistent vol, andcalibrate_sabrcan fit (α, ρ, ν), butSwaptionPricertakes a scalarvolinput — it does not yet pull a strike-specific vol from a calibratedSABRSurfaceautomatically. The surface→pricer wiring is manual. - Single-curve fallback is silent. When no projection/discount curve is
supplied,
IRSPricercollapses the float leg to the par identityN·(1−df_last)andCurveSetfalls back to the Treasury curve without warning. This is convenient but can mask a missing-curve configuration. - Cross-repo / FinView-resident. This model is grounded entirely in FinView Python; there are no 10-K-derived inputs and no InsModel-side engine. The InsModel venv reproduces the numbers only because it imports the same FinView source. Governance treats this under BV-032 (cross-repo FinView-resident model) — the card is descriptive of in-repo code, not of a productionised market-data pipeline.
Ratification status (RAT-132-v1.0.0 remediation, 2026-06-06). - INV-006 / COND-001 — CLOSED (doc-correction). "Hull-White" was dropped from the registry name + description and this card title + description; the declared methodology now matches the implemented SABR-fed Black-76/Bachelier code. The short-rate-engine alternative was not built (would be re-submitted for re-review if it is). See Limitation 1 and the Name-correction callout. - COND-002 — CLOSED (honest scoping). A-054 (FX correlation, default-zero) and DS-058 (swaption vols + FX basis,
planned; strike-grid IV is the paid-only DR-007 gap) are not fabricated. The placeholder-dependent members (swaption, rate-option, xccy) are scoped non-production — see the Production Scope table at the top andmodel_registry.yaml::M-132.production_scope. Calibrating A-054 / sourcing DS-058 stays an honest pending build (PL-07 / WS3). - Validation evidence — Tier-2 pack assembled atmodelling/validation_evidence/M-132/v1.0.0/README.md(real tests + reconciliation + gold-copy challenger lane; honest gaps preserved). The (T1) full pack is not required at Tier-2 (charter §4.2). - INV-032 — still tracked (non-gating, LG-132-03): FinView-resident model consumed by InsModel viasys.pathinsertion; no packaged interface / cross-repo drift gate.
Validation Packet
| Check | Evidence | Status |
|---|---|---|
| Par-swap FV ≈ 0 at inception | test_irs_pricer.py::test_par_swap_fv_near_zero |
pass |
| Pay/receive direction symmetry | test_irs_pricer.py::test_direction_symmetry |
pass |
| DV01 strictly positive | test_irs_pricer.py::test_dv01_positive |
pass |
| Key-rate DV01 concentrates at swap tenor | test_irs_pricer.py::test_key_rate_concentration |
pass |
| Off-market swap has non-zero FV (correct sign) | test_irs_pricer.py::test_off_market_swap_has_nonzero_fv |
pass |
| Result-key contract present | test_irs_pricer.py::test_result_keys |
pass |
| Swaption pricer suite | tests/test_swaption_pricer.py |
pass |
| Curve bootstrap suite | tests/test_curve_builder.py |
pass |
| HW exact curve refit (P_hw(0,T)=DF) | test_hull_white_1f.py::test_exact_curve_refit |
pass |
| HW f(0,t) integrates back to curve | test_hull_white_1f.py::test_instantaneous_forward_matches_curve |
pass |
| HW B(t,T) limits / monotonicity | test_hull_white_1f.py::test_B_function_limits |
pass |
| HW caplet analytic vs exact-MC | test_hull_white_1f.py::test_caplet_analytic_vs_montecarlo |
pass |
| HW Jamshidian swaption vs exact-MC | test_hull_white_1f.py::test_swaption_jamshidian_vs_montecarlo |
pass |
| HW ZCB-option put-call parity | test_hull_white_1f.py::test_put_call_parity_zcb_option |
pass |
| HW premium monotone in σ | test_hull_white_1f.py::test_vol_monotonicity |
pass |
| HW σ→0 collapses to intrinsic | test_hull_white_1f.py::test_zero_vol_intrinsic |
pass |
| HW-vs-Bachelier challenger (soft) | test_hull_white_1f.py::test_hw_vs_bachelier_swaption_crosscheck |
pass |
| HW ENGINE_CONTRACT outputs present | test_hull_white_1f.py::test_engine_contract_outputs_present |
pass |
| HW consumes curve, not discrete fwds | test_hull_white_1f.py::test_consumes_curvebuilder_not_discrete_forwards |
pass |
| HW engine binding / market_data | test_hull_white_1f.py::test_engine_binding_and_market_data |
pass |
| NPV ↔ DV01 reconciliation | snapshot: -$212,990.86 ≈ DV01 $4,544.54 × 47.45bp | consistent |
| Gold-copy challenger cross-check | finlib/gold_test_derivatives.py (e.g. CME_ERIS_10Y) |
available |
| Cross-venv reproducibility | identical output under FinView .venv and InsModel Models/.venv |
confirmed |
| Suite total at capture | 34 passed (irs + swaption + curve) | pass |
Gaps relative to a full Tier-2 packet: no calibrated production vol surface, no HW short-rate validation, no day-count/convexity sensitivity tests. These trace directly to Limitations 1–3 and 5.
References
Multi-curve / OIS discounting: - Henrard, M. (2014). Interest Rate Modelling in the Multi-Curve Framework. - Bianchetti, M. (2010). "Two Curves, One Price." - Mercurio, F. (2009). "Interest Rates and the Credit Crunch: New Formulas and Market Models." (post-LIBOR projection vs discount separation)
SABR / smile:
- Hagan, P., Kumar, D., Lesniewski, A., Woodward, D. (2002). "Managing Smile
Risk." Wilmott — the SABR approximation implemented in
vol_surface.py::sabr_implied_vol / calibrate_sabr.
- Obłój, J. (2008). "Fine-tune your smile: correction to Hagan et al."
Hull-White / short-rate (implemented — finview.L1.hull_white_1f, INV-006 2026-06-08):
- Hull, J. & White, A. (1990). "Pricing Interest-Rate Derivative Securities."
- Brigo, D. & Mercurio, F. (2006). Interest Rate Models — Theory and
Practice, ch. 3 (Hull-White affine bond/option formulas, §3.11 Jamshidian).
- Jamshidian, F. (1989). "An Exact Bond Option Formula." J. Finance —
the coupon-bond-option decomposition used for the analytic HW swaption.
- Glasserman, P. (2004). Monte Carlo Methods in Financial Engineering —
exact Gaussian short-rate transition (test-only independent estimator).
Engine files (FinView-resident):
- finlib/curve_builder.py — bootstrap_sofr_curve, build_sofr_curve,
CurveSet (finview.L0.curve_builder / curve_set / interpolation).
- finlib/derivatives/irs_pricer.py — IRSPricer (finview.L1.irs_pricer).
- finlib/derivatives/swaption_pricer.py — SwaptionPricer
(finview.L1.swaption_pricer).
- finlib/derivatives/rate_option_pricer.py, inflation_swap_pricer.py,
fx_forward_pricer.py, xccy_swap_pricer.py — remaining family members.
- finlib/vol_surface.py — SABR (sabr_implied_vol, calibrate_sabr,
SABRSurface) and SVI.
- finlib/gold_test_derivatives.py — gold-copy challenger reference values.
Tests:
- tests/test_irs_pricer.py, tests/test_swaption_pricer.py,
tests/test_curve_builder.py, tests/test_fx_forward_pricer.py,
tests/test_inflation_swap_pricer.py, tests/test_rate_option_pricer.py,
tests/test_gold_derivatives.py, tests/test_hull_white_1f.py (the 12
HW acceptance tests — INV-006).
Internal: - BV-032 — cross-repo FinView-resident model boundary (no 10-K inputs; FinView Python is the source of truth for this card).
Change Log
Card change history. Code-side change history lives in git log of the component files.
- 2026-06-08 (INV-006 — Hull-White 1F engine built, Decision 053 1L build #2434).
Took the alternative the RAT-132-v1.0.0 COND-001 remediation explicitly left
open: built a real Hull-White 1-factor short-rate engine
(
finview.L1.hull_white_1f,finlib/derivatives/hull_white_1f.py) and bound it to M-132. The engine is calibrated to the canonicalcurve_builderdiscount curve by construction (exact A/B affine refit; instantaneous forwardf(0,t)derived analytically from the pchip log-DF interpolant — the forward-curve fix mandated by the 1L design review, NOT the discreteforward_rates[]), with analytic ZCB-option / caplet-floorlet pricing, a European swaption via Jamshidian decomposition, and a test-only exact-transition Monte-Carlo cross-checker. Added the HW-vs-Bachelier swaption challenger lane (soft, non-gated). 12 real deterministic tests (tests/test_hull_white_1f.py) all pass. Restored "Hull-White" to the family name (registry + this card title/description); rewrote the Methodology HW bullet and replaced Limitation 1 ("not implemented" → "implemented, vol params uncalibrated"). Registered the engine (engine_registry.yaml, total_engines 131→132) and A-284 (mean-reversion a) / A-285 (short-rate σ) as exogenous/uncalibrated assumptions (NOT default-zero fabrication; per Decision 053 §4). Production scope: HW bond/curve analytics are production, HW option outputs are non-production until a,σ are calibrated (DS-058 strike-grid IV is the DR-007 paid-only gap) — mirror inmodel_registry.yaml::M-132.production_scope. Tier-2 evidence pack atvalidation_evidence/M-132/v1.0.1/. Regenerated the FinView binding manifest. No engine outputs, back-test numbers, or validation results were fabricated. Prepared for 2L re-review (RAT-132-v1.0.1); 1L did not edit the RAT record or the 2L workspace. - 2026-05-08 — stub created from registry data per Decision 023 Phase 5 / B-07.
- 2026-06-06 (1L remediation, RAT-132-v1.0.0 COND-001 + COND-002) — Remediated the two gating conditions under the Decision 053 1L charter §2.2 (no engine outputs, back-test numbers, or validation results fabricated). COND-001 (doc): dropped the unimplemented "Hull-White" from the model name
- description (registry + this card) — now "Multi-Curve / Black-Bachelier /
SABR"; added the Name-correction callout. COND-002 (doc/scoping): split the
family into a production linear-IR core and non-production placeholder-dependent
members (swaption / rate-option / xccy) via a Production Scope table here and
model_registry.yaml::M-132.production_scope; A-054 / DS-058 calibration is left as an honest pending build (PL-07 / WS3), not fabricated. LG-132-01 (doc): reconcileddocumentation_packflags (model_card + change_log → present; validation_evidence → present, pack assembled). Assembled the Tier-2 validation-evidence pack atvalidation_evidence/M-132/v1.0.0/. Re-stamped doc-currency. Prepared for 2L re-review; 1L did not edit the RAT record or the 2L workspace. - 2026-06-06 — 2L code-grounded documentation refresh against
irs_pricer.py(sha22d4662) +sofr_futures_pricer.py+ the InsModel snapshot harness. Reconciledpar_rate/par_swap_rate/annuityto engine emission (FinView #92, 2026-06-04): rewrote the Representative-pricer paragraph and the Output-Snapshot prose to read these from engine output rather than re-deriving, and converted Limitation 4 to a RESOLVED note. Added the Standards Coverage section (framework-level ASOP 56 / SR 26-2; no numbered standard prescribes the IR/FX pricing math). Tightened the Hull-White wording in Methodology and Limitation 1 to "no HW short-rate engine/class is implemented (grep finds only a comment reference insofr_futures_pricer.py)". Corrected the snapshot-provider note:snap_M_132resides in InsModelModels/scripts/model_snapshots.pyand path-inserts FinView. Noted gated/ratification items (INV-006, Tier-2 validation evidence, A-054 / DS-058, INV-032) under Limitations. Non-output-changing: no model outputs, back-test numbers, or validation results were fabricated or changed.
Open findings (2)
Independent 2nd-line review (INV-2026-06) — implemented capability vs registered scope. Each carries a recommended fix and is tracked in insightalm-mrm until closed.
Validation evidence + change logs missing across most of the inventory
Only M-001/M-020/M-050 carried full documentation packs before this pass. Most models record validation_evidence: missing and change_log: missing with peer_review: pending. Gold tests freeze behaviour but many assert only structural invariants (e.g. reserve>0), not correctness against external truth. The flagship T0-vs-10-K match is circular (BV-032).
Recommendation: For each Tier-1 model: produce a validation-evidence pack (back-test vs disclosed results once BV-032 re-calibration lands, sensitivity suite, challenger comparison), a change log, and a 2L ratification. Sequence behind BV-032 (firm-data) for anything needing 10-K reconciliation.
FinView-resident pricing/CECL engines reached cross-repo with no drift gate
M-040 (CECL) and M-130-137 (asset pricing) are FinView-resident, consumed by InsModel only via sys.path insertion. No packaged interface or drift gate — a finlib signature change silently breaks the InsModel snapshot harness / consumers.
Recommendation: Define a packaged interface (or a versioned contract) for the FinView pricing library and a CI drift gate, so cross-repo consumers fail loudly on signature change. Tie to D041 ownership.
Per-tier expectations
Per MRM Framework §10.2 + §10.3, this model's regulatory_frameworks tag list activates the following overlays:
| component | tier-2 expectation | status |
|---|---|---|
| Registry entry | required | present |
| Model card (§10.5 doc pack) | required | present |
| Validation evidence | required | present |
| Change log | required | present |
| Independent effective challenge (2L) | required | attested |
Ratified — RAT-132-v1.0.1
Latest ratification on file: RAT-132-v1.0.1. Authored by 2L (mrm-peer-reviewer) per Decision 028 charter §5 Pattern A.