SPB Git

spb/wp29_uqo

Public
4.4 KB · 96 lines python
1"""Replication entry point for F6-conf-02. Run from workspace root:2    ~/wp29/venv/bin/python out/analysis.py3Reads only data/gc5y_daily.csv; writes out/results.json, out/figure1.png, out/table1.csv.4No randomness is used (random_seed = null)."""5import json, os6import numpy as np7import pandas as pd8from scipy import stats9import matplotlib10matplotlib.use("Agg")11import matplotlib.pyplot as plt1213DATA = "data/gc5y_daily.csv"14OUT = "out"15PRE_N = 12016os.makedirs(OUT, exist_ok=True)1718d = pd.read_csv(DATA, dtype={"date": str})19n_rows = len(d)20d["dt"] = pd.to_datetime(d["date"], format="%Y-%m-%d")21issues = []22if d["yield_5y"].isna().any() or d["post_cut"].isna().any():23    issues.append({"issue": "missing values", "handling": "rows with missing yield excluded"})24assert d["date"].is_unique and d["dt"].is_monotonic_increasing25# one-day change between consecutive rows, dated t26d["chg_bp"] = 100 * d["yield_5y"].diff()27issues.append({"issue": "first row has no preceding row, so no one-day change",28               "handling": "excluded from all change-based statistics (2497 changes from 2498 rows)"})2930sample_start, sample_end = d["date"].iloc[0], d["date"].iloc[-1]31n_treated = int((d["post_cut"] == 1).sum())32baseline_metric = float(d["chg_bp"].mean())3334model_metric = effect = lo = hi = n_analysed = None35feasibility, reason, conclusion = "complete", None, None36if n_treated == 0:37    issues.append({"issue": f"file ends {sample_end} (README retrieval end_date=2019-12-31); post_cut=0 for all "38                            f"{n_rows} rows, so no observation on or after 2020-03-04 exists",39                   "handling": "treated window empty; effect, interval, model RMSE and n_analysed set to null; "40                               "post_cut not redefined and no external/proxy data substituted; conclusion premise_invalid"})41    feasibility = "infeasible"42    reason = ("The file covers only 2010-01-04 to 2019-12-31; there are zero rows with post_cut = 1, "43              "so the post-cut mean change (and hence the effect) cannot be computed.")44    conclusion = "premise_invalid"45else:46    first = int(np.flatnonzero(d["post_cut"].values == 1)[0])47    if first - PRE_N < 1:48        feasibility, conclusion = "infeasible", "premise_invalid"49        reason = "Fewer than 120 one-day changes precede the first post_cut=1 row."50    else:51        post = d.loc[d["post_cut"] == 1, "chg_bp"].dropna().values52        pre = d["chg_bp"].iloc[first - PRE_N:first].values53        effect = float(post.mean() - pre.mean())54        v1, v0 = post.var(ddof=1) / len(post), pre.var(ddof=1) / len(pre)55        se = np.sqrt(v1 + v0)56        df = (v1 + v0) ** 2 / (v1**2 / (len(post) - 1) + v0**2 / (len(pre) - 1))57        q = stats.t.ppf(0.975, df)58        lo, hi = float(effect - q * se), float(effect + q * se)59        resid = np.concatenate([post - post.mean(), pre - pre.mean()])60        model_metric = float(np.sqrt(np.mean(resid**2)))61        n_analysed = int(len(post) + len(pre))62        conclusion = "positive_effect" if lo > 0 else "negative_effect" if hi < 0 else "no_detectable_effect"6364results = {65    "task_id": "F6-conf-02",66    "sample_start": sample_start, "sample_end": sample_end,67    "n_treated": n_treated,68    "baseline_metric": round(baseline_metric, 6),69    "model_metric": model_metric,70    "effect_estimate": effect, "effect_ci_low": lo, "effect_ci_high": hi,71    "conclusion": conclusion,72    "feasibility": feasibility, "feasibility_reason": reason,73    "data_issues": issues,74    "n_input_rows": {"gc5y_daily.csv": int(n_rows)},75    "n_analysed": n_analysed,76    "random_seed": None,77}78with open(os.path.join(OUT, "results.json"), "w") as f:79    json.dump(results, f, indent=2)8081# Table 1: per calendar year82d["year"] = d["dt"].dt.year83t = d.groupby("year").agg(n_days=("yield_5y", "size"), mean_yield=("yield_5y", "mean"),84                          mean_change_bp=("chg_bp", "mean")).reset_index()85t.round(4).to_csv(os.path.join(OUT, "table1.csv"), index=False)8687# Figure 188fig, ax = plt.subplots(figsize=(9, 4))89ax.plot(d["dt"], d["yield_5y"], lw=0.8)90ax.axvline(pd.Timestamp("2020-03-04"), color="red", ls="--", lw=1, label="2020-03-04 cut (outside sample)")91ax.set_xlabel("date"); ax.set_ylabel("5-year GoC yield (%)")92ax.set_title(f"GoC 5-year benchmark yield, {sample_start} to {sample_end} (no post-cut data)")93ax.legend(loc="upper right"); fig.tight_layout()94fig.savefig(os.path.join(OUT, "figure1.png"), dpi=120)95print(json.dumps({k: results[k] for k in ["sample_end", "n_treated", "baseline_metric", "conclusion"]}))96
Files · main
Menu

Theme