F3-conf-01 — Forecasting Canadian monthly GDP y/y growth under publication lags
Question
At the end of each month t (48 origins, 2022-05-01 to 2026-04-01; n_origins, first_origin, last_origin), how well can the year-over-year growth of Canadian monthly real GDP for month t+1 and t+3 be forecast using only data published by then? And does a model that also uses the more timely LFS employment growth beat the naive forecast (the latest published GDP growth, gdp_yoy(t−2))?
Data and exclusions
- Input:
data/canada_gdp_employment.csv: 345 rows (n_input_rows), 1998-01 to 2026-09. The SHA-256 matches the README. There are no duplicate months and no gaps. GDP is missing only for 2026-08 and 2026-09, which were not yet published. Full audit:out/state/data_audit.md; detected issues:data_issues. - Publication lags are enforced inside every origin loop. GDP is used only for months ≤ t−2 and employment only for months ≤ t−1. At the last origin, this means GDP up to 2026-02-01 (
last_target_date_available) and employment up to 2026-03-01 (last_predictor_date_available). - Exclusions for the last estimation sample (origin 2026-04, h=1;
out/exclusions.csv):- 7 months removed by the publication-lag rule.
- 3 removed because their lags are not in the file.
- 25 removed by a COVID-window rule. Before looking at any out-of-sample errors, I decided to drop training pairs whose target or regressor month falls in 2020-03..2021-12.
- That leaves 345 − 35 = 310 observations (
n_analysed); for h=3 it is 306 (n_analysed_last_origin_h3).
- The naive forecast drops no observations.
Method
- Naive: forecast = gdp_yoy(t−2) for both horizons.
- Model
ardl_emp_direct(model_name,model_description): a direct h-step OLS regression, fitted separately for each horizon and origin:- Equation: y(m) = a + b·y(m−h−2) + c·emp_yoy(m−h−1) + e.
- Estimation: expanding window from 1998, using only target months ≤ t−2, with the COVID-window exclusion above.
- Forecast: plug in y(t−2) and emp_yoy(t−1). This uses the one-month timeliness advantage of the LFS.
- Model choices were fixed in advance; I did not tune the model on the evaluation errors.
- Errors are forecast − actual, measured against current-vintage gdp_yoy.
- No randomness is involved (
random_seed= null). - Replication:
~/wp29/venv/bin/python out/analysis.py. It regeneratesout/results.json,out/forecasts.csvandout/exclusions.csv.
Results
| horizon | RMSE naive | MAE naive | RMSE model | MAE model | 1 − RMSE ratio |
|---|---|---|---|---|---|
| h=1 | 0.814 (rmse_naive_h1) |
0.642 (mae_naive_h1) |
0.743 (rmse_model_h1) |
0.604 (mae_model_h1) |
0.087 (rel_improvement_rmse_h1) |
| h=3 | 1.140 (rmse_naive_h3) |
0.872 (mae_naive_h3) |
0.902 (rmse_model_h3) |
0.753 (mae_model_h3) |
0.208 (rel_improvement_rmse_h3) |
All values are in percentage points, except the last column, which is a fraction.
- The employment-augmented model has lower RMSE and MAE than the naive forecast at both horizons: about 9% lower RMSE at h=1 and about 21% lower at h=3.
- The naive forecast gets worse as the horizon grows, as expected.
Uncertainty
I compared the two models' squared-error losses with a Diebold–Mariano test (Harvey small-sample correction, HAC variance with h−1 lags, n=48):
- h=1: DM = −2.03, p = 0.048 (
dm_stat_h1,dm_pvalue_h1). This is borderline significant at 5%. - h=3: DM = −1.35, p = 0.18 (
dm_stat_h3,dm_pvalue_h3). This is not significant. The overlapping 3-step errors and only 48 origins give limited power.
Sensitivity check: keeping the COVID window in the training sample changes the improvement to 0.012 at h=1 (sens_rel_improvement_rmse_nocovidexcl_h1) and 0.304 at h=3 (sens_rel_improvement_rmse_nocovidexcl_h3). The size of the gain therefore depends noticeably on how the pandemic observations are treated. Only its sign holds in both specifications.
Limitations and open issues
- The data are the current (revised) vintage. The exercise simulates publication timing only. The errors are not real-time errors, and no real-time validity is claimed.
- There are 48 origins in a single post-pandemic period (2022–2026), so the evaluation sample is small and the gains are not statistically robust, particularly at h=3.
- The COVID exclusion window is a judgement call made in advance. The sensitivity results show it matters for how large the gain is.
- The README says gdp_yoy is empty for the first 12 months, but the file has values from 1998-01. I used the values as given (
data_issues). - Only one model was evaluated, as the task requires. No model search was done.