Skip to content

Add Heston model calibration adjoint example - #26

Open
tylrcc wants to merge 1 commit into
auto-differentiation:mainfrom
tylrcc:example/heston-model-adjoint
Open

tylrcc wants to merge 1 commit into
auto-differentiation:mainfrom
tylrcc:example/heston-model-adjoint

Conversation

@tylrcc

@tylrcc tylrcc commented Nov 12, 2026

Copy link
Copy Markdown

Closes #19.

Python port of the AdjointHestonModel C++ example, following the pattern of swap-adjoint.py:

  • Same setup as the C++ original: DAX data from QuantLib's Heston test (spot 4468.17, 13 strikes x 8 expiries = 104 prices, fit on prices via HestonModelHelper with PriceError), COSHestonEngine(model, 12, 75), Levenberg-Marquardt at tolerance 1e-12 starting from (0.1, 1.0, 0.5, -0.5, 0.1), then a forward-start call (strike set in 6M, expiry 18M) priced with AnalyticHestonForwardEuropeanEngine.
  • Sensitivities to all 114 market inputs via the implicit function theorem: Hessian blocks of the calibration objective from central differences of its adjoint gradient (11 recordings), one more recording for dV/dp and the direct dV/dm, and a 5x5 solve (numpy, already in the examples' requirements).
  • The eight largest sensitivities are cross-checked inside the example by bump-and-recalibrate.

Testing, with two caveats I want to be explicit about:

  1. The current QuantLibAAD wheel is not reachable from my sandbox, so I ran the identical example code against QuantLib-Risks 1.33.3 (the direct predecessor of QuantLibAAD; the tape-construction lines differ slightly between the two APIs). The full flow runs end to end and the cross-check agrees: e.g. zero rate 524d IFT 2887.910476 vs bump-and-recalibrate 2888.227150 (1.1e-4 relative); zero rate 165d -1040.308095 vs -1040.250569; worst of the eight is 4.3e-4 relative.
  2. In that older 1.33.3 build, COSHestonEngine segfaults when pricing a helper, so for the local run I substituted AnalyticHestonEngine for the calibration engine only (the submitted file uses COS, as in the C++ example and as the issue describes; plain QuantLib 1.44 prices the same helper with COS without issue, giving the same model value as the analytic engine to 6 significant digits). With the analytic engine the local calibration lands on theta 0.0722, kappa 3.6200, sigma 1.2293, rho -0.5790, v0 0.1289 and a forward-start value of 480.64; the COS calibration in the current build may differ slightly in the last digits. If the COS engine misbehaves in the current build as well, the analytic engine is a drop-in fallback for this example.

Note: this repo requires a signed CLA before merge (per CONTRIBUTING) — I understand it will be handled through the CLA flow.

Port of the AdjointHestonModel C++ example. A Heston model is
calibrated to 104 DAX option prices and prices a forward-start call;
the sensitivities of the price to all 114 market inputs are computed
with the implicit function theorem - Hessian blocks of the calibration
objective from central differences of its XAD gradient (11 recordings)
- instead of recording the calibration itself.

The example cross-checks the eight largest sensitivities by bumping
each input, recalibrating, and repricing.
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Heston model example with AAD

2 participants