import json, math, statistics as S
D=json.load(open('bk_clean.json'))
BT={d:v for d,v in D['btc']['line']}
def sma(x,n): return [None if i<n-1 else sum(x[i-n+1:i+1])/n for i in range(len(x))]
def ema(x,n):
    a=2/(n+1); o=[]; e=None
    for v in x: e=v if e is None else e+a*(v-e); o.append(e)
    return o
def hyst(cond_on,cond_off):
    s=False; o=[]
    for on,off in zip(cond_on,cond_off):
        if on: s=True
        elif off: s=False
        o.append(s)
    return o
def states(ds,L):
    lg=[math.log(v) for v in L]; e20=ema(lg,20); e50=ema(lg,50); m50=sma(L,50); m100=sma(L,100)
    btc=[BT.get(d) for d in ds]; 
    out={}
    out['T1 above rising EMA20']=[i>=20 and lg[i]>e20[i] and e20[i]>e20[i-5] for i in range(len(L))]
    out['T2 above 50d avg']=[m50[i] is not None and L[i]>m50[i] for i in range(len(L))]
    out['T3 above 100d avg (1% band)']=hyst([m100[i] is not None and L[i]>m100[i]*1.01 for i in range(len(L))],[m100[i] is None or L[i]<m100[i]*0.99 for i in range(len(L))])
    out['T4 EMA20 over EMA50']=[i>=50 and e20[i]>e50[i] for i in range(len(L))]
    out['T5 up over 30 days']=[i>=30 and L[i]>L[i-30] for i in range(len(L))]
    out['T6 up over 14 days']=[i>=14 and L[i]>L[i-14] for i in range(len(L))]
    # BTC gate
    bl=[b for b in btc]; 
    def bsma(i,n):
        xs=[x for x in bl[max(0,i-n+1):i+1] if x]; return sum(xs)/len(xs) if len(xs)>=n*0.9 else None
    bon=[(bl[i] and bsma(i,100) and bl[i]>bsma(i,100)) or False for i in range(len(L))]
    out['B BTC above 100d avg']=bon
    out['T4 + BTC on']=[a and b for a,b in zip(out['T4 EMA20 over EMA50'],bon)]
    out['T1 + BTC on']=[a and b for a,b in zip(out['T1 above rising EMA20'],bon)]
    # ratio vs BTC
    r=[math.log(L[i]/bl[i]) if bl[i] else None for i in range(len(L))]
    rr=[x if x is not None else (r[i-1] if i else 0) for i,x in enumerate(r)]
    re20=ema(rr,20); re50=ema(rr,50)
    out['R ratio vs BTC EMA20>EMA50']=[i>=50 and re20[i]>re50[i] for i in range(len(L))]
    return out
def run(ds,L,st,lo,hi,cost=0.01):
    # signal at close i -> hold i..i+1
    eq=0; bh=0; sw=0; on=0; n=0; prev=False
    for i in range(len(L)-1):
        if not(lo<=ds[i]<hi): continue
        r=math.log(L[i+1]/L[i]); bh+=r; n+=1
        if st[i]!=prev: eq+=math.log(1-cost/2); sw+=1; prev=st[i]
        if st[i]: eq+=r; on+=1
    return eq,bh,on/max(n,1),sw,n
def fwd(ds,L,st,h,lo,hi):
    a=[];b=[]
    for i in range(len(L)-h):
        if not(lo<=ds[i]<hi): continue
        x=L[i+h]/L[i]-1
        (a if st[i] else b).append(x)
    return a,b
keys=[k for k in D if k!='btc']
NAMES=None; res={}
periods=[("all","2022-09-01","2026-12-31"),("H1 to Sep24","2022-09-01","2024-09-01"),("H2 from Sep24","2024-09-01","2026-12-31")]
for k in keys:
    ds=[d for d,_ in D[k]['line']]; L=[v for _,v in D[k]['line']]
    S_=states(ds,L); NAMES=list(S_)
    for nm,st in S_.items():
        for pn,lo,hi in periods:
            eq,bh,tim,sw,n=run(ds,L,st,lo,hi)
            if n<60: continue
            a,b=fwd(ds,L,st,14,lo,hi)
            res.setdefault(nm,{}).setdefault(pn,[]).append(dict(k=k,eq=eq,bh=bh,tim=tim,sw=sw,n=n,on14=S.median(a) if a else None,off14=S.median(b) if b else None))
for nm in NAMES:
    print("\n==",nm)
    for pn,_,_ in periods:
        rs=res[nm].get(pn,[]); 
        if not rs: continue
        beat=sum(1 for r in rs if r['eq']>r['bh']); pos=sum(1 for r in rs if r['eq']>0)
        sp=[r['on14']-r['off14'] for r in rs if r['on14'] is not None and r['off14'] is not None]
        print(f" {pn:14s} baskets {len(rs):2d} beat hold {beat:2d}  strat>0 {pos:2d}  med strat/yr {S.median([r['eq']/r['n']*365 for r in rs])*100:+6.0f}%  med hold/yr {S.median([r['bh']/r['n']*365 for r in rs])*100:+6.0f}%  time on {S.median([r['tim'] for r in rs])*100:3.0f}%  switches/yr {S.median([r['sw']/r['n']*365 for r in rs]):4.1f}  fwd14 on-off {S.median(sp)*100:+5.1f}pts ({sum(1 for x in sp if x>0)}/{len(sp)})")
