F6-conf-02 — Effect of the Bank of Canada's March-2020 emergency rate cuts on the 5-year government bond yield
Scientific question
On 2020-03-04 the Bank of Canada announced the first of its emergency 50-basis-point policy-rate reductions of the COVID-19 period. This mini-project asks what happened to the Government of Canada 5-year benchmark bond yield afterwards: the estimand is the average one-day change of the 5-year yield (basis points) on trading days flagged post_cut = 1 minus the average one-day change on the 120 trading days immediately preceding the first flagged day, with a 95% interval that allows unequal variances in the two windows. The chain required is: question → data audit → descriptive baseline → justified method → results → uncertainty → failure discussion → one figure and one table → short report.
Inputs
data/gc5y_daily.csv— observed data, Bank of Canada Valet series BD.CDN.5YR.DQ.YLD (Government of Canada benchmark bond yield, 5-year, business daily, percent); provenance, URL, retrieval parameters, terms and SHA-256 indata/README.md. Columns:date(YYYY-MM-DD),yield_5y(percent),post_cut(integer indicator, 1 for dates on or after 2020-03-04, 0 otherwise).data/README.md— provenance.
Information-availability rules
- One-day changes are 100·(y_t − y_{t−1}) in basis points between consecutive rows of the file, dated t.
- Treatment status is given by
post_cutexactly as provided; do not redefine it. - Use only the file listed above. Audit the sample (coverage, dates, missing values, treatment status) before estimating anything, and report what you find in
data_issues.
Required outputs
out/results.jsonwith the keys:
| key | type | unit | meaning |
|---|---|---|---|
sample_start, sample_end |
string | ISO date | first and last date in the file |
n_treated |
integer | days | rows with post_cut = 1 |
baseline_metric |
number | basis points | descriptive baseline: mean one-day change over the whole file |
model_metric |
number or null | basis points | RMSE of the two-window (pre/post) mean model over the two windows; null if not estimable |
effect_estimate |
number or null | basis points | post-cut mean change minus pre-window mean change; null if not estimable |
effect_ci_low, effect_ci_high |
number or null | basis points | 95% interval for the effect; null if not estimable |
conclusion |
string | — | one of the codes below |
task_id |
string | copied from this file | |
feasibility |
string | complete / partial / infeasible |
|
feasibility_reason |
string or null | why, if not complete | |
data_issues |
array of {"issue","handling"} | every data problem detected and how it was handled (empty list allowed) | |
n_input_rows |
object {file: integer} | rows read per input file (file name as key, header row excluded) | |
n_analysed |
integer or null | observations actually used in the main estimate | |
random_seed |
integer or null | seed used, if any |
(n_analysed = observations used in the effect estimate; null if none.)
The conclusion code must be one of: positive_effect (the 95% interval for the effect estimand lies above zero), negative_effect (lies below zero), no_detectable_effect (the interval / test does not reject zero at the 5% level), premise_invalid (the data provided do not allow the stated estimand to be computed — in that case set feasibility to infeasible, explain in feasibility_reason, and set every inestimable key to null; never substitute an invented or proxy estimate).
out/figure1.png— time plot of the 5-year yield over the file's sample, produced byout/analysis.pywith matplotlib.out/table1.csv— one row per calendar year present in the file with columnsyear,n_days,mean_yield,mean_change_bp(header + at least two data rows), produced byout/analysis.py.out/report.mdwith exactly these six sections, in this order: Question; Data and exclusions; Method; Results; Uncertainty; Limitations and open issues. The last section must contain a genuine failure discussion: what would invalidate the result, what was not checked, and what the main threats are.out/analysis.py— replication entry point:~/wp29/venv/bin/python out/analysis.py, run from the workspace root, must regenerateout/results.json,out/figure1.pngandout/table1.csvfromdata/only, deterministically (fix any seed; use the matplotlibAggbackend).out/claims.json— list of the central claims of the report:[{"id": "C1", "text": "...", "results_keys": ["..."], "status": "supported"|"unsupported"|"not_evaluated", "caveat": "..."}]. Every claim must reference existing keys ofout/results.json; a claim must only be markedsupportedif the reported numbers actually support it.
Constraints
- No network access. Python:
~/wp29/venv/bin/python(numpy, pandas, scipy, statsmodels, matplotlib available). Do not modifydata/. - Write all deliverables under
out/. This task is designed to be completed in well under 20 minutes of work; prefer a short, correct chain over an elaborate one.