"""Per-hour P&L breakdown of a backtest trade book. Usage: python backtest/research/hour_analysis.py BOOK.csv BAR_MINUTES Reports, per UTC hour (both entry hour and DECISION hour = entry_time minus one bar, the clock blocked_hours_utc evaluates): trade count, total R, mean R, win rate, profit factor. Also a per-(hour, direction) table. Analysis tooling only — never imported by the live code. """ import sys import pandas as pd def hour_tables(book_csv: str, bar_minutes: int): df = pd.read_csv(book_csv) et = pd.to_datetime(df["entry_time"], utc=True, format="mixed") df["entry_hour"] = et.dt.hour df["decision_hour"] = (et - pd.Timedelta(minutes=bar_minutes)).dt.hour def table(group_cols): g = df.groupby(group_cols)["r_multiple"] out = g.agg(count="count", total_r="sum", mean_r="mean", wr=lambda r: (r > 0).mean() * 100) out["pf"] = g.apply( lambda r: r[r > 0].sum() / max(-r[r <= 0].sum(), 1e-9)) return out.round(2) return (table("decision_hour"), table(["decision_hour", "direction"]), table("entry_hour")) if __name__ == "__main__": book, mins = sys.argv[1], int(sys.argv[2]) by_dec, by_dec_dir, by_ent = hour_tables(book, mins) print(f"\n── {book} · by DECISION hour (bar-close clock) ──") print(by_dec.to_string()) print(f"\n── by (decision hour, direction) ──") print(by_dec_dir.to_string())