"""XS-ENS 执行延迟与调仓相位测试（crypto-multi-sleeve 报告附录）
引擎/数据/成本/资金费与研究第 1 轮完全相同（bt.run，1h bar，信号在调仓 bar 收盘、默认下一根 1h 开盘成交）。
延迟 k 小时 = 目标权重整体后移 k 根 1h bar（信号仍只用调仓时刻之前的数据）。
相位 = 72h 调仓网格整体平移 off 小时（基准锚定 2020-01-01 00:00 UTC）。
"""
import sys, json, numpy as np, pandas as pd
C="/workspace/iq/strategies/crypto/"; sys.path.insert(0,C); sys.path.insert(0,C+"round2/")
import os; os.chdir(C)
from bt import *
from lib2 import base_sleeves, daily
U20=SYMS
O1=panel(U20,"1h",field="o"); C1=panel(U20,"1h",field="c"); F1=fund_panel(U20,O1.index)
valid=C1.notna()&(C1.notna().cumsum()>24*30); vol=C1.pct_change().rolling(24*7,min_periods=72).std()
def xs_raw(Ls=(168,336,504,720),q=0.33):
    W=0
    for L in Ls:
        S=((C1/C1.shift(L)-1)/(vol*np.sqrt(L))).where(valid); rk=S.rank(axis=1,pct=True)
        w=(rk>=1-q).astype(float)-(rk<=q).astype(float); w=w.where(valid,0)
        W=W+w.div(w.abs().sum(1).replace(0,np.nan),axis=0).fillna(0)
    return W/len(Ls)
RAW=xs_raw()
def xs_w(H=72,offset=0):
    reb=(np.arange(len(O1))+offset)%H==0; W=RAW.copy(); W.loc[~reb]=np.nan; return W.ffill().fillna(0)
UTC=lambda s: pd.Timestamp(s,tz="UTC"); OOS=UTC("2024-01-01"); END=UTC("2026-08-31")
def sst(x,lo,hi):
    x=x[(x.index>=UTC(lo))&(x.index<UTC(hi))]; eq=(1+x).cumprod(); yrs=len(x)/365.25
    return dict(cagr=eq.iloc[-1]**(1/yrs)-1,sharpe=x.mean()/x.std()*np.sqrt(365),mdd=(eq/eq.cummax()-1).min())
def split(r,lo,hi):
    r=r[(r.index>=UTC(lo))&(r.index<UTC(hi))]; yrs=(UTC(hi)-UTC(lo)).days/365.25
    return dict(gross=r.gross.sum()/yrs,fees=-r.fees.sum()/yrs,funding=-r.fund.sum()/yrs,net=r.net.sum()/yrs,turn=r.turn.sum()/yrs)
# other sleeves (same as backtest.py)
B=base_sleeves(); A=pd.read_pickle(C+"round2/res/all_daily.pkl"); famB=pd.read_pickle(C+"round2/res/famB.pkl")
trend=daily(famB["BTCabove200_else0.5"]).reindex(B.index).fillna(0); ls=A["Dr_LSENS_top+glb_L137_H3"].reindex(B.index).fillna(0)
ev=pd.read_pickle(C+"round3_events/ev/fa_sleeves.pkl")[("PRE=MON+PDL+AIR","corrected funding + pre-reg delist exit (NEW HEADLINE)")].reindex(B.index).fillna(0)
ref=pd.read_parquet(C+"res/final_XS_ENS_168-720_H72_voladj.parquet")
# 相位 d = 调仓网格整体推迟 d 小时（offset = (72-d)%72）；d=71 即“提前 1h”= 实盘时点（用截至 00:00 的收盘、00:00 后几秒成交）
variants=[("基准：00:00 那根 1h 收盘出信号、01:00 开盘成交",0,0)]+[(f"再延迟 {k}h",k,0) for k in (1,2,4,8,24)]+[("实盘时点：提前 1h（截至 00:00 收盘、00:00 成交）",0,71)]+[(f"实盘时点 + 延迟 {k}h",k,71) for k in (1,4,8)]+[(f"相位推迟 {d}h",0,d) for d in range(1,71)]
rows=[]; base_w=xs_w()
for name,k,off in variants:
    w=(base_w if off==0 else xs_w(offset=(72-off)%72)).shift(k).fillna(0)
    r=run(w,O1,fund=F1)
    if k==0 and off==0: assert np.allclose(r.net.values,ref.net.reindex(r.index).values,atol=1e-12), "baseline mismatch"
    d=daily(r).reindex(B.index).fillna(0); d=d[d.index<=END]
    rec=dict(variant=name,delay_h=k,phase_h=off)
    for p,lo,hi in [("OOS","2024-01-01","2026-09-01"),("IS22","2022-01-01","2024-01-01"),("IS","2020-01-01","2024-01-01")]:
        s=sst(d,lo,hi); rec.update({f"{p}_{m}":v for m,v in s.items()})
    for p,lo,hi in [("OOS","2024-01-01","2026-09-01"),("IS22","2022-01-01","2024-01-01")]:
        sp=split(r,lo,hi); rec.update({f"{p}_{m}":v for m,v in sp.items()})
    t=trend[trend.index<=END]; l=ls[ls.index<=END]; e=ev[ev.index<=END]; x=d.reindex(t.index).fillna(0)
    for nm,combo in [("p",0.4*t+0.25*x+0.35*l),("pe",0.4*t+0.25*x+0.35*l+0.1*e)]:
        for p,lo,hi in [("OOS","2024-01-01","2026-09-01"),("IS22","2022-01-01","2024-01-01")]:
            s=sst(combo,lo,hi); rec.update({f"{nm}_{p}_{m}":v for m,v in s.items()})
    rows.append(rec)
    if not name.startswith('相位') or off%6==0: print(name,{k2:round(v,4) for k2,v in rec.items() if k2.startswith(("OOS_c","OOS_s","OOS_m","IS22_s","p_OOS_s","pe_OOS_s"))},flush=True)
T=pd.DataFrame(rows); T.to_csv(sys.argv[1] if len(sys.argv)>1 else "/workspace/report_cms/xsdelay/xs_delay.csv",index=False)
