"""E-AN4-5 (DC Analyst 4, 7 Oct 2026): HOT/COLD operator overlay on FW mc5 + SW live book trades. Read only (gold p/*.pkl, idx.json, lab trades).
Record at our entry minute, leak free: hit = honest 5x printed before entry, miss = pulled or 7 d closed before entry, open = left out."""
import csv, pickle, json, datetime, bisect
G = "/opt/sw/harness/gold"; BKK = datetime.timezone(datetime.timedelta(hours=7))
IDX = json.load(open(G + "/idx.json"))
def ts(s, fmt): return datetime.datetime.strptime(s, fmt).replace(tzinfo=BKK).timestamp() if s else None
C = list(csv.DictReader(open("/opt/tw/an4/an45_clusters.csv")))
CL = {r["pool"]: r["cl"] for r in C}
byc = {}
for r in C:
    if not r["first_trade"]: continue
    byc.setdefault(r["cl"], []).append((ts(r["first_trade"], "%Y-%m-%d %H:%M"), ts(r["pull"], "%Y-%m-%d %H:%M") if r["pull"] else None,
                                        ts(r["x5"], "%Y-%m-%d %H:%M") if r["x5"] else None, r["pool"]))
def record(pool, te):
    w = l = u = 0
    for ft, pl, x5, p in byc.get(CL.get(pool), []):
        if p == pool or ft >= te or ft < te - 3 * 86400: continue
        if x5 and x5 < te: w += 1
        elif (pl and pl < te) or ft + 7 * 86400 < te: l += 1
        else: u += 1
    return w, l, u
def ent(s): return datetime.datetime.strptime("2026 " + s, "%Y %d %b %H:%M").replace(tzinfo=BKK).timestamp()
out = []
for book, fn, tp in (("sw_live", "/root/fwa3/lab/out/sw_accept/live_book_trades.csv", 5.0), ("fw_mc5", "/root/fwa3/lab/out/sw/fw_mc5_trades.csv", None)):
    for r in csv.DictReader(open(fn)):
        pool = r["pool"].lower(); te = ent(r["entry_bkk"]); tx = ent(r["exit_bkk"]); x = float(r["x"])
        w, l, u = record(pool, te); res = w + l
        flag = "HOT" if res >= 3 and w >= 2 * res / 3 else ("COLD" if res >= 3 and w == 0 else "")
        xo = x; why_o = r["why"]; te2 = te
        if flag:
            c = pickle.load(open(G + "/p/%s.pkl" % pool, "rb"))["c"]; T = list(c["t"]); cap = c["cap"]
            i0 = bisect.bisect_left(T, te); i0 = min(i0, len(T) - 1); cap0 = cap[i0]
            pull_t = IDX.get(pool, {}).get("pull_t")
            def at(t):
                j = max(0, min(bisect.bisect_right(T, t) - 1, len(T) - 1)); return cap[j]
            if flag == "HOT":
                peak = cap0; te2 = None; why_o = "48h"
                for j in range(i0, len(T)):
                    if T[j] > te + 48 * 3600: te2 = te + 48 * 3600; break
                    peak = max(peak, cap[j])
                    if cap[j] <= 0.5 * peak: te2 = T[j]; why_o = "trail"; break
                if te2 is None: te2 = T[-1]; why_o = "data_end"
            else:
                te2 = te + 900; why_o = "15min"
                if tp:
                    for j in range(i0, len(T)):
                        if T[j] > te2: break
                        if cap[j] >= tp * cap0: te2 = T[j]; why_o = "target"; break
                if tx < te2: te2 = tx; why_o = r["why"]
            if pull_t and pull_t <= te2 and why_o != r["why"]: xo = 0.0; why_o = "pull"
            elif why_o != r["why"]:
                xo = x * at(te2) / at(tx) if at(tx) > 0 else 0.0
        out.append(dict(book=book, tok=r["tok"], pool=pool, half=r["half"], entry_bkk=r["entry_bkk"], why=r["why"], x=x, w=w, l=l, u=u, flag=flag, x_overlay=round(xo, 4), why_overlay=why_o, te2_min=round((te2 - te) / 60, 1) if flag else None))
with open("/opt/tw/an4/an45_trades.csv", "w") as f:
    wr = csv.DictWriter(f, fieldnames=list(out[0])); wr.writeheader(); wr.writerows(out)
for b in ("sw_live", "fw_mc5"):
    for h in "AB":
        s = [o for o in out if o["book"] == b and o["half"] == h]
        print(b, h, "trades", len(s), "HOT", sum(o["flag"] == "HOT" for o in s), "COLD", sum(o["flag"] == "COLD" for o in s))
