"""v3knobs.py (A1.22): re-pick stop level and entry checkpoint on the dust-guarded mc5 book. $100, real depth, 4 h time stop, pull = 0.
Stops 0.4/0.5/0.6/0.7 (armed from entry) and 0.5 armed only after entry +10 min; entries +3..+7 min, band $250k-$1M. Pick on H1, test once on H2."""
import collections, statistics as st, datetime, random, numpy as np
exec(open("/root/fwa1/v3exit.py").read().split("extdone = ")[0])
extdone = {r[0] for r in E.execute("SELECT DISTINCT pool FROM done")}
H = 3600; NEED = int((420 + 4 * H + 600) / SPB)
full = [p for p in pools if p["pool"] in extdone and meta[p["pool"]][4] + NEED <= head]
for p in full: CACHE[p["pool"]] = path12(p)
def ex(s, te, stop, arm_after=0):
    T, M, pull, m0, mc = s
    ok = T <= te + 4 * H; Tn, Mn = T[ok], M[ok]
    for k in range(len(Mn)):
        if pull is not None and pull <= Tn[k]: return 0.0
        if Mn[k] <= stop and Tn[k] >= te + arm_after:
            j = max(k, int(np.searchsorted(T, Tn[k] + 3, "right")) - 1); return float(M[j])
    if pull is not None and pull <= te + 4 * H: return 0.0
    return float(Mn[-1]) if len(Mn) else m0
SIG = {}
for te in (180, 240, 300, 360, 420):
    out = []
    for p in full:
        pth = CACHE[p["pool"]][0]; i = state(pth, te)
        if i is None or pth[i][4] < 0.1 or not any(x[2] for x in pth[:i + 1]): continue
        s = series_t(p, 100, te)
        if s and 2.5e5 <= s[4] < 1e6: out.append((p, s))
    SIG[te] = out
alld = sorted({day(p["t"]) for p in full}); D1 = [d for d in alld if d < day(CUT)]; D2 = [d for d in alld if d >= day(CUT)]
def worst3(R, days):
    pn = collections.defaultdict(float)
    for p, x in R: pn[day(p["t"])] += (x - 1) * 100
    dl = sorted(datetime.date(2026, int(d[:2]), int(d[3:])) for d in days)
    cal = [dl[0] + datetime.timedelta(j) for j in range((dl[-1] - dl[0]).days + 1)]
    v = [pn.get(c.strftime("%m-%d"), 0.0) for c in cal]
    return min(sum(v[i:i + 3]) for i in range(max(1, len(v) - 2)))
def S(R, days):
    R = [r for r in R if day(r[0]["t"]) in days]; v = [x for p, x in R]
    if not v: return dict(n=0)
    los = [x for x in v if x < 1]
    return dict(n=len(v), mean=st.mean(v), med=st.median(v), usd=sum(x - 1 for x in v) * 100 / len(days), w3=worst3(R, days),
                loss=st.mean([(x - 1) * 100 for x in los]) if los else 0, win=sum(x > 1 for x in v) / len(v))
def fmt(d): return "n%d mean %.2fx med %.2fx $%.0f/day worst3 $%.0f avg loss/loser $%.0f win %.0f%%" % (d["n"], d["mean"], d["med"], d["usd"], d["w3"], d["loss"], 100 * d["win"]) if d["n"] else "n0"
print("pools", len(full), "days H1 %d H2 %d" % (len(D1), len(D2)))
GRID = []
for te in (180, 240, 300, 360, 420):
    for stop, arm in ((0.4, 0), (0.5, 0), (0.6, 0), (0.7, 0), (0.5, 600)):
        R = [(p, ex(s, te, stop, arm)) for p, s in SIG[te]]
        a, b = S(R, D1), S(R, D2)
        GRID.append((a.get("usd", -1e9), te, stop, arm, a, b))
        print("+%dm stop %.1fx%s | H1 %s | H2 %s" % (te // 60, stop, " arm+10m" if arm else "", fmt(a), fmt(b)), flush=True)
base = [g for g in GRID if g[1] == 300 and g[2] == 0.5 and g[3] == 0][0]
GRID.sort(key=lambda g: -g[0]); pick = GRID[0]
print("\nH1 PICK: +%dm stop %.1fx arm %ds  (H1 $%.0f/day)" % (pick[1] // 60, pick[2], pick[3], pick[0]))
print("  pick H2:", fmt(pick[5])); print("  base H2:", fmt(base[5]))
ok = pick[5]["usd"] > base[5]["usd"] and pick[5]["w3"] >= base[5]["w3"]
print("  PASS" if ok else "  FAIL", "(H2 $/day must rise and worst 3 days not worse)")
# by-knob views on H1 only (one knob at a time from base)
print("\none knob at a time, H1 pick within each knob:")
st1 = max([g for g in GRID if g[1] == 300], key=lambda g: g[0]); en1 = max([g for g in GRID if g[2] == 0.5 and g[3] == 0], key=lambda g: g[0])
for lab, g in (("stop knob", st1), ("entry knob", en1)):
    ok = g[5]["usd"] > base[5]["usd"] and g[5]["w3"] >= base[5]["w3"]
    print("  %s: +%dm stop %.1f arm %d | H2 %s | %s" % (lab, g[1] // 60, g[2], g[3], fmt(g[5]), "PASS" if ok else "FAIL"))
allb = [(p, ex(s, 300, 0.5)) for p, s in SIG[300]]; d = S(allb, D1 + D2)
print("\nbase all days: %s" % fmt(d))
