# 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 regenerates `out/results.json`, `out/forecasts.csv` and `out/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.