"""_baltussen_recheck_20261018.py -- audit of Antigravity's _test_baltussen_gamma_hedging.py (Claude, 2026-10-18).
Report-only, 0 ledger: no new candidate, the family is already KILLED. Question: is the kill right, and was the test the paper?

Fixes against the original script:
  1. Returns in bps of the entry price, not raw index points (NQ went from ~2,000 to ~21,000 in the sample, so a t-test on
     points is a test of 2020-2025 only, and a fixed 1.0 pt cost is 10x heavier in 2011 than in 2025).
  2. The paper's spec next to Antigravity's: Baltussen, Da, Lammers, Martens (JFE 2021) predict the last 30 minutes
     (15:30-16:00) with the rest-of-day return (prior 16:00 close -> 15:30). Gao, Han, Li, Zhou (JFE 2018) use the first
     half hour (prior close -> 10:00). Antigravity used 10:00 -> 15:00 predicting 15:00 -> 16:00, which is neither.
  3. The gamma conditioning (sign of dealer net gamma) needs option open interest; we have none, so the mechanism itself
     cannot be tested here. Only the unconditional momentum is tested.
  4. G9-style yardstick: mean / sd of the hold return = expectancy in R if the stop sat at 1 sd of the hold move.
     The +0.05R entry floor applies to that number.
Clock (G10): the 09:30 ET volatility spike sits at 09:30 in January and July, so the `est` column is ET with DST.
Data: quantlab/data/inbox/new_markets/{nsx,spx}usd_m1_est.parquet, 2010-11 -> 2025-12-31."""
from __future__ import annotations
import os
import numpy as np, pandas as pd
from scipy import stats

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
FILES = {"NQ (NSXUSD)": "nsxusd_m1_est.parquet", "SPX (SPXUSD)": "spxusd_m1_est.parquet"}
# [withheld: refers to the lab's private live strategy]
COST_BP = {"NQ (NSXUSD)": 1.45 / 30000 * 1e4, "SPX (SPXUSD)": 0.5 / 6500 * 1e4}
AG_COST_PT = {"NQ (NSXUSD)": 1.0, "SPX (SPXUSD)": 0.5}


def daily_prices(path):
    d = pd.read_parquet(path).reset_index()
    d["t"] = pd.to_datetime(d["est"]); d = d.sort_values("t")
    assert d["t"].is_unique
    d["date"] = d["t"].dt.date; d["hm"] = d["t"].dt.strftime("%H:%M")
    want = {"10:00": "open", "15:00": "open", "15:30": "open", "15:59": "close"}
    cols = {}
    for hm, f in want.items():
        s = d[d["hm"] == hm].drop_duplicates("date").set_index("date")[f]
        cols[f"{f[0]}{hm.replace(':', '')}"] = s
    p = pd.DataFrame(cols).dropna()
    p.index = pd.to_datetime(p.index)
    p["prev_close"] = p["c1559"].shift(1)
    gap = (p.index.to_series().diff().dt.days <= 4).values      # prior close must be the previous session
    p = p[gap].dropna()
    return p


def block(name, sig, ret, price, cost_bp, ag_cost_pt=None):
    """sig, ret in bps; trade = sign(sig) * ret."""
    s = np.sign(sig); m = s != 0
    g = (s * ret)[m]; yrs = g.index.year
    sd = g.std(ddof=1)
    net = g - cost_bp
    t_g = stats.ttest_1samp(g, 0).statistic; t_n = stats.ttest_1samp(net, 0).statistic
    half = g.index < "2018-01-01"
    by_y = net.groupby(yrs).sum()
    line = (f"  {name:<44} n={m.sum():>5}  gross {g.mean():+6.2f} bp (t {t_g:+5.2f})  net@{cost_bp:.2f}bp {net.mean():+6.2f} bp "
            f"(t {t_n:+5.2f})  sd {sd:5.1f} bp  R@1sd {net.mean() / sd:+.4f}  "
            f"2010-17 t {stats.ttest_1samp(net[half], 0).statistic:+5.2f} / 2018-25 t {stats.ttest_1samp(net[~half], 0).statistic:+5.2f}  "
            f"net-positive years {int((by_y > 0).sum())}/{len(by_y)}")
    if ag_cost_pt is not None:
        pts = (s * ret / 1e4 * price)[m] - ag_cost_pt
        line += f"\n  {'':<44} (Antigravity's units: points, fixed {ag_cost_pt} pt: mean {pts.mean():+.2f} pt, t {stats.ttest_1samp(pts, 0).statistic:+.2f})"
    return line


def main():
    out = []
    pr = lambda s="": (out.append(s), print(s, flush=True))
    pr("BALTUSSEN / INTRADAY MOMENTUM RECHECK 2026-10-18 (Claude) -- report-only, 0 ledger")
    for name, fn in FILES.items():
        p = daily_prices(os.path.join(ROOT, "quantlab", "data", "inbox", "new_markets", fn))
        bp = lambda a, b: (b / a - 1.0) * 1e4
        pr(f"\n{name}: {len(p)} complete sessions {p.index.min().date()} -> {p.index.max().date()}, cost {COST_BP[name]:.2f} bp round trip")
        pr(block("A. Antigravity: 10:00->15:00 sign, hold 15:00->16:00", bp(p["o1000"], p["o1500"]), bp(p["o1500"], p["c1559"]),
                 p["o1500"], COST_BP[name], AG_COST_PT[name]))
        pr(block("B. Baltussen 2021: prior close->15:30, hold last 30m", bp(p["prev_close"], p["o1530"]), bp(p["o1530"], p["c1559"]),
                 p["o1530"], COST_BP[name]))
        pr(block("C. Gao 2018: prior close->10:00, hold last 30m", bp(p["prev_close"], p["o1000"]), bp(p["o1530"], p["c1559"]),
                 p["o1530"], COST_BP[name]))
        pr(block("D. placebo: random sign, hold 15:30->16:00", pd.Series(np.random.default_rng(7).choice([-1.0, 1.0], len(p)), p.index),
                 bp(p["o1530"], p["c1559"]), p["o1530"], COST_BP[name]))
    pr("\nRead: G12 needs one-sided t >= 2.326 on a pre-registered holdout; G9 needs expectancy >= +0.05R after cost.")
    open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "_baltussen_recheck_20261018.out"), "w", encoding="utf-8").write("\n".join(out) + "\n")


if __name__ == "__main__":
    main()
