import json, math, statistics as S, collections
exec(open('it2c.py').read().split("# HOT conditional")[0])
# per basket daily position weight under rule C (BTC + majors gate, 30/15, trim half at HOT)
POS={}; FEAT={}
for k in keys:
    ds=[d for d,_ in D[k]['line']]; L=[v for _,v in D[k]['line']]; bo=bt_on(ds); st=stage_series(L)
    w=[0.0]*len(L); i=30
    while i<len(L)-1:
        ok=L[i]>max(L[i-30:i]) and bo[i] and (k=='majors' or ON['majors'].get(ds[i]))
        if not ok: i+=1; continue
        cur=1.0; ex=None
        for j in range(i,len(L)):
            if j>i and L[j]<min(L[j-15:j]): ex=j; break
            if j>i and cur==1.0 and st[j][0]=='HOT': cur=0.5
            w[j]=cur
        if ex is None: break
        i=ex+1
    POS[k]=dict(zip(ds,w))
    lg=[math.log(x) for x in L]
    bl=[BT.get(d) for d in ds]
    FEAT[k]={}
    for i in range(len(L)):
        if i<90: continue
        lo=min(L[i-89:i+1]); hi=max(L[i-89:i+1])
        r30=L[i]/L[i-30]-1; b30=(bl[i]/bl[i-30]-1) if bl[i] and bl[i-30] else 0
        FEAT[k][ds[i]]=dict(r30=r30,rel=r30-b30,dd=L[i]/hi-1,up=L[i]/lo-1,r7=L[i]/L[i-7]-1)
days=sorted({d for k in keys for d in POS[k]})
RET={k:{} for k in keys}
for k in keys:
    ds=[d for d,_ in D[k]['line']]; L=[v for _,v in D[k]['line']]
    for i in range(len(L)-1): RET[k][ds[i]]=L[i+1]/L[i]-1
btd=sorted(BT); BR={btd[i]:BT[btd[i+1]]/BT[btd[i]]-1 for i in range(len(btd)-1)}
def sim(select, K=None, lo='2023-01-01', hi='2027-01-01', excl_majors=False):
    eq=0; prev={}; cost=0
    yr=collections.defaultdict(float)
    for d in days:
        if not(lo<=d<hi): continue
        opn=[(k,POS[k][d]) for k in keys if POS[k].get(d,0)>0 and d in RET[k] and not(excl_majors and k=='majors')]
        if K and select and opn:
            opn=sorted(opn,key=lambda x:select(x[0],d),reverse=True)[:K]
        tot=len(opn)
        # each open slot gets 1/max(K,n) of capital (unused = cash)
        den=K if K else max(tot,1)
        wts={k:w/den for k,w in opn}
        turn=sum(abs(wts.get(k,0)-prev.get(k,0)) for k in set(wts)|set(prev))
        r=sum(wt*RET[k][d] for k,wt in wts.items())-turn*0.005
        eq+=math.log(1+r); yr[d[:4]]+=math.log(1+r); prev=wts
    return eq,yr
feat=lambda f:(lambda k,d:FEAT[k].get(d,{}).get(f,-9))
rows=[('equal weight every open basket (no cap)',None,None),('cap 3, strongest 30d',feat('r30'),3),('cap 3, weakest 30d',lambda k,d:-feat('r30')(k,d),3),
      ('cap 2, strongest vs BTC 30d',feat('rel'),2),('cap 2, weakest vs BTC 30d',lambda k,d:-feat('rel')(k,d),2),
      ('cap 2, furthest above 90d low',feat('up'),2),('cap 2, closest to 90d low',lambda k,d:-feat('up')(k,d),2),
      ('cap 2, strongest 7d',feat('r7'),2),('cap 1, strongest 30d',feat('r30'),1),('cap 1, weakest 30d',lambda k,d:-feat('r30')(k,d),1),
      ('cap 2, memes first then strongest',lambda k,d:(('meme' in k or k in('sol_pump','sol_bonk'))*10+feat('r30')(k,d)),2)]
def bh(k):
    yr=collections.defaultdict(float); e=0
    for d,r in RET[k].items():
        if d>='2023-01-01': e+=math.log(1+r); yr[d[:4]]+=math.log(1+r)
    return e,yr
print(f"{'portfolio':42s} total   2023   2024   2025   2026 (log %)")
for nm,s,K in rows:
    e,y=sim(s,K); print(f"{nm:42s} {e*100:+6.0f} "+" ".join(f"{y.get(x,0)*100:+6.0f}" for x in ('2023','2024','2025','2026')))
for nm,s,K in rows[:1]:
    e,y=sim(s,K,excl_majors=True); print(f"{'(same, without majors basket)':42s} {e*100:+6.0f} "+" ".join(f"{y.get(x,0)*100:+6.0f}" for x in ('2023','2024','2025','2026')))
for k in ('majors',):
    e,y=bh(k); print(f"{'hold majors basket':42s} {e*100:+6.0f} "+" ".join(f"{y.get(x,0)*100:+6.0f}" for x in ('2023','2024','2025','2026')))
yb=collections.defaultdict(float); eb=0
for d,r in BR.items():
    if d>='2023-01-01': eb+=math.log(1+r); yb[d[:4]]+=math.log(1+r)
print(f"{'hold BTC':42s} {eb*100:+6.0f} "+" ".join(f"{yb.get(x,0)*100:+6.0f}" for x in ('2023','2024','2025','2026')))
ys=collections.defaultdict(list)
for k in keys:
    if k in('majors',): continue
    e,y=bh(k)
    for x,v in y.items(): ys[x].append(v)
print(f"{'hold every alt basket (median)':42s}        "+" ".join(f"{S.median(ys[x])*100:+6.0f}" for x in ('2023','2024','2025','2026')))
json.dump({k:{d:w for d,w in v.items() if w} for k,v in POS.items()},open('posC.json','w'))
print()
def sim2(select,K):
    eq=0; pk=0; mdd=0; prev={}; expo=[]
    for d in days:
        if d<'2023-01-01': continue
        opn=[(k,POS[k][d]) for k in keys if POS[k].get(d,0)>0 and d in RET[k]]
        if K and select and opn: opn=sorted(opn,key=lambda x:select(x[0],d),reverse=True)[:K]
        den=K if K else max(len(opn),1); wts={k:w/den for k,w in opn}
        turn=sum(abs(wts.get(k,0)-prev.get(k,0)) for k in set(wts)|set(prev))
        r=sum(wt*RET[k][d] for k,wt in wts.items())-turn*0.005; prev=wts
        eq+=math.log(1+r); pk=max(pk,eq); mdd=min(mdd,eq-pk); expo.append(sum(wts.values()))
    return eq,mdd,S.mean(expo)
for K in (1,2,3,4,5):
    e,m,x=sim2(feat('r30'),K); print(f"cap {K} strongest 30d: total {e*100:+.0f} log%, worst drop {(math.exp(m)-1)*100:.0f}%, avg money in {x*100:.0f}%")
e=0;pk=0;mdd=0
for d in sorted(BR):
    if d<'2023-01-01': continue
    e+=math.log(1+BR[d]); pk=max(pk,e); mdd=min(mdd,e-pk)
print(f"BTC hold: total {e*100:+.0f}, worst drop {(math.exp(mdd)-1)*100:.0f}%")
