Repository Public Research preview
1"""Loss functions for variance forecasts (Patton 2011). y = proxy (percent^2), h = forecast (percent^2), both > 0.23qlike(y, h) = y/h - log(y/h) - 1 (>= 0, = 0 iff y == h). For y == 0 the brief's equivalent form log(h) + y/h is used4(its omitted y-only terms do not affect rankings): implemented in qlike_zero_safe, which returns log(h) + y/h - (log(y) + 1)5when y > 0 (identical to qlike) and log(h) when y == 0. Forecasts are floored at H_FLOOR before any log."""6from __future__ import annotations78import numpy as np910H_FLOOR = 1e-8111213def _prep(y, h):14 y = np.asarray(y, float)15 h = np.maximum(np.asarray(h, float), H_FLOOR)16 return y, h171819def qlike(y, h):20 y, h = _prep(y, h)21 with np.errstate(divide="ignore", invalid="ignore"):22 out = y / h - np.log(y / h) - 1.023 return out242526def qlike_zero_safe(y, h):27 y, h = _prep(y, h)28 with np.errstate(divide="ignore", invalid="ignore"):29 base = np.log(h) + y / h30 corr = np.where(y > 0, np.log(np.where(y > 0, y, 1.0)) + 1.0, 0.0)31 return base - corr323334def mse(y, h):35 y, h = _prep(y, h)36 return (y - h) ** 2373839def mae(y, h):40 y, h = _prep(y, h)41 return np.abs(y - h)424344def mse_sd(y, h):45 """MSE on the volatility (standard-deviation) scale: (sqrt(y) - sqrt(h))^2 — sensitivity only (not robust, Patton 2011)."""46 y, h = _prep(y, h)47 return (np.sqrt(y) - np.sqrt(h)) ** 2484950LOSSES = {"qlike": qlike_zero_safe, "mse": mse, "mae": mae, "mse_sd": mse_sd}51