Conversation
There was a problem hiding this comment.
Pull request overview
This PR standardizes how volatility-surface forwards and discount curves are calibrated from put-call parity, removes user-selectable curve models from the API/UI, and introduces a consistent ref_date for time-to-maturity calculations across loaders, surfaces, and calibration.
Changes:
- Make
ref_datean explicit field on surface pricers/loaders and propagate it intoVolSurface. - Rework curve calibration flow: asset curve is always fitted from parity forwards, quote curve is fitted when calibratable (otherwise treated as known), and API/UI curve selection is removed.
- Simplify parity tooling by removing discount-factor fitting helpers and updating tests/docs/examples to the new calibration approach.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| quantflow/rates/interpolated.py | Use shared rounding precision (ROUND_RATE) when setting interpolated curve anchor rates during calibration. |
| quantflow/options/surface.py | Introduce explicit ref_date, change default asset curve model, refactor curve calibration behavior, and update surface construction. |
| quantflow/options/parity.py | Remove discount-factor fitting utilities and adjust plotting to use forward + quote-discount estimation. |
| quantflow/data/yahoo.py | Initialize loaders with explicit ref_date and use interpolated curves as the starting quote curve model for equities. |
| quantflow/data/deribit.py | Initialize loaders with explicit ref_date and rely on default curve setup appropriate for Deribit flows. |
| quantflow_tests/test_surface_calibration.py | Update calibration tests to match new curve-fitting semantics and remove tests for deleted helpers. |
| quantflow_tests/test_parity.py | Update parity tests to validate the new quote-discount estimation approach. |
| quantflow_tests/test_non_inverse_surface.py | Ensure loaders are built with an explicit ref_date. |
| quantflow_tests/test_app.py | Update API behavior assertions now that curve selection is backend-driven and cached by asset only. |
| frontend/src/volatility-surface.md | Remove curve selectors and align UI copy with the new backend-driven curve calibration behavior. |
| docs/tutorials/volatility_surface.md | Update tutorial narrative and references to the new forward/curve calibration flow. |
| docs/tutorials/curve_calibration.md | Expand and clarify the curve calibration derivation around fixed forwards and quote discount estimation. |
| docs/examples/curve_calibration.py | Update example workflow to use calibrate_forwards outputs and simplify dataframe construction. |
| app/api/volatility.py | Remove curve selection query params and always run backend-driven calibrate_curves(). |
| app/api/docs/volatility_surface.md | Align API documentation with the new fixed curve calibration behavior. |
Suppressed comments (2)
quantflow/options/surface.py:1567
- The calibrate_curves() docstring says that when the asset curve model cannot be calibrated (e.g. NoDiscountCurve) an InterpolatedMonotonicCubicCurve is fitted instead, but the implementation now raises ValueError in that case. Please update the docstring to reflect the actual behavior (or implement the fallback).
cannot be calibrated, for example a NoDiscountCurve, an
[InterpolatedMonotonicCubicCurve][quantflow.rates.interpolated.InterpolatedMonotonicCubicCurve]
is fitted instead: it passes exactly through its nodes, so the curve
implied forward reproduces the parity forward at every calibrated
maturity.
quantflow/options/surface.py:1522
- The asset_curve parameter docs say that passing None keeps the current curve and treats it as known, but the implementation always fits the asset curve from parity forwards (and raises if the curve has no calibrator). The parameter docs should reflect this behavior.
"YieldCurve type or instance to fit the asset discount curve "
"$D_a$. "
"When None the current asset_curve is kept and treated as known."
),
| curve = ( | ||
| curve_type(ref_date=self.ref_date) | ||
| if isinstance(curve_type, type) | ||
| else curve_type | ||
| else curve_type.model_copy(update=dict(ref_date=self.ref_date)) | ||
| ) |
| "YieldCurve type or instance to fit the quote currency discount " | ||
| "curve $D_q$. " | ||
| "When None the current quote_curve is kept and treated as known." | ||
| ), |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #92 +/- ##
==========================================
+ Coverage 88.75% 89.03% +0.27%
==========================================
Files 84 85 +1
Lines 5142 5410 +268
==========================================
+ Hits 4564 4817 +253
- Misses 578 593 +15 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
No description provided.