"""
缠论完整交易系统 — 日线为基础级别
买卖点: 一类(背驰)+三类(回踩中枢)
"""
import pandas as pd, numpy as np

df_raw = pd.read_parquet("data/btc_multidim.parquet")
dd = df_raw.resample("1D").agg({"open":"first","high":"max","low":"min","close":"last","volume":"sum"}).dropna()

# 4H 用于精确入场
d4h = df_raw.resample("4h").agg({"open":"first","high":"max","low":"min","close":"last"}).dropna()

# ── 日线缠论结构 ──
def get_daily_structure(data):
    O,H,L,C = data["open"].values,data["high"].values,data["low"].values,data["close"].values
    n = len(data)
    
    fx = []
    for i in range(1,n-1):
        if H[i]>H[i-1] and H[i]>H[i+1] and L[i]>L[i-1] and L[i]>L[i+1]:
            fx.append((i,"顶",H[i]))
        elif L[i]<L[i-1] and L[i]<L[i+1] and H[i]<H[i-1] and H[i]<H[i+1]:
            fx.append((i,"底",L[i]))
    
    bi = []; i = 0
    while i < len(fx)-1:
        f1,best = fx[i],None
        for j in range(i+1,min(i+15,len(fx))):
            f2 = fx[j]
            if f2[1]!=f1[1] and f2[0]-f1[0]>=2:
                if (f1[1]=="底" and f2[2]>f1[2]) or (f1[1]=="顶" and f2[2]<f1[2]):
                    best=j; break
        if best:
            f2=fx[best]
            bi.append({"s":f1[0],"e":f2[0],"d":"up" if f1[1]=="底" else "down",
                       "sp":f1[2],"ep":f2[2],"sh":H[f1[0]],"sl":L[f1[0]],
                       "eh":H[f2[0]],"el":L[f2[0]]})
            i=best
        else: i+=1
    
    xd = []
    for i in range(len(bi)-2):
        b1,b2,b3=bi[i],bi[i+1],bi[i+2]
        if b1["d"]!=b2["d"] and b2["d"]!=b3["d"]:
            if b1["d"]=="up":
                xd.append({"d":"up","h":max(b1["eh"],b2["eh"],b3["eh"]),
                           "l":min(b1["sl"],b2["sl"],b3["sl"])})
            else:
                xd.append({"d":"down","h":max(b1["sh"],b2["sh"],b3["sh"]),
                           "l":min(b1["el"],b2["el"],b3["el"])})
    
    zs = []; i = 0
    while i < len(xd)-2:
        hs=[x["h"] for x in xd[i:i+3]]; ls=[x["l"] for x in xd[i:i+3]]
        ZG,ZD = min(hs),max(ls)
        if ZG>ZD:
            end=i+3
            while end<len(xd):
                h,l=xd[end]["h"],xd[end]["l"]
                if max(ZG,h)-min(ZD,l)>0 and h>ZD and l<ZG:
                    ZG,ZD=min(ZG,h),max(ZD,l); end+=1
                else: break
            zs.append({"ZG":ZG,"ZD":ZD,"ZZ":(ZG+ZD)/2,"end_xd":end-1})
            i=end
        else: i+=1
    
    return bi, xd, zs, C

bi, xd, zs, close_vals = get_daily_structure(dd)
print(f"日线: {len(bi)}笔 {len(xd)}线段 {len(zs)}中枢")

# ── 交易回测: 滚动窗口 ──
FEE = 0.001
SL_DAILY, TP_DAILY = 0.03, 0.09  # 日线级别: SL=3% TP=9% (R:R=1:3)
MAX_DAYS = 30

trades = []
min_days = 90  # 至少3个月日线数据

for end_idx in range(min_days, len(dd)):
    window = dd.iloc[:end_idx+1]
    bi_w, xd_w, zs_w, _ = get_daily_structure(window)
    
    if len(zs_w) < 1:
        continue
    
    last_zs = zs_w[-1]
    ZG, ZD, ZZ = last_zs["ZG"], last_zs["ZD"], last_zs["ZZ"]
    today_close = dd["close"].iloc[end_idx]
    today_idx = end_idx
    
    # ── 判断买卖点 ──
    signal = None
    
    # 三买: 中枢上方 + 回踩ZG附近
    if today_close > ZG and abs(today_close - ZG)/ZG < 0.03:
        # 确认: 之前曾突破ZG
        prev_highs = dd["high"].iloc[max(0,today_idx-10):today_idx]
        if (prev_highs > ZG).any():
            signal = "三买"
    
    # 三卖: 中枢下方 + 反弹ZD附近
    if today_close < ZD and abs(today_close - ZD)/ZD < 0.03:
        prev_lows = dd["low"].iloc[max(0,today_idx-10):today_idx]
        if (prev_lows < ZD).any():
            signal = "三卖"
    
    # 一买: 中枢下方 + 底分型
    if today_close < ZD and len(bi_w) >= 2:
        last_bi = bi_w[-1]
        if last_bi["d"] == "down":
            # 在4H上找精确入场
            signal = "一买"
    
    # 一卖: 中枢上方 + 顶分型
    if today_close > ZG and len(bi_w) >= 2:
        last_bi = bi_w[-1]
        if last_bi["d"] == "up":
            signal = "一卖"
    
    if signal is None:
        continue
    
    # ── 模拟交易 ──
    direction = 1 if signal in ["一买","三买"] else -1
    entry = today_close
    sl, tp = SL_DAILY, TP_DAILY
    
    win, loss = False, False
    for j in range(1, min(MAX_DAYS, len(dd)-today_idx-1)):
        exit_px = dd["close"].iloc[today_idx+j]
        ret = (exit_px/entry - 1) * direction
        if ret <= -sl:
            trades.append({"sig": signal, "ret": -sl-FEE, "win": 0, "bars": j,
                          "date": dd.index[today_idx]})
            loss = True; break
        elif ret >= tp:
            trades.append({"sig": signal, "ret": tp-FEE, "win": 1, "bars": j,
                          "date": dd.index[today_idx]})
            win = True; break
    if not win and not loss:
        ep = dd["close"].iloc[min(today_idx+MAX_DAYS, len(dd)-1)]
        trades.append({"sig": signal, "ret": (ep/entry-1)*direction-FEE, 
                      "win": 1 if (ep/entry-1)*direction>0 else 0, "bars": MAX_DAYS,
                      "date": dd.index[today_idx]})

# ── 结果 ──
if trades:
    td = pd.DataFrame(trades)
    print(f"\n交易: {len(td)}笔 胜率:{td['win'].mean():.1%} 均益:{td['ret'].mean()*10000:+.0f}bps "
          f"累计:{(1+td['ret']).prod():.4f}")
    for s in ["一买","三买","一卖","三卖"]:
        sub = td[td["sig"]==s]
        if len(sub)>0:
            print(f"  {s}: {len(sub)}笔 胜率{sub['win'].mean():.1%} 均益{sub['ret'].mean()*10000:+.0f}bps")
    td["mo"] = pd.to_datetime(td["date"]).dt.to_period("M")
    print(f"\n月度:\n{td.groupby('mo').agg(n=('ret','count'),wr=('win','mean'),cum=('ret',lambda x:(1+x).prod()-1)).round(3)}")
else:
    print("无信号")
