Story: Support volatility surfaces — the remaining work
Table of Contents
This page documents a story in Sprint 30, carried unfinished from Sprint 29 at close. It captures the goal, current status, acceptance criteria, and the tasks that compose it.
1. Goal
The system builds and serves volatility surfaces as market data. A surface is calibrated from its quotes, read by pricing, and fed by a synthetic generator that starts from calibrated levels.
2. Status
| Field | Value |
|---|---|
| State | STARTED |
| Parent sprint | Sprint 30 |
| Now | Not yet started. Split from Support volatility surfaces, which closed in sprint 29 with its done tasks. |
| Waiting on | Nothing. |
| Next | Build the SSVI calibration engine. |
| Last touched | 2026-11-08 |
3. Acceptance
- A surface is calibrated from its quotes, checked for arbitrage and written as a candidate with lineage.
- A second person publishes a candidate, and the published surface and its slices can be read and seen on a screen.
- A report binds to a published surface, and ORE prices an FX option from the exported grid.
- A synthetic generator publishes contributor quotes that a blueprint can calibrate from.
- The synthetic feeds start once from their calibrated levels, take a new calibration at the market day roll, and recalibrate on a schedule.
4. Tasks
| Task | State | Start | End | Description |
|---|---|---|---|---|
| Build the SSVI calibration engine | DONE | 2026-11-09 | 2026-11-09 | A pure quant engine that fits SSVI to weighted FX volatility quotes, samples the output grid and checks the result for arbitrage, with no service or database. |
| Seed a surface blueprint for one pair | DONE | 2026-11-09 | 2026-11-09 | Seed the first FX volatility surface blueprint, for EUR/USD, whose pillars read the derived ATM, RR and BF quotes and whose output series exists. |
| Make FX forwards available from the IR curves | DONE | 2026-11-09 | 2026-11-09 | Compute FX forward rates, discount factors, forward points and swap points from the published IR curves and spot, read them through a service operation, and show all four on a screen. |
| Read FX forwards for a pair | DONE | 2026-11-09 | 2026-11-09 | A read operation that answers one USD-hub pair at one as-of from its spot, two published funding curves and pair conventions, and names the inputs it used. |
| Write the FX forward ladder journey | DONE | 2026-11-09 | 2026-11-09 | The user journey for reading a pair's forward ladder, judged step by step, and signed off by the owner before any prototype. |
| Prototype the FX forward ladder | DONE | 2026-11-09 | 2026-11-09 | A plain HTML prototype of the forward ladder under doc/prototypes/market_data, signed off by the owner before any code. |
| Build the FX forward ladder screen | DONE | 2026-11-09 | 2026-11-09 | The live screen that draws the signed-off prototype through the shared parts, in three languages, tested and signed off. |
| Build holiday calendars in provisioning | DONE | 2026-11-09 | 2026-11-09 | Provisioning loads the holiday rules of every published calendar and builds its dates, so value dates respect holidays on a fresh tenant. |
| Control auto-approval for a tenant, in plain view | DONE | 2026-11-09 | 2026-11-09 | A recorded per-tenant switch closes approvals without a person, provisioning turns it on, a profile says whether it stays on, and every screen and record shows it. |
| Give parties the system's raw quotes through subscriptions | DONE | 2026-11-09 | 2026-11-09 | The system's feeds play the vendor, and every operational party receives the IR quotes and USD spots of all 20 funding currencies into its own series through its subscriptions. |
| Bootstrap and publish each party's funding curves in provisioning | DONE | 2026-11-09 | 2026-11-09 | A provisioning step gives every operational party its own blueprints, bootstraps them from the system's raw quotes and publishes them under the tenant's auto-approval. |
| Publish FX forward curves with their provenance | DONE | 2026-11-09 | 2026-11-10 | A forward curve becomes a party's published record in the database: its points, its inputs and how it was approved, through the same maker-checker as an IR curve. |
| Show published FX forward curves and their provenance | DONE | 2026-11-10 | 2026-11-10 | The ladder screen reads published sets, explains where each number came from, and the compute-on-read path goes. |
| Publish FX forward curves in provisioning | BACKLOG | A separate provisioning step, after each party's funding curves, publishes a forward curve for every USD pair that party can build. | ||
| Give each party its surface blueprints | BACKLOG | Each party owns FX volatility surface blueprints whose pillars read the system's raw volatility quotes through its subscriptions. | ||
| Calibrate a volatility surface from its quotes | BACKLOG | The marketdata.v1.surface.calibrate operation and its engine, with the recipe and result checks run in the service, writing a candidate with lineage; see Constructing a volatility surface: from quotes to a published set. | ||
| Publish a calibrated surface | BACKLOG | A maker raises the publish of a surface candidate, a second person decides, and the approved set becomes the authoritative surface for its blueprint and as-of. | ||
| Calibrate and publish each party's surfaces in provisioning | BACKLOG | A provisioning step, after the forward curves, calibrates each party's surfaces from its published forward sets and publishes them under the tenant's auto-approval. | ||
| Read a published surface and its slices | BACKLOG | The surface and slice reads the slices journey needs, over the published set rather than the quotes; see Constructing a volatility surface: from quotes to a published set. | ||
| Export a published surface to ORE through the report binding | BACKLOG | A report binds to a published surface, and its ORE export writes the grid as ORE volatility quotes with the matching fx_volatility_config. | ||
| Build the calibrate and slices screens | BACKLOG | The screens of the Calibrate or refresh a surface and Inspect a surface's slices journeys, over the calibrate operation and the published surface reads. | ||
| Build the synthetic FX volatility surface generator | BACKLOG | A generator of kind fx_vol_surface whose SSVI state evolves through bounded processes correlated with spot, observed by contributors with noise profiles; see the approach note and A synthetic contributor publishes noisy observations of a latent surface. | ||
| Load the public rates as a workflow step | BACKLOG | The official service serves a step that backfills each accepted public source and completes once its fixings are stored, so a workflow can order calibration after the rates exist. | ||
| Run the synthetic calibration workflow | BACKLOG | A workflow on the engine loads the public rates, calibrates the feeds, approves the fits the policy allows and tells the reviewer of the exceptions, started by an operator or by another run. | ||
| Release the synthetic feeds after calibration | BACKLOG | The synthetic adapters serve no demand for an asset class until it is released, so every feed starts once, from its calibrated level, and the recorded spots have no jump. | ||
| Calibrate in the provisioning system run | BACKLOG | The system run of provisioning starts the calibration workflow after it publishes the system data, and a profile may release the feeds once it completes. | ||
| Resume a feed from its last stored spot | BACKLOG | A feed that has run before starts again from its own last stored spot, not from the fixing, so a restart, a deploy or a crash puts no jump in the recorded series. | ||
| Take a new calibration at the market day roll | BACKLOG | A running feed whose pair has a newly approved calibration, or whose spread was recalibrated, takes it at its next market day roll without a restart. | ||
| Recalibrate the synthetic feeds on a schedule | BACKLOG | The scheduler starts the calibration workflow each business day, so new fixings move the levels and the fits without a person starting it. | ||
| Re-anchor a class to the public rates | BACKLOG | An operator re-anchors an asset class: its feeds restart from the latest calibrated levels, a deliberate and recorded jump, since otherwise a running feed's level follows its own path. |
5. Decisions
- Provisioning leaves each party ready to price from its own surfaces (2026-11-09). The owner chose: every operational party has funding curves in all 20 currencies, forward curves for USD pairs and for the crosses with a convention, and calibrated surfaces. A cross spot derives from its two USD legs. The published surfaces use each party's forward sets, so Calibrate returns to the backlog until those exist.
- The system owns raw market data, and parties own what derives from it (2026-11-09). The owner's model: the system tenant plays the vendor, as Bloomberg would, and subscriptions and derived data such as curves and forwards are party concerns. A funding curve is therefore bootstrapped per party.
- Provisioning runs under a visible auto-approval (2026-11-09). A recorded per-tenant switch closes approvals during provisioning. Afterwards regular users publish through maker-checker, unless the profile keeps the switch on for a demonstration. The switch must be obvious to anyone troubleshooting.
- IR feeds are calibrated from public rates before provisioning publishes forwards (2026-11-09). Context: the FX spot feeds start from the public Frankfurter fixings and the FX variance is fitted to their history, but the IR feeds start from fixed template levels. The system stores no public IR rate. Forwards built from those curves carry rate differentials with no tie to the market. Decision: the owner chose to finish IR calibration before the forwards are complete. The forward records, their reads and their screen can be built first. Publish FX forward curves in provisioning waits on Read the public overnight rates through an adapter and Calibrate the synthetic IR feeds from the public rates, in the story Build the IR curves from public data. Consequences: another environment takes the two IR tasks in parallel with the FX work here, and the forwards step in provisioning starts once both are merged.
- A cross settles on its two calendars, and its spot comes from the USD legs (2026-11-10). Context: the acceptance asked for the convention on a USD holiday. Decision: follow ORE, whose cross conventions advance on the two currencies' calendars only, so a USD holiday does not move a cross's spot date; QuantLib confirms the dates. The spot is the ratio of the party's two USD legs, each read in the market's direction. Consequences: a cross forward equals the ratio of its USD-leg forwards on the same dates.
- Raw quotes are delivered into each party's own series (2026-11-09). Context: the system tenant plays the vendor, and two readings were possible: one shared copy that parties read, or delivery through a subscription into each party's own series. Decision: the owner chose delivery, which the sprint 29 routes already do, with metering per party. London and New York keep their own vendors and also take Bloomberg, because only Bloomberg quotes the whole funding set. Consequences: no reorder of the tasks is needed. The feeds already run, so the release task is not a prerequisite of the party curves.
- FX forward curves are published records (2026-11-09). The owner reversed computing forwards on read. A forward set is written to the database with its provenance and passes through maker-checker, as an IR curve does. Provisioning publishes them in a separate step after the funding curves.
- The FX forward ladder journey and prototype are signed off together (2026-11-09). The owner chose one sign off for both. The screen starts from USD pairs, its ladder start moves near dates only, and its chart spaces tenors evenly.
- Split from Support volatility surfaces on 2026-11-08 at sprint 29 close. The acceptance above is copied from that story; its done tasks are recorded there.
- Reviewed on 2026-11-08 at sprint 30 start. Goal rewritten, because the architecture it named is done. The tasks are two arcs: the surface and the calibration of the synthetic feeds.
- The tasks run in dependency order, and the surface path reaches pricing (2026-11-09). Context: three surface tasks had no goal or acceptance, and the construction note's path from a calibrated surface to a report had no tasks for the publish, the ORE export or the screens. No blueprint was seeded. Decision: the task table is in working order, the surface arc first. The arc adds the engine, split out of the calibrate task so unit tests can prove it alone, a seeded blueprint for EUR/USD, the publish, the ORE export and the screens. Consequences: the story closes only when pricing reads a surface; the first surface calibrates from the derived quotes, so the generator can follow it.
- The calibration fits gamma, as QuantExt does (2026-11-09). Context: the decision of 2026-11-03 set SSVI with gamma = 1/2 for the synthetic surface. QuantExt calibrates a power-law SSVI with gamma in (0, 1), and its bounds on real-shaped smiles are the ground truth this engine ports (
QuantExt/test/sviparametricvolatility.cppandQuantExt/test/bfrrvolsurface.cppin ORE 1.8.17.0). SSVI and Surface-Wide Parameterization (riskhub.org) found a power-law gamma of 0.28 on a Heston surface. Decision: the calibration engine fits rho, eta and gamma, with phi(theta) = eta * theta^(-gamma). Consequences: the no-arbitrage conditions are checked expiry by expiry, because the curvature condition depends on theta once gamma differs from 1/2. The generator's own choice of gamma is taken up in its task.
6. Out of scope
- The fixings history. Years of daily fixings in every environment are Seed the public fixings history from a DQ snapshot, a story of its own: this story works from the adapter's shorter window without it, with the priors of the derived quotes dominating and weak butterflies.
- Two-way pricing. Every quote, synthetic or real, is a mid, and valuation runs on mids. Bid and ask, for every input and not only vol surfaces, are a later level of work, taken up once mid valuation is reliable for every product.
- The rest of the scope is set by the architecture task.