"""Audit: could the gold-hours kill rule's bars ever have bound?

The rule: confirmed if the 08:00-12:00 NY overlap carries > 33.3 % of daily
variance and holds the busiest half hour; refuted under 25 %. Measured 31.2 %,
so the verdict was `partly` / inconclusive. That verdict is only meaningful if
the data can tell 31.2 % apart from the bars. This bootstraps over days.
"""
import os
import numpy as np, pandas as pd

BARS = os.path.expanduser("~/data/bars/XAUUSD_mt5_m1.csv")
TZ = "America/New_York"
df = pd.read_csv(BARS, parse_dates=["minute"])
df["minute"] = df["minute"].dt.tz_convert(TZ)
df = df.sort_values("minute").reset_index(drop=True)
df["gap_min"] = df["minute"].diff().dt.total_seconds().div(60)
df["dclose"] = df["bid_close"].diff()
df["is_gap"] = df["gap_min"].ne(1.0)
df.loc[df.index[0], "is_gap"] = True
df["ny_date"] = df["minute"].dt.date
df["dow"] = df["minute"].dt.dayofweek
df["bin"] = df["minute"].dt.hour * 2 + (df["minute"].dt.minute >= 30).astype(int)

wk = df[df["dow"] < 5]
mv = wk[~wk["is_gap"]].assign(sq=lambda d: d["dclose"] ** 2)
pdb = mv.groupby(["ny_date", "bin"])["sq"].sum()
overlap = list(range(16, 24))

# The published statistic, rebuilt: mean over days per bin, then the overlap's
# share of the sum of those means.
def share_of(table):
    bv = table.groupby("bin").mean()
    return bv.reindex(overlap).sum() / bv.sum()

point = share_of(pdb)
days = sorted({d for d, _ in pdb.index})
print(f"days: {len(days)}   published share: {point:.4f}")

wide = pdb.unstack("bin")            # day x bin
rng = np.random.default_rng(20260911)
boot = []
for _ in range(4000):
    pick = rng.integers(0, len(wide), len(wide))
    s = wide.iloc[pick]
    bv = s.mean(axis=0)
    boot.append(bv.reindex(overlap).sum() / bv.sum())
boot = np.array(boot)
lo, hi = np.percentile(boot, [2.5, 97.5])
se = boot.std(ddof=1)
print(f"bootstrap over days: se {se:.4f}  95% CI [{lo:.4f}, {hi:.4f}]")
print(f"bars: refute < 0.2500, confirm > 0.3333;  band width {0.3333-0.25:.4f}"
      f" = {(0.3333-0.25)/se:.2f} standard errors")
print(f"P(bootstrap >= 0.3333) = {(boot >= 1/3).mean():.4f}")
print(f"P(bootstrap <= 0.2500) = {(boot <= 0.25).mean():.4f}")
print(f"P(inconclusive)        = {((boot > 0.25) & (boot < 1/3)).mean():.4f}")
