TeX 53.6%
Python 46.2%
1"""Robustness battery (Table VIII) from stored event files.23For each subsample/design variant, re-estimate (i) the market-wide baseline4ΔΔ breadth at h ∈ {5, 30} and (ii) the headline network differential at h=5,5with day-block bootstrap SEs:67 full full sample (reference)8 post-decimal events dated 2002+ (kills 1/8–1/16 tick regime)9 mid-day event minute in [10:00, 15:30) ET10 ex-announcement exclude 10:00±10min and 14:00–14:30 ET event minutes11 calm-years exclude 2008, 2009, 202012 crisis-years 2008, 2009, 2020 only13 |z|>=8, |z|>=12 nested source-magnitude thresholds14 ex-noncommon exclude sources flagged non-common (ticker heuristic)15 placebo-network network differential computed on placebo events only16 (falsification: should be ≈ 0)17 month-cluster full sample, bootstrap clustered by month instead of day1819Outputs: outputs/estimates/stage_f_robustness.json,20 outputs/tables/table8_robustness.{tex,csv}21"""2223from __future__ import annotations2425import json26from pathlib import Path2728import numpy as np29import polars as pl3031ROOT = Path(__file__).resolve().parents[1]32EV = ROOT / "outputs" / "estimates" / "events"33EV2 = ROOT / "outputs" / "estimates" / "events2"34UNIV = ROOT / "data" / "metadata" / "universe_monthly.parquet"35TAB = ROOT / "outputs" / "tables"36B = 50037SEED = 20260713383940def dd_boot(df, col, rng, cluster="date"):41 g = (df.filter(pl.col(col).is_not_null())42 .group_by(cluster, "kind")43 .agg(pl.col(col).sum().alias("s"), pl.len().alias("n"))44 .pivot(on="kind", index=cluster, values=["s", "n"]))45 need = ("s_real", "n_real", "s_placebo", "n_placebo")46 if any(c not in g.columns for c in need) or g.height < 10:47 return np.nan, np.nan, 048 g = g.fill_null(0)49 sr, nr = g["s_real"].to_numpy(), g["n_real"].to_numpy()50 sp, npb = g["s_placebo"].to_numpy(), g["n_placebo"].to_numpy()51 est = sr.sum() / max(nr.sum(), 1) - sp.sum() / max(npb.sum(), 1)52 idx = rng.integers(0, len(sr), size=(B, len(sr)))53 bs = (sr[idx].sum(1) / np.maximum(nr[idx].sum(1), 1)54 - sp[idx].sum(1) / np.maximum(npb[idx].sum(1), 1))55 return float(est), float(bs.std()), int(nr.sum())565758def one_boot(df, col, rng, kind="placebo"):59 """Single-arm mean with day bootstrap (for the placebo-network check)."""60 g = (df.filter((pl.col("kind") == kind) & pl.col(col).is_not_null())61 .group_by("date").agg(pl.col(col).sum().alias("s"), pl.len().alias("n")))62 s, n = g["s"].to_numpy(), g["n"].to_numpy()63 est = s.sum() / max(n.sum(), 1)64 idx = rng.integers(0, len(s), size=(B, len(s)))65 bs = s[idx].sum(1) / np.maximum(n[idx].sum(1), 1)66 return float(est), float(bs.std()), int(n.sum())676869def main() -> None:70 rng = np.random.default_rng(SEED)71 e1 = pl.concat([pl.read_parquet(p) for p in sorted(EV.glob("events_*.parquet"))72 if p.stat().st_size > 500], how="diagonal").with_columns(73 pl.col("date").str.slice(0, 4).cast(pl.Int32).alias("year"),74 pl.col("z").abs().alias("absz"),75 (pl.col("breadth_5") - pl.col("pre_breadth")).alias("db_5"),76 (pl.col("breadth_30") - pl.col("pre_breadth")).alias("db_30"),77 pl.col("date").str.slice(0, 7).alias("ym"))78 e2 = pl.concat([pl.read_parquet(p) for p in sorted(EV2.glob("events2_*.parquet"))79 if p.stat().st_size > 500], how="diagonal").with_columns(80 pl.col("date").str.slice(0, 4).cast(pl.Int32).alias("year"),81 pl.col("z").abs().alias("absz"),82 (pl.col("nbh_5") - pl.col("non_5")).alias("nd_5"),83 pl.col("date").str.slice(0, 7).alias("ym"))84 noncommon = (pl.read_parquet(UNIV)85 .filter(pl.col("flag_noncommon"))86 .select("month", "ticker").unique()87 .with_columns(pl.lit(True).alias("nc")))88 e1 = e1.join(noncommon, on=["month", "ticker"], how="left")89 e2 = e2.join(noncommon, on=["month", "ticker"], how="left")9091 CRISIS = [2008, 2009, 2020]92 subs = {93 "Full sample": (pl.lit(True), pl.lit(True)),94 "Post-decimalization (2002+)": (pl.col("year") >= 2002,) * 2,95 "Mid-day events (10:00–15:30)": (pl.col("mod").is_between(600, 929),) * 2,96 "Ex announcement windows": (97 ~(pl.col("mod").is_between(595, 615)98 | pl.col("mod").is_between(840, 870)),) * 2,99 "Calm years (ex 2008–09, 2020)": (~pl.col("year").is_in(CRISIS),) * 2,100 "Crisis years only": (pl.col("year").is_in(CRISIS),) * 2,101 "Source $|z|\\ge 8$": (pl.col("absz") >= 8,) * 2,102 "Source $|z|\\ge 12$": (pl.col("absz") >= 12,) * 2,103 "Ex non-common tickers": (pl.col("nc").is_null(),) * 2,104 }105 rows = []106 for label, (c1, c2) in subs.items():107 b5, s5, n5 = dd_boot(e1.filter(c1), "db_5", rng)108 b30, s30, _ = dd_boot(e1.filter(c1), "db_30", rng)109 nd, snd, nn = dd_boot(e2.filter(c2), "nd_5", rng)110 rows.append({"sample": label, "db5": b5, "db5_se": s5,111 "db30": b30, "db30_se": s30,112 "nd5": nd, "nd5_se": snd, "n": n5})113 print(f"{label:<32} ΔΔb5={b5*1e4:+.2f}({s5*1e4:.2f}) "114 f"ΔΔb30={b30*1e4:+.2f}({s30*1e4:.2f}) "115 f"net5={nd*1e4:+.1f}({snd*1e4:.1f}) n={n5:,}", flush=True)116117 # month-cluster bootstrap variant (full sample)118 b5, s5, n5 = dd_boot(e1, "db_5", rng, cluster="ym")119 nd, snd, _ = dd_boot(e2, "nd_5", rng, cluster="ym")120 rows.append({"sample": "Month-cluster bootstrap", "db5": b5, "db5_se": s5,121 "db30": None, "db30_se": None, "nd5": nd, "nd5_se": snd, "n": n5})122 print(f"month-cluster: ΔΔb5={b5*1e4:+.2f}({s5*1e4:.2f}) net5={nd*1e4:+.1f}({snd*1e4:.1f})")123124 # placebo-network falsification: nbh−non among placebos alone125 pe, ps, pn = one_boot(e2, "nd_5", rng, kind="placebo")126 rows.append({"sample": "Placebo events, neighbor diff", "db5": None,127 "db5_se": None, "db30": None, "db30_se": None,128 "nd5": pe, "nd5_se": ps, "n": pn})129 print(f"placebo network diff: {pe*1e4:+.1f}({ps*1e4:.1f})")130131 out = pl.DataFrame(rows)132 out.write_csv(TAB / "table8_robustness.csv")133 (ROOT / "outputs" / "estimates" / "stage_f_robustness.json").write_text(134 json.dumps(rows, indent=1))135136 def cell(v, s):137 if v is None:138 return "---"139 return f"{v*1e4:,.2f} ({s*1e4:,.2f})"140 lines = [141 "% Auto-generated by scripts/16_robustness.py — do not edit numbers.",142 "\\begin{table}[htbp]\\centering\\begin{adjustbox}{max width=\\textwidth}\\begin{threeparttable}",143 "\\caption{Robustness of the market-wide null and the network channel}",144 "\\label{tab:robustness}",145 "\\small\\begin{tabular}{lrrr}",146 "\\toprule",147 "Sample / design & $\\Delta\\Delta$Breadth$_{5}$ & "148 "$\\Delta\\Delta$Breadth$_{30}$ & Network diff$_{5}$ \\\\",149 "\\midrule"]150 for r in rows:151 lines.append(f"{r['sample']} & {cell(r['db5'], r['db5_se'])} & "152 f"{cell(r['db30'], r['db30_se'])} & "153 f"{cell(r['nd5'], r['nd5_se'])} \\\\")154 lines += [155 "\\bottomrule\\end{tabular}",156 "\\begin{tablenotes}[flushleft]\\footnotesize",157 "\\item Notes: All entries $\\times 10^{-4}$, day-block bootstrap SEs in",158 "parentheses (500 reps; final row of the market-wide block uses",159 "month-cluster resampling). $\\Delta\\Delta$Breadth = abnormal market-wide",160 "breadth (real $-$ placebo, post $-$ pre). Network diff = neighbor $-$",161 "non-neighbor abnormal breadth at $h{=}5$. `Placebo events' row reports",162 "the neighbor differential among placebo events alone (falsification;",163 "expected $\\approx 0$).",164 "\\end{tablenotes}\\end{threeparttable}\\end{adjustbox}\\end{table}"]165 (TAB / "table8_robustness.tex").write_text("\n".join(lines))166 (ROOT / "paper" / "tables" / "table8_robustness.tex").write_text("\n".join(lines))167 print("robustness table written")168169170if __name__ == "__main__":171 main()172