giacomini_white#
- cultivars.forecast.comparison.giacomini_white(losses_a, losses_b, *, horizon=1, lags=1, instruments=None)[source]#
Giacomini-White (2006) test that a loss gap was predictable at the origin.
The conditional null \(\mathbb{E}[d_t \mid \mathcal{F}_{t-h}] = 0\) is tested through the instruments \(h_t\): a constant,
lagslagged differentials, and whatever the caller adds, via the Wald statistic\[\mathrm{GW} = T\, \bar z^\top \hat\Omega^{-1} \bar z, \qquad z_t = h_t\, d_t, \qquad \mathrm{GW} \sim \chi^2_{\dim h}\]under the null, with \(\hat\Omega\) the uncentered sample covariance of \(z_t\) at one step and Bartlett HAC beyond. Because a loss indexed by its origin is only realized
horizonsteps later, the lagged differentials start at \(d_{t - h}\) – the most recent one actually known – rather than \(d_{t-1}\), and the sample drops its firsthorizon + lags - 1origins.lags=0with no instruments is the unconditional test, a chi-squared cousin of Diebold-Mariano.The test is built for rolling-window estimation, where parameter estimates never converge and the forecasting method – model, window, estimator – is what the null is about; under a recursive scheme the null drifts as the window grows. Use
ForecastComparisonfor the unconditional question with the small-sample correction. At one step the size is close to nominal from 100 origins on; at multi-step horizons the truncated Bartlett kernel understates the moment covariance and the test over-rejects mildly (about 7-9% at nominal 5% for a four-step horizon), which the record’s notes say.- Parameters:
losses_a (
ArrayLike) –(T,)losses of the first forecaster, one per evaluation origin, negatively oriented.losses_b (
ArrayLike) –(T,)losses of the second, aligned origin by origin.horizon (
int) – The forecast horizon behind the losses; sets both the instrument lag and the HAC window.lags (
int) – Lagged differentials among the instruments.instruments (
ArrayLike|None) – Optional(T,)or(T, m)further instruments, each row known at its origin – a regime indicator, a volatility proxy, the sign of the last error. The caller vouches for measurability; the function cannot.
- Return type:
- Returns:
The
GiacominiWhiteTest.- Raises:
DimensionError – If the series or instruments do not align.
SpecificationError – If there are too few origins, the horizon or
lagsis invalid, or the series are numerically identical.NumericalError – If a series is not finite or the instruments are collinear.
Note
Caller instruments are aligned to the full
(T,)series and trimmed with it, soinstruments[t]must be known at origint, before the loss attis realized; an instrument that peeks at the outcome makes the gap predictable by construction. A constant caller instrument duplicates the built-in constant and is refused as collinear. The retained sample must hold at least eight origins,2 * horizon + 1, and twice the instrument count, whichever is largest.See also
GiacominiWhiteTest– the record, with the decision rule.ForecastComparison– this test on the default instruments beside the unconditional ones.
References
Giacomini, R., & White, H. (2006). Tests of conditional predictive ability. Econometrica, 74(6), 1545-1578.
Example
Two forecasters whose loss gap reverses with a regime; the regime as instrument makes the reversal predictable, and the constant-only test, which is the unconditional one, sees only the near-zero average:
>>> import numpy as np >>> rng = np.random.default_rng(0) >>> regime = np.repeat([1.0, -1.0], 100) >>> a = rng.standard_normal(200) ** 2 + 0.6 * regime >>> b = rng.standard_normal(200) ** 2 - 0.6 * regime >>> verdict = giacomini_white(a, b, instruments=regime) >>> bool(verdict.pvalue < 0.01), verdict.instruments, verdict.df, verdict.nobs (True, 'constant, d[t-1], z1', 3, 199) >>> unconditional = giacomini_white(a, b, lags=0) >>> bool(unconditional.pvalue > 0.1), unconditional.instruments, unconditional.nobs (True, 'constant', 200) >>> giacomini_white(a, b, horizon=2, lags=2).instruments 'constant, d[t-2], d[t-3]'