SPB Git forge

spb/wp15_uqo

Public MIT
3commits 1branches 1releases
7.6 MBsize
maindefault branch
52 min agolast push
TeX 53.6% Python 46.2%
9.5 KB · 191 lines python
Raw Blame History
1"""Generate paper/results_macros.tex from saved machine-readable outputs.23Every numerical claim in the manuscript resolves to a macro defined here4(CLAUDE.md §26.5). Rerun after any estimation stage; compile refuses stale5numbers by construction because macros are the only path into the text.6"""78from __future__ import annotations910import json11from pathlib import Path1213import polars as pl1415ROOT = Path(__file__).resolve().parents[1]16OUTE = ROOT / "outputs"17M = []181920def macro(name: str, value: str) -> None:21    M.append(f"\\newcommand{{\\{name}}}{{{value}}}")222324def num(x, nd=0):25    return f"{x:,.{nd}f}"262728def main() -> None:29    # ---- data scale (stage C summary)30    sc = json.loads((OUTE / "diagnostics/stage_c/stage_c_summary.json").read_text())31    macro("DataRows", num(sc["total_rows"]))32    macro("DataRowsBn", f"{sc['total_rows']/1e9:.2f}")33    macro("DataTickers", num(sc["tickers_total"]))34    macro("DataSpells", num(sc["spells_total"]))35    macro("DataOHLCViol", num(sc["total_ohlc_violations"]))36    macro("DataDupKeys", num(sc["total_duplicate_keys"]))37    macro("DataMultiSpellTickers", num(sc["multi_spell_tickers"]))3839    # ---- splits (stage D)40    ev = pl.read_parquet(OUTE / "diagnostics/stage_d/split_events.parquet")41    fwd = int(ev["event"].str.starts_with("split").sum())42    macro("NSplitEvents", num(ev.height))43    macro("NSplitFwd", num(fwd))44    macro("NSplitRev", num(ev.height - fwd))4546    # ---- extreme minute returns (fig E5 source)47    e5 = pl.read_csv(OUTE / "figures/data/figE5_extreme_minutes.csv")48    g1_90s = e5.filter(pl.col("year").is_between(1992, 1999))["gt1"].mean() * 1e449    g1_10s = e5.filter(pl.col("year").is_between(2010, 2019))["gt1"].mean() * 1e450    g5_1719 = e5.filter(pl.col("year").is_between(2017, 2019))["gt5"].mean() * 1e451    g5_20 = e5.filter(pl.col("year") == 2020)["gt5"].mean() * 1e452    macro("ExtremeGtOneNineties", num(g1_90s, 0))53    macro("ExtremeGtOneTens", num(g1_10s, 1))54    macro("ExtremeDropFactor", num(g1_90s / g1_10s, 0))55    macro("ExtremeGtFivePreCovid", f"{g5_1719:.3f}")56    macro("ExtremeGtFiveCovid", num(g5_20, 1))57    macro("ExtremeCovidFactor", num(g5_20 / g5_1719, 0))5859    # ---- Epps (fig E8 source)60    ep = pl.read_csv(OUTE / "diagnostics/stage_e/epps_curves.csv")61    def epv(y, k):62        return ep.filter((pl.col("year") == y) & (pl.col("agg_minutes") == k)63                         )["mean_pairwise_corr"][0]64    macro("EppsNinetySixOne", f"{epv(1996,1):.3f}")65    macro("EppsNinetySixThirty", f"{epv(1996,30):.2f}")66    macro("EppsFifteenOne", f"{epv(2015,1):.2f}")67    macro("EppsFifteenThirty", f"{epv(2015,30):.2f}")68    macro("EppsTwentyFourOne", f"{epv(2024,1):.2f}")69    macro("EppsTwentyFourThirty", f"{epv(2024,30):.2f}")7071    # ---- stage F baseline72    f1 = json.loads((OUTE / "estimates/stage_f_baseline.json").read_text())73    macro("NEventsReal", num(f1["n_events_real"]))74    macro("NEventsRealMM", f"{f1['n_events_real']/1e6:.2f}")75    macro("NEventsPlacebo", num(f1["n_events_placebo"]))76    for r in f1["baseline"]:77        if r["h"] in (5, 30):78            tag = "Five" if r["h"] == 5 else "Thirty"79            macro(f"DDBreadth{tag}", f"{r['dd_breadth']*1e4:.2f}")80            macro(f"DDBreadth{tag}SE", f"{r['se_breadth']*1e4:.2f}")81    grad = {g["group"]: g for g in f1["gradient_state"]}82    macro("DDGradLargest", f"{grad['12–20']['dd']*1e4:.2f}")83    macro("DDGradLargestSE", f"{grad['12–20']['se']*1e4:.2f}")8485    # ---- stage F2 (if available)86    f2p = OUTE / "estimates/stage_f2.json"87    if f2p.exists():88        f2 = json.loads(f2p.read_text())89        nw = {(r["scope"], r["h"]): r for r in f2["network"]}90        for h, tag in [(5, "Five"), (15, "Fifteen"), (30, "Thirty")]:91            macro(f"NetDiff{tag}", f"{nw[('all',h)]['dd']*1e4:.1f}")92            macro(f"NetDiff{tag}SE", f"{nw[('all',h)]['se']*1e4:.1f}")93        macro("NetDiffFiveNineties", f"{nw[('1992–1999',5)]['dd']*1e4:.0f}")94        macro("NetDiffFiveOughts", f"{nw[('2000–2009',5)]['dd']*1e4:.0f}")95        macro("NetDiffFiveTens", f"{nw[('2010–2019',5)]['dd']*1e4:.0f}")96        macro("NetDiffFiveTwenties", f"{nw[('2020–2026',5)]['dd']*1e4:.0f}")97        cm = {(r["scope"], r["h"]): r for r in f2["cumulative"]}98        macro("CumThirty", f"{cm[('all',30)]['dd']*1e4:.1f}")99        macro("CumThirtySE", f"{cm[('all',30)]['se']*1e4:.1f}")100        cj = pl.DataFrame(f2["cojumps_yearly"])101        def sev(y):102            return cj.filter(pl.col("year") == y)["mean_share4"][0] * 100103        macro("CoJumpSevCalm",104              f"{cj.filter(pl.col('year').is_in([2015,2017,2019]))['mean_share4'].mean()*100:.1f}")105        macro("CoJumpSevGFC", f"{sev(2008):.1f}")106        macro("CoJumpSevCovid", f"{sev(2020):.1f}")107        sv = cj.filter(pl.col("year") >= 2013)108        macro("SevereCovid",109              f"{cj.filter(pl.col('year')==2020)['severe_per1000'][0]:.1f}")110        macro("SeverePreCovid",111              f"{cj.filter(pl.col('year').is_in([2017,2018,2019]))['severe_per1000'].mean():.2f}")112        macro("SevereGFC", f"{cj.filter(pl.col('year')==2008)['severe_per1000'][0]:.1f}")113        macro("SevereEarlyNineties",114              f"{cj.filter(pl.col('year').is_between(1992,1997))['severe_per1000'].mean():.0f}")115        macro("CoJumpSevEarlyNineties",116              f"{cj.filter(pl.col('year').is_between(1992,1997))['mean_share4'].mean()*100:.1f}")117        macro("CoJumpPerThousandRecent",118              f"{cj.filter(pl.col('year').is_between(2021,2025))['per1000'].mean():.0f}")119120121    # ---- zero-return share (fig E7 source) and post-decimalization extremes122    e7 = pl.read_csv(OUTE / "figures/data/figE7_zeroret.csv")123    macro("ZeroRetNinetySix", f"{e7.filter(pl.col('year')==1996)['zero_pct'][0]:.0f}")124    macro("ZeroRetTwentyFour", f"{e7.filter(pl.col('year')==2024)['zero_pct'][0]:.0f}")125    macro("ExtremeGtOneTwoThousandTwo", num(e5.filter(pl.col("year") == 2002)["gt1"][0] * 1e4, 0))126    macro("ExtremeGtOneNinetyTwo", num(e5.filter(pl.col("year") == 1992)["gt1"][0] * 1e4, 0))127128    # ---- revision checks (scripts/17_revision_checks.py, 2026-10-17)129    rcp = OUTE / "estimates/revision_checks.json"130    if rcp.exists():131        rc = json.loads(rcp.read_text())132        pb = rc["pre_event"]["breadth"]133        macro("PreBreadthReal", num(pb["real"] * 1e4, 0))134        macro("PreBreadthPlacebo", num(pb["placebo"] * 1e4, 0))135        macro("PreBreadthDiff", f"{pb['diff']*1e4:.1f}")136        macro("PreBreadthDiffSE", f"{pb['se']*1e4:.1f}")137        pi_ = rc["pre_event"]["intensity"]138        macro("PreIntensityDiff", f"{pi_['diff']:.3f}")139        macro("PreIntensityDiffSE", f"{pi_['se']:.3f}")140        br = rc["base_rates"]141        macro("BaseBreadthShare", f"{br['placebo_breadth_5']:.2f}")142        macro("NEligMean", num(br["nelig_5_mean"], 0))143        macro("NEligNineties", num(br["nelig_5_by_decade"]["1992–1999"], 0))144        macro("EventsPerStockWeek", f"{br['events_per_stock_week']:.1f}")145        macro("EventDays", num(br["event_days"]))146        macro("NeighborBaseShare", f"{br['placebo_nbh_5']:.2f}")147        macro("MatchRate", f"{br['match_rate']*100:.1f}")148        macro("MatchRateNineties", f"{br['match_rate_by_decade']['1992–1999']*100:.0f}")149        macro("MatchRateMinPost", f"{min(v for k, v in br['match_rate_by_decade'].items() if k != '1992–1999')*100:.0f}")150        macro("CumBaseFifteen", f"{br['placebo_cum_15']*100:.0f}")151        mde = 2.8 * f1["baseline"][2]["se_breadth"]  # h=5, 5% size / 80% power152        macro("MDEFive", f"{mde*1e4:.1f}")153        macro("MDEEventsPer", num(1.0 / (mde * br["nelig_5_mean"]), 0))154        ca = rc["coarrival"]155        macro("ShareSingleton", f"{ca['share_by_class']['1']*100:.0f}")156        macro("MeanCoArrival", f"{ca['mean_events_per_event_minute']:.1f}")157        cls = {r["cls"]: r for r in ca["by_class"]}158        macro("DDSingletonFive", f"{cls['1']['db5']*1e4:.1f}")159        macro("DDSingletonFiveSE", f"{cls['1']['db5_se']*1e4:.1f}")160        macro("DDSingletonThirty", f"{cls['1']['db30']*1e4:.1f}")161        macro("DDSingletonThirtySE", f"{cls['1']['db30_se']*1e4:.1f}")162        macro("DDMultiThirty", f"{cls['3–5']['db30']*1e4:.1f}")163        macro("DDMultiThirtySE", f"{cls['3–5']['db30_se']*1e4:.1f}")164        macro("NetDiffSingleton", f"{cls['1']['nd5']*1e4:.0f}")165        macro("NetDiffSingletonSE", f"{cls['1']['nd5_se']*1e4:.1f}")166        st = {r["h"]: r for r in rc["stratified"]}167        macro("PostDiffFive", f"{st[5]['post_diff']*1e4:.0f}")168        macro("StratFive", f"{st[5]['strat']*1e4:.0f}")169        macro("StratFiveSE", f"{st[5]['strat_se']*1e4:.1f}")170        macro("StratThirty", f"{st[30]['strat']*1e4:.0f}")171        macro("StratThirtySE", f"{st[30]['strat_se']*1e4:.1f}")172        macro("StratShareOfBase", f"{st[5]['strat']/br['placebo_breadth_5']*100:.0f}")173        macro("NetDiffFiveTickerSE", f"{rc['cluster']['nd5']['se_ticker']*1e4:.1f}")174        bs = {r["sign"]: r for r in rc["network_by_sign"]}175        macro("NetDiffNeg", f"{bs['negative']['dd']*1e4:.0f}")176        macro("NetDiffPos", f"{bs['positive']['dd']*1e4:.0f}")177        nc = {r["scope"]: r for r in rc["network_components"]}178        macro("NetRealNdNineties", f"{nc['1992–1999']['real_nd_5']*1e4:.0f}")179        macro("NetPlaceboNdNineties", f"{nc['1992–1999']['placebo_nd_5']*1e4:.0f}")180        macro("NetRealNdTens", f"{nc['2010–2019']['real_nd_5']*1e4:.0f}")181        macro("NetPlaceboNdTens", f"{nc['2010–2019']['placebo_nd_5']*1e4:.0f}")182183    tex = "% Auto-generated by scripts/15_build_results_macros.py — DO NOT EDIT.\n"184    tex += "\n".join(M) + "\n"185    (ROOT / "paper" / "results_macros.tex").write_text(tex)186    print(f"{len(M)} macros written")187188189if __name__ == "__main__":190    main()191