Task: Dual-curve (discount + projection) short-rate model

Table of Contents

This page documents a task in the IR Rates synthetic data: dataset seeding, index cleanup, dual-curve, quoting conventions story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

Today ir_curve_generation_config drives exactly one short-rate process, whose discount_factor() feeds every instrument (deposits, FRAs, swaps) via curve_instrument_pricer – a single self-discounting curve, deliberately simplified for Phase 1 (confirmed intentional for the current PoC, not a gap). Real post-2008 market practice separates OIS discounting from index/IBOR projection, with a basis spread between them. This task adds that: a second process/curve per currency+index representing the discounting leg, distinct from the projection/index leg the existing process already models, with a basis spread parameter between them.

2. Scope

  • curve_instrument_pricer needs to accept two discount-factor sources (discounting + projection) instead of one.
  • New config fields for the discounting curve's own process parameters (mirroring the existing projection process' kappa/theta/ sigma/initial_rate).
  • Separate charts/UI in the IR curve editor to show both curves distinctly (not one merged "curve shape" chart).
  • Raised while reviewing the IR curve editor's charts in Tick-batch publishing and persistence for curve instruments; deliberately deferred out of that task's scope.

3. Note: not a mismatch today

The seeded indices (SOFR/US, ESTR/EUR, SONIA/GBP) are all overnight RFRs – the same logic applies uniformly to all three, none is a special case. An OIS swap referencing an overnight index genuinely is a single-curve, self-discounting instrument in real markets: its floating leg settles at the overnight rate itself, and that same overnight rate is also the standard discounting rate for cleared/ collateralized derivatives in that currency (this is exactly what the post-2008 multi-curve framework's "OIS-discounting" leg is – the OIS curve itself, built from OIS instruments, is single-curve by construction; it is only the IBOR-projection leg layered on top of it that needs a second curve). So single-curve modeling is the correct choice for what is currently seeded, not a simplification that happens to work. The mismatch this task actually resolves would arise from adding an IBOR-style term index (EURIBOR, legacy LIBOR, term SOFR) – those carry a credit/liquidity/term premium distinct from the risk-free overnight rate, so a swap referencing one genuinely needs OIS discounting plus a separate IBOR projection curve. IBOR-style indices should not be added to the seeded universe until this task lands.

4. Status

Field Value
State ABANDONED
Parent story IR Rates synthetic data: dataset seeding, index cleanup, dual-curve, quoting conventions
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-09-23

5. Acceptance

  • A decision is made and documented on the config-model shape (second process embedded in ir_curve_generation_config, vs. a separate linked discounting-curve entity).
  • curve_instrument_pricer derives each instrument's rate from the correct pair of discount factors (discounting curve for the numeraire, projection curve for the index leg) rather than one shared source.
  • The IR curve editor shows both curves distinctly (separate charts or a clearly-labelled combined view, not a silent merge).
  • Existing single-curve configs continue to work (either migrated to a degenerate discounting==projection case, or an explicit toggle).

6. Plan

(Implementation strategy. Written when work starts; key decisions are distilled into the parent story's * Decisions at close, but the plan itself stays — it is the historical record of what we did.)

7. Notes

8. Test Scenarios

Manual QA scenarios (scaffolded via compass add test_scenario, run through the QA Validation Runner panel) that verify this task. Link new ones here as they're created; the scenario doc itself links back via its "Verifies task" field.

Scenario State Notes
     

9. PRs

PR Title
   

10. Review

Comment summary File Decision Notes
       

11. Result

Abandoned at sprint 25 close. The IR work needs a refactor at the implementation level before more features land, and sprint 26 does not reach it. The capture Refactor the IR rates implementation before more IR features land holds the remaining work.

Emacs 29.3 (Org mode 9.6.15)