F3-conf-04 — Multi-horizon forecasts of Canadian quarterly CPI inflation
Question
Over 40 rolling quarterly origins, 2015-10-01 to 2025-07-01 (n_origins, first_origin, last_origin), does a time-series model forecast Canadian quarterly CPI inflation (400 × Δln of the quarterly-average NSA CPI) better than the seasonal-naive forecast at horizons 1, 2 and 4? And at h = 4, is the mean squared-error loss differential different from zero once we allow for the serial correlation that overlapping 4-step errors create?
Data and exclusions
data/cpi_quarterly.csv: 127 rows, 1995Q1–2026Q3 (n_input_rows).data/cpi_monthly.csv: 381 rows (n_input_rows), used only for the provenance audit. Both SHA-256 hashes matchdata/README.md. Averaging the monthly index by quarter reproducescpi_avg(max abs diff 3e-7), and 400·Δln reproducesinfl_annualised(max abs diff 3e-6). Neither file has duplicates or gaps (details inout/state/data_audit.md).- Exclusions (
out/exclusions.csv): one row removed, 1995Q1, because its inflation value is undefined. That leaves 126 analysable quarters (data_issues). - The 2022Q2 value (12.15 %) is a genuine part of the inflation surge. I kept it (
data_issues). - The last estimation sample (origin 2025Q3) has 121 regression observations (
n_analysed).
Method
- Baseline (seasonal naive): the forecast for target t+h is the value at t+h−4.
- Model (
model_name=ar_seas_aic):model_description. The regression has four quarter-of-year intercepts plus p lags of inflation. At each origin, AIC picks p from 0 to 8, comparing all candidates on a common sample. The chosen model is then re-estimated by OLS on every available quarter up to and including the origin. Forecasts for h = 2 and 4 are iterated from the one-step equation. At each origin the code cuts the series at the origin before doing any estimation or selection, so no later quarter is used (this is asserted inout/analysis.py). AIC chose p = 1 or 2 across origins (selected_lags_by_origin). - Evaluation: errors are e = actual − forecast. RMSE and MAE are taken over the 40 origins at each horizon.
- h = 4 test (Diebold–Mariano): d_t = e²_snaive,t − e²_model,t. Its mean is
loss_diff_mean_h4, and its standard error comes from a Bartlett-kernel (Newey–West) long-run variance (hac_kernel_h4) with truncation lag 3 = h−1 (hac_lags_h4). The test statistic isdm_stat_h4and its p-valuedm_pvalue_h4is two-sided against N(0,1). I fixed the lag and kernel before seeing any results. Nothing in the analysis is random (random_seed= null).
Results
| h | RMSE snaive | RMSE model | MAE snaive | MAE model | 1 − RMSE ratio |
|---|---|---|---|---|---|
| 1 | 2.849 (rmse_snaive_h1) |
2.193 (rmse_model_h1) |
2.137 (mae_snaive_h1) |
1.519 (mae_model_h1) |
0.230 (rel_improvement_rmse_h1) |
| 2 | 2.847 (rmse_snaive_h2) |
2.463 (rmse_model_h2) |
2.126 (mae_snaive_h2) |
1.553 (mae_model_h2) |
0.135 (rel_improvement_rmse_h2) |
| 4 | 2.882 (rmse_snaive_h4) |
2.343 (rmse_model_h4) |
2.181 (mae_snaive_h4) |
1.597 (mae_model_h4) |
0.187 (rel_improvement_rmse_h4) |
RMSE and MAE are in percentage points of annualised inflation. Over this window the model has lower RMSE and MAE than the seasonal-naive forecast at all three horizons. The RMSE reductions are 23 %, 13 % and 19 %.
At h = 4, the mean loss differential is d̄ = 2.818 squared pp (loss_diff_mean_h4), with HAC SE 2.086 (loss_diff_se_h4). That gives DM = 1.351 (dm_stat_h4) and a two-sided p = 0.177 (dm_pvalue_h4). The model's squared error was smaller at 29 of the 40 origins (n_loss_diff_positive_h4). At conventional levels, the h = 4 improvement cannot be distinguished statistically from zero.
Uncertainty
- The conclusion depends on the HAC choices (
sensitivity_h4). With Bartlett lag 4, p = 0.128. With a rectangular kernel at lag 3, p = 0.097. With the Harvey–Leybourne–Newbold small-sample correction and t(39) reference, p = 0.225. With Bartlett lag 6, p = 0.041. The SE shrinks as the lag grows, which means d_t has negative autocorrelations at higher lags. The lag-6 result was not pre-specified and is the only one below 0.05; I treat it as a sensitivity check, not as evidence. The pre-specified result (lag 3, p = 0.18) stands. - 40 overlapping observations is a small sample for long-run-variance estimation, so the normal approximation is rough. Squared-error losses are also strongly affected by the 2021–2023 inflation surge, so a handful of quarters drive much of d̄.
- No uncertainty is reported for the RMSE and MAE at h = 1 and 2. The task only asks for a formal test at h = 4.
Limitations and open issues
- I chose one model ahead of time and did not compare alternatives (SARIMA, direct forecasts) on the test window, so there is no search-induced bias. However, the results describe only this model.
- The errors are computed on the current data vintage, and a quarter is treated as known at the end of that quarter. No real-time validity is claimed. Actual CPI publication comes about three weeks later, and basket updates may have small effects.
- The DM test compares forecasts, not models. Both forecasts come from expanding-window estimates, and the model is not nested in the seasonal-naive forecast in any parameter sense, so applying standard DM asymptotics is reasonable but approximate.
- Feasibility: complete (
feasibility).