"""_ictsb01_cost_periods_20261020.py - ICTSB01 result before and after costs by period. Read-only, DISCOVERY ONLY (<= 2020-12-31).

Written by: Claude (2026-10-20), review of the Aydeus Lab page for ICTSB01. EMPIRICAL RESEARCH, NOT LAW / NOT DEPLOYED. No new rule, no selection:
the frozen ICTSB01 functions are imported unchanged (lock checked first) and the run's own GROSS and primary NET lists are split by period.

Why: the US100 minute file has bid = ask before 2012-03 (spread 0.00 in 2005-2011, ICTSB01 precheck), so the primary NET charges only the
0.5 pt stop/flat slippage in those years and the real spread from 2012. The cumulative NET curve rises to 2011 and falls in 2012-2013. This
splits that fall into what the spread appearing in the file explains and what the rule itself does before any cost (GROSS: the same
pessimistic fill rules on mid prices, zero spread, zero slippage).

Parity check: the full-period GROSS and NET must equal the frozen run (_ictsb01_run_20261020.out): GROSS n 884, +0.0849R; NET n 862, -0.0499R.
"""
from __future__ import annotations

import hashlib
import json
import os
import sys

import numpy as np
import pandas as pd

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import _ictsb01_silver_bullet_20261020 as S  # noqa: E402

OUT = os.path.join(HERE, "_ictsb01_cost_periods_20261020.out")
PERIODS = (("2005-2011 (file spread 0)", 2005, 2011), ("2012-2013", 2012, 2013), ("2014-2020", 2014, 2020),
           ("2012-2020 (real file spread)", 2012, 2020), ("2005-2020 (all)", 2005, 2020))


def sha(p: str) -> str:
    return hashlib.sha256(open(p, "rb").read()).hexdigest()


def main() -> None:
    lock = json.load(open(S.LOCK))
    assert lock["script_sha256"] == sha(os.path.join(HERE, "_ictsb01_silver_bullet_20261020.py")), "frozen script changed"
    assert lock["hdam_sim_sha256"] == sha(os.path.join(S.LAB, "hdam", "hdam_sim.py")), "hdam_sim changed"
    book = S.H.load_book(S.SYM, "discovery")
    P = S.trades_of(S.build_days(S.fast_book(book), specs=("M5",)), "M5", "dol")
    G = S.trades_of(S.build_days(S.fast_book(book, mid=True), specs=("M5",), slip=0.0), "M5", "dol")
    sp, sg = S.stats(P.x_R), S.stats(G.x_R)
    S.pr(f"ICTSB01 cost by period  {pd.Timestamp.now('UTC'):%Y-%m-%d %H:%MZ}  frozen lock {lock['frozen_utc']}")
    S.pr(f"parity: NET  {S.fmt(sp)}  (frozen run: n 862, -0.0499R, t -0.83)")
    S.pr(f"parity: GROSS {S.fmt(sg)}  (frozen run: n 884, +0.0849R, t +1.43)")
    assert sp["n"] == 862 and abs(sp["mean"] + 0.0499) < 5e-5 and sg["n"] == 884 and abs(sg["mean"] - 0.0849) < 5e-5, "parity failed"
    P["year"], G["year"] = P.day.dt.year, G.day.dt.year
    P["spread_r"] = P.s_pre / P.risk
    S.pr("\nmedian file spread before the order (pt) and median 1R (pt) by year, primary trades:")
    S.pr("  " + "  ".join(f"{y}:{g.s_pre.median():.2f}/{g.risk.median():.1f}" for y, g in P.groupby("year")))
    S.pr("\nperiod                         NET (bid/ask, spread + slippage)          GROSS (mid, zero cost)                    mean spread / 1R")
    for name, a, z in PERIODS:
        p, g = P[(P.year >= a) & (P.year <= z)], G[(G.year >= a) & (G.year <= z)]
        S.pr(f"  {name:28s} {S.fmt(S.stats(p.x_R))}   {S.fmt(S.stats(g.x_R))}   {p.spread_r.mean():.3f}R")
    S.pr("\nReading: the NET minus GROSS gap per period is the cost (with small differences in which orders fill on bid/ask vs mid).")
    open(OUT, "w", encoding="utf-8").write("\n".join(S.LINES) + "\n")


if __name__ == "__main__":
    main()
