Skip to content

Fix variance swap fair strike with a dividend yield and reduced put grids - #282

Merged
domokane merged 1 commit into
domokane:masterfrom
Cashubski:fix/variance-swap-put-count
Sep 27, 2026
Merged

domokane merged 1 commit into
domokane:masterfrom
Cashubski:fix/variance-swap-put-count

Conversation

@Cashubski

Copy link
Copy Markdown
Contributor

Summary

EquityVarianceSwap.fair_strike (the Demeterfi, Derman, Kamal and Zhou replication) has three defects. Under a flat volatility the fair variance strike should be the squared volatility whatever the rate and dividend yield; currently:

r q fair variance strike expected
5% 0% 0.0898 0.09
5% 2% 0.1281 0.09
0% 3% 0.1472 0.09
5% 5% inf 0.09
  1. Dividend yield. The first term used r * t where the log-contract drift is (r - q) * t, and the option portfolio was compounded by g = exp((r - q) t) instead of exp(r t) (DDKZ 1999, eq. 29, with the forward F = S0 exp((r - q) t)). The error is about 2 q, as the table shows.
  2. Reduced put grid. When the requested put strikes would go below zero, the code truncates the strike list and sets self.num_put_options, but allocates the weights and runs the pricing loop with the requested count, so it raised IndexError (e.g. 140 puts with unit spacing from a forward near 103).
  3. Zero strike. The truncation loop could keep a strike of exactly zero, where the log-contract weight is -inf (the r == q row above).

Changes

  • (r - q) in the log-contract term and exp(r t) compounding of the option portfolio.
  • Use self.num_put_options / self.num_call_options for the weight arrays and the pricing loops.
  • Keep the truncated put strikes strictly positive.

With the fix the fair strike is within 0.2% of the squared volatility for every combination above (the residual is the strike discretisation). The existing test uses q = 0 and is unchanged.

Tests

Two new tests in tests/unit/test_FinEquityVarianceSwap.py: a put grid that exceeds the positive strikes (no error, reduced count, fair strike within 2% of the flat volatility squared), and rate/yield combinations including r == q with a grid reaching zero (finite, within 1%). Full unit suite passes (1,060 tests).

…rids

EquityVarianceSwap.fair_strike had three defects:

- The log-contract drift used r instead of r - q and the option portfolio
  was compounded by exp((r - q) T) instead of exp(r T). Under a flat
  volatility the fair variance strike was too high by about twice the
  dividend yield (0.128 instead of 0.090 for sigma = 30%, q = 2%).
- When the requested put strikes reached below zero the strike list was
  truncated but the weight array and the pricing loop still used the
  requested count, raising IndexError.
- The truncated grid could include a strike of exactly zero, where the
  log-contract weight is infinite.

The existing test (q = 0) is unchanged. New tests check the fair strike
against the squared flat volatility across rate and dividend combinations
and with a put grid that reaches zero.
@domokane

Copy link
Copy Markdown
Owner

OK. Good find. Thanks.

@domokane
domokane merged commit 76b3bc2 into domokane:master Sep 27, 2026
2 checks passed
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.

2 participants