Fix FX variance swap fair strike and the realised variance normalisation - #283
Merged
domokane merged 1 commit intoSep 30, 2026
Merged
Conversation
FinFXVarianceSwap.fair_strike could not run: it built FXVanillaOption with the equity constructor's arguments and raised TypeError, and it had no tests. It also carried the three defects fixed in the equity version: the log-contract drift used r_d instead of r_d - r_f, the option portfolio was compounded by exp((r_d - r_f) T) instead of exp(r_d T), and a put grid reduced to positive strikes was still looped over with the requested count and could include a zero strike. Price the replication options with the Garman-Kohlhagen closed form and apply the same corrections. realised_variance in both the equity and the FX class summed N - 1 squared returns but divided by N, the number of prices; divide by the number of returns.
domokane
approved these changes
Sep 30, 2026
Owner
|
Thanks |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #282, which fixed the equity variance swap. The FX class has the same replication code and more.
1.
FinFXVarianceSwap.fair_strikecannot run. It prices the replication options withFXVanillaOption(self.maturity_dt, k, put_type), the equity constructor's arguments, so every call raisesThe class has no currency pair to build an FX option with, and does not need one: the replication options are now priced with the Garman–Kohlhagen closed form (
european_valuewith the foreign rate as the dividend yield).2. The same three defects as the equity version. The log-contract drift used
r_dinstead ofr_d - r_f, the option portfolio was compounded byexp((r_d - r_f) t)instead ofexp(r_d t), and a put grid truncated to positive strikes was still looped over with the requested count and could contain a zero strike. In FX the foreign rate is never zero in practice, so the first two bias every fair strike by about2 r_f.With the fix, under a flat 12% volatility the fair variance strike is within 0.02% of 0.0144 for
(r_d, r_f)in{(3%, 0%), (3%, 5%), (1%, 4%), (4%, 4%)}.3. Realised variance normalisation (both classes).
realised_variancesums theN - 1squared returns ofNprices but divides byN. The market-standard definition divides by the number of returns, so the result was low by a factor(N - 1) / N: eleven prices with a constant 1% daily log return gave 0.02291 instead of252 × 0.01² = 0.0252. Fewer than two prices now raisesFinError.Tests
New
tests/unit/test_FinFXVarianceSwap.py(fair strike equals the flat variance across rate pairs; reduced put grid; realised variance of a constant-return series) and one realised-variance test intest_FinEquityVarianceSwap.py. Full unit suite passes (1,065 tests).