# F6-conf-02 — BoC March-2020 emergency cut and the GoC 5-year yield ## Question What was the average one-day change (bp) of the Government of Canada 5-year benchmark yield on days flagged `post_cut = 1` (on or after 2020-03-04), minus the average over the 120 trading days before the first flagged day? The interval is a 95% Welch (unequal-variance) interval. ## Data and exclusions `data/gc5y_daily.csv` (Bank of Canada Valet BD.CDN.5YR.DQ.YLD). The SHA-256 matches the README, and 2498 rows were read (`n_input_rows`). The sample runs from `sample_start` = 2010-01-04 to `sample_end` = 2019-12-31. There are no missing values and no duplicate dates, and the dates are strictly increasing. The calendar gaps are weekends and holidays (`data_issues`). **Critical finding:** `n_treated` = 0. Every row has `post_cut = 0`, because the README's retrieval request used `end_date=2019-12-31`, which is before the 2020-03-04 event. The flag matches its stated rule on every row; it just has nothing to flag. Exclusions (`out/exclusions.csv`): the first row has no prior row, so 2497 changes remain. The treated and pre windows are empty or undefined, so 0 observations are analysed (`n_analysed` = null). ## Method - Changes: 100·(y_t − y_{t−1}) between consecutive rows. - Baseline: the mean change over the whole file. - Planned model: a two-window mean model (the pre-window is the 120 rows before the first `post_cut = 1` row; the post-window is all flagged rows). The effect is the difference in means, with a Welch t interval and Welch–Satterthwaite degrees of freedom. RMSE is the root mean squared deviation from each window's own mean. `out/analysis.py` implements this model in general form. When the treated window is empty it returns nulls. I checked that the code runs only on a throwaway copy of the data with an artificial flag; those numbers are not results and are not reported. No randomness is used (`random_seed` = null). ## Results - `baseline_metric` = −0.043 bp mean daily change over 2010–2019 (`baseline_n_changes` = 2497, sd `baseline_sd_change_bp` ≈ 4.24 bp). - `effect_estimate`, `effect_ci_low`, `effect_ci_high` and `model_metric` are all null. - `conclusion` = `premise_invalid`, `feasibility` = `infeasible` (`feasibility_reason`). `out/table1.csv` gives yearly counts, mean yield and mean change for 2010–2019. `out/figure1.png` plots the yield series, which ends before the event. ## Uncertainty No interval can be given for the effect because there are no post-cut observations. The baseline is a descriptive mean only. Its sampling error (about 4.24/√2497 ≈ 0.08 bp under independence) is larger than the mean itself. ## Limitations and open issues - **Why the task fails:** the file does not cover the event. With `n_treated` = 0, both windows in the estimand (the post-cut days, and the 120 days before the first flagged day) are undefined. I deliberately did not substitute any of the following, because each would be a different estimand or would break the information rules: - a proxy, such as the last 120 days of 2019 compared with an earlier window; - a placebo cut date; - outside 2020 data. - **What would invalidate a result, even with correct data:** - The March 2020 cuts happened at the same time as the global COVID-19 market shock, the Fed's emergency cuts and BoC asset purchases (from late March 2020). A pre/post difference in means cannot attribute yield changes to the BoC cut. - The post window is open-ended (all dates after the cut), so its mean mixes the announcement response with months of later dynamics. - Daily changes in March 2020 were very volatile and probably autocorrelated and fat-tailed. A Welch interval assumes independent observations and could be too narrow. - The cut was partly anticipated after the Fed's 2020-03-03 move. - **Not checked:** - I did not check the yield values against any external source (no network access, and only the provided file may be used). - I did not check for data revisions in Valet. - **To fix:** re-retrieve the series with an end_date after 2020-03-04, for example `end_date=2020-12-31`, and re-run `out/analysis.py`. It would then compute the estimand without any code changes.