Monte Carlo variance swaps¶
MCVarianceSwapEngine prices the same spot-start variance swap
using integrated log-price diffusion squared. It is not a historical realized
variance or discrete squared-return estimator.
Estimator and supported market¶
For each path, the engine integrates sigma(t, S(t))² from zero to the final
grid time and divides by that time. sigma is the retained generalized
Black-Scholes process's log-price diffusion, not arithmetic diffusion
sigma × S. The pinned native floating-grid trapezoidal rule selects the path
state by truncating t / dt; its integration intervals can differ from the
path-step count by floating-point rounding. Numerical fixture parity preserves
that distinction rather than substituting integer-node indexing.
- Supported automatic volatility dispatch:
BlackConstantVolandBlackVarianceCurve<Linear>through its local-volatility curve. - Rust retains existing explicit external local-volatility handles, with reference, state and diffusion validation. No new external-local-vol facade is added to Go or Python.
- Other variance-curve interpolators and volatility surfaces are not silently converted to local volatility. Standalone arithmetic GBM, Heston, jump and GJR processes are not accepted as this engine's process.
- Start must equal current Settings evaluation date and all three market reference dates at pricing. No forward-start contracts, historical fixings, accrued variance, observation calendars or discrete-monitoring controls.
- Paths require positive finite states and finite nonnegative log diffusion; nonfinite intermediate values or outputs error rather than publish NaN/Inf.
Strike 0.04 is annualized variance, equivalent to 20%². Notional is cash
per whole variance unit. Long NPV is
discount(maturity) × notional × (variance − strike); short reverses its sign.
The risk-free curve's reference-to-maturity year fraction determines the grid
horizon. See the instrument page for ownership and start/expiry boundaries.
Configuration and results¶
Exactly one grid mode and one sampling mode must be supplied. Contradictory selectors error. An optional checked maximum is valid in either sampling mode.
| Input | Contract |
|---|---|
steps |
Positive explicit path-step count |
steps_per_year |
Positive density; count is max(trunc(density × maturity_time), 1) |
samples |
Fixed sample count of at least two |
tolerance |
Finite positive absolute annualized-variance standard-error target, not cash or relative error |
max_samples |
Tolerance mode: defaults to 50,000, at least 1,023. Fixed mode: optional validated upper bound, at least samples |
seed |
0 randomizes; 1..2³²−1 is reproducible and restarts on recalculation |
| Resource caps | At most 100,000 steps / 1,000,000 samples; conservative (2 × steps + 2) × sample_budget ≤ 100,000,000 |
Fixed mode always runs the requested sample count; a supplied maximum validates the bound but does not act as a stopping criterion. Its work budget uses the requested count. Tolerance mode starts with 1,023 paths, then adapts native-sized batches. It reports the actual count used. Reaching the budget without meeting the target errors; it does not return an unconverged price. Only PseudoRandom is supported: no antithetics, Brownian bridge, control variates or quasi-MC modes.
| Result | Meaning |
|---|---|
variance() |
Mean annualized path statistic |
samples() |
Actual completed path count |
variance_error() |
Nonnegative standard error in annualized-variance units |
error_estimate() |
Native signed cash error: discount × notional × position_sign × variance_error; negative for shorts |
option_weights() |
Empty for MC, not a replication portfolio |
Sampling errors exclude time discretization and integration bias. At constant
volatility, the mathematical path statistic is sigma²; floating integration and
centered sample statistics can introduce tiny roundoff error. Sampling error can
be zero even on a coarse grid. That does not certify the grid or a more general
volatility model.
Do not use the signed cash error as an unsigned confidence-interval half-width.
The finite option-strip engine has separate tail/strike-spacing bias and a native nonzero-dividend limitation. Compare the two engines only in valid zero-dividend, dense-strip limits, not as an arbitrary finite-strip equality assertion.
Paired examples¶
The complete examples share spot 100, rate 3%, no dividends, constant
volatility 20%, one year, 252 steps, 1,023 samples and seed 42. Variance
is approximately 0.04, with approximately zero NPV at strike 0.04.
from itofin.pricingengines import MCVarianceSwapEngine
engine = MCVarianceSwapEngine(process, steps=252, samples=1023, seed=42)
swap.set_engine(engine)
print(swap.variance(), swap.samples(), swap.variance_error(), swap.error_estimate())
Tolerance mode replaces samples=1023 with tolerance=1e-5, max_samples=50000.
Complete Python example.
engine, err := session.NewMCVarianceSwapEngine(process, itofin.MCVarianceSwapConfig{
Steps: 252, Samples: 1023, Seed: 42,
})
if err != nil { panic(err) }
defer engine.Close()
if err := swap.SetMCEngine(engine); err != nil { panic(err) }
Go/C zero-valued option selectors mean unset; Python uses None and rejects
explicit zero grid/sample selectors or tolerance. Tolerance mode uses
AbsoluteTolerance: 1e-5, MaxSamples: 50000 instead of Samples.
Complete Go example with all results and cleanup.
Ownership and recalculation¶
The engine retains its process, while the instrument retains its engine and Settings. C handles and Go objects are context/session-owned; close Go objects before their session. Python objects are thread-confined. Market edits invalidate cached prices; nonzero-seed recalculation restarts the stream. A failed live calculation does not expose stale or partial sampling results. Replication engines do not provide MC sample/error statistics.
Default maturity-day NPV and cash error estimate are zero; variance, sample count, variance error and weights are unavailable. Included maturity-day events still require positive pricing time. Changing the reference-date-event flag after an expired cache requires explicit recalculation because that setter does not notify.
Pinned source-built native fixtures include the original time-dependent 90-day native case, not only flat volatility.