Conformal VaR (vetted.conformal)¶
Historical-simulation VaR takes an empirical quantile and hopes. Split conformal prediction takes the same quantile with a (n + 1) correction and gets a guarantee: if the calibration days and the next day are exchangeable, the next loss exceeds the VaR with probability at most alpha, with no distributional assumption.
from vetted import conformal
v = conformal.conformal_var(last_250_days_pnl, alpha=0.01)
With a volatility forecast (GARCH, EWMA, anything), calibration runs on standardised losses and the result is that model's shape with a coverage that is guaranteed rather than assumed:
v = conformal.conformal_var(pnl, 0.01, scale=vol_history, next_scale=vol_tomorrow)
Adaptive conformal VaR¶
Markets are not exchangeable for long. adaptive_var produces
out-of-sample forecasts that steer their level online (Gibbs and Candes
2021), so the long-run exception rate converges to alpha whatever the data
do:
out = conformal.adaptive_var(pnl, alpha=0.01, window=250, gamma=0.005, scale=ewma_vol)
out["var"], out["exception_rate"], out["bound"], out["guarantee_holds"]
- With
unbounded="inf"the formal bound holds for any sequence. - With the default
unbounded="max_loss", a forecast that would be infinite is capped at the window's largest loss so it stays usable. If a capped forecast is then breached, the guarantee no longer applies, and the result says so inguarantee_holds(withcapped_daysandcapped_exceptions).
Example¶
In examples/risk_model_validation.py, 20 simulated 1250-day histories of a
GARCH desk with fat tails: historical simulation failed validation 17 times,
RiskMetrics EWMA 16 times, the same EWMA volatility with an adaptive conformal
quantile 0 times, and the true model once. In 4 of the 20 histories the
conformal forecast hit its cap and was breached, so its formal guarantee did
not apply there. This is one simulated process, not a general result.