"""Final chain-2 evidence, computed with the same rule2 code the live engine runs. Writes evidence2.json."""
import json, itertools
import bt_chain2 as B, rule2
from baskets_def import CMC_BASKETS, TRADABLE
risk=rule2.risk_series(sorted(B.BTC),B.BTC)
lines={b[0]:B.build(b[0]) for b in CMC_BASKETS}
def run(keys,cut=None,after=None,build_kw=None,**kw):
    ts=[]
    for k in keys:
        ds,L,_=B.build(k,**build_kw) if build_kw else lines[k]
        for t in rule2.trades(ds,L,risk,**kw):
            if t["status"]!="closed": continue
            if cut and ((t["sig"]>=cut)!=after): continue
            t["b"]=k; ts.append(t)
    return ts
M=sorted(TRADABLE); NON=[b[0] for b in CMC_BASKETS if b[0] not in TRADABLE and b[0]!="rh_memes"]
ev={"rule":"chain-2","period":"Jan 2024 to Sep 2026","tradable":M}
allt=run(M); ev["all"]=rule2.stats(allt)
ev["trades"]=[[t["b"],t["sig"],t["exit"],round(t["ret"]*100,1),t["why"],t["bars"]] for t in allt]
ev["per_basket"]={k:rule2.stats([t for t in allt if t["b"]==k]) for k in M}
ev["halves"]={"to_jun25":rule2.stats(run(M,"2025-07-01",False)),"from_jul25":rule2.stats(run(M,"2025-07-01",True))}
ev["non_meme"]=rule2.stats(run(NON))
V={}
V["enter next close"]=rule2.stats(run(M,delay=1)); V["no costs"]=rule2.stats(run(M,cost=0.0)); V["2% round trip"]=rule2.stats(run(M,cost=0.02))
V["no sell rule, hold 14 days"]=rule2.stats(run(M,stop=9,trend=False,tp=False)); V["break of 30 bar high"]=rule2.stats(run(M,brk=30))
V["stale price filter"]=rule2.stats(run(M,build_kw=dict(stale=True))); V["members need $100k volume"]=rule2.stats(run(M,build_kw=dict(minvol=100000)))
V["missing coin counted as -100%"]=rule2.stats(run(M,build_kw=dict(miss=-1.0)))
V["old rule: all baskets, 30 bar break, hold 14"]=rule2.stats(run(M+NON,brk=30,stop=9,trend=False,tp=False))
ev["variants"]=V
grid=[]
for brk,stop,mh in itertools.product((10,20,30),(0.08,0.12,0.16),(7,14,21)):
    s=rule2.stats(run(M,brk=brk,stop=stop,maxh=mh)); grid.append([brk,stop,mh,s.get("n"),s.get("mean"),s.get("pf")])
ev["grid"]=grid; ev["grid_pf_range"]=[min(g[5] for g in grid if g[5]),max(g[5] for g in grid if g[5])]; ev["grid_pf_above_1"]=sum(1 for g in grid if g[5] and g[5]>1)
best=None
for g in itertools.product((10,20,30),(0.08,0.12,0.16),(7,14,21)):
    s=rule2.stats(run(M,"2025-07-01",False,brk=g[0],stop=g[1],maxh=g[2]))
    if s.get("pf") and (best is None or s["pf"]>best[0]): best=(s["pf"],)+g
ev["walk_forward"]={"meme_first":rule2.stats(run(M,"2025-07-01",False)),"non_first":rule2.stats(run(NON,"2025-07-01",False)),
    "meme_second":rule2.stats(run(M,"2025-07-01",True)),"non_second":rule2.stats(run(NON,"2025-07-01",True)),
    "best_first_half":list(best[1:]),"best_first_half_in_second":rule2.stats(run(M,"2025-07-01",True,brk=best[1],stop=best[2],maxh=best[3]))}
ev["misses"]={k:lines[k][2] for k in M}
json.dump(ev,open('evidence2.json','w'))
print(json.dumps({k:v for k,v in ev.items() if k not in ("trades","grid")},indent=0))
