"""Bigger sample for the frozen chain-2 rule: more years (from Sep 2022) and meme baskets on other chains.
Nothing is re-tuned: same rule2 defaults. Everything outside the original 4 baskets in 2024-2026 is out of sample."""
import json, glob, os, datetime as dt, statistics as S, collections
import rule2
from baskets_def import CMC_BASKETS, EXCLUDE, MEME
files=sorted(glob.glob('snapB/*.json')); days=[os.path.basename(f)[:10] for f in files]
snap={d:json.load(open(f)) for d,f in zip(days,files)}
px={d:{c[0]:c[6] for c in s if c[6]} for d,s in snap.items()}
BTC={d:c[6] for d,s in snap.items() for c in s if c[1]=="BTC" and c[3] is None and c[6]}
risk=rule2.risk_series(sorted(BTC),BTC)
has=lambda t,s:bool(set(t)&s)
ORIG={b[0]:(b[1],b[3]) for b in CMC_BASKETS if b[0] in ("sol_pump","sol_bonk","sol_memes","base_memes")}
NEW={"eth_memes":("Ethereum",lambda t:has(t,MEME)),"bnb_memes":("BNB Smart Chain (BEP20)",lambda t:has(t,MEME) or "four-meme-ecosystem" in t),
     "sui_memes":("Sui Network",lambda t:has(t,MEME)),"tron_memes":("Tron20",lambda t:has(t,MEME) or "sun-pump-ecosystem" in t),
     "avax_memes":("Avalanche C-Chain",lambda t:has(t,MEME)),"arb_memes":("Arbitrum",lambda t:has(t,MEME)),
     "poly_memes":("Polygon",lambda t:has(t,MEME)),"ton_memes":("TON",lambda t:has(t,MEME)),"rh_memes":("Robinhood Chain",lambda t:has(t,MEME))}
def build(key,plat,rule,minvol=25000,topn=15):
    ex=EXCLUDE.get(key,set()); line=[]; lvl=1.0; mem=None; started=False; nm=[]
    for i in range(len(days)-1):
        d,n=days[i],days[i+1]
        if mem is None or dt.date.fromisoformat(d).weekday()==0:
            xs=[c for c in snap[d] if c[3]==plat and not c[9] and c[1] not in ex and rule(c[10]) and c[8]>=minvol and c[6]>0 and c[7]>0]
            xs.sort(key=lambda c:-c[7]); m=[c[0] for c in xs[:topn]]; mem=m if len(m)>=4 else None
            if mem: nm.append(len(m))
        if mem is None:
            if started: line.append((n,lvl))   # flat while too few members, keeps the line continuous
            continue
        rs=[]
        for cid in mem:
            a=px[d].get(cid); z=px[n].get(cid)
            if not a: continue
            if z is None:
                if any(cid in px[days[k]] for k in range(i+2,min(i+5,len(days)))): continue
                rs.append(-0.5); continue
            rs.append(max(-0.9,min(2.0,z/a-1)))
        if len(rs)<4:
            if started: line.append((n,lvl))
            continue
        started=True; lvl*=1+sum(rs)/len(rs); line.append((n,lvl))
    return [d for d,_ in line],[x for _,x in line],(round(S.mean(nm),1) if nm else 0)
res={"by_basket":{},"groups":{}}; allt=[]
for k,(plat,rule) in list(ORIG.items())+list(NEW.items()):
    ds,L,avgm=build(k,plat,rule)
    if len(L)<60: res["by_basket"][k]={"n":0,"note":"too little history","days":len(L)}; continue
    ts=[t for t in rule2.trades(ds,L,risk) if t["status"]=="closed"]
    for t in ts: t["b"]=k; t["group"]=("A in sample" if k in ORIG and t["sig"]>="2024-01-01" else ("B old years" if k in ORIG else "C new chains"))
    allt+=ts; res["by_basket"][k]=dict(rule2.stats(ts),first=ds[0],avg_members=avgm)
for g in ("A in sample","B old years","C new chains"):
    res["groups"][g]=rule2.stats([t for t in allt if t["group"]==g])
oos=[t for t in allt if t["group"]!="A in sample"]
res["groups"]["out of sample (B+C)"]=rule2.stats(oos); res["groups"]["everything"]=rule2.stats(allt)
# clustering: trades that start the same week are not independent; average them per week
def weekly(ts):
    w=collections.defaultdict(list)
    for t in ts: w[dt.date.fromisoformat(t["sig"]).isocalendar()[:2]].append(t["ret"])
    xs=[S.mean(v) for v in w.values()]; pos=[x for x in xs if x>0]; neg=[x for x in xs if x<=0]
    return dict(weeks=len(xs),mean=round(S.mean(xs)*100,1),win=round(len(pos)/len(xs)*100),pf=round(sum(pos)/-sum(neg),2) if neg else None)
res["weekly_everything"]=weekly(allt); res["weekly_oos"]=weekly(oos)
yr=collections.defaultdict(list)
for t in allt: yr[t["sig"][:4]].append(t)
res["by_year"]={y:rule2.stats(v) for y,v in sorted(yr.items())}
res["trades"]=[[t["b"],t["sig"],t["exit"],round(t["ret"]*100,1),t["why"],t["bars"],t["group"]] for t in allt]
json.dump(res,open('bt_wide.json','w'))
print(json.dumps({k:v for k,v in res.items() if k!="trades"},indent=0))
