"""烛龙交易分析：逐笔拆解盈利/亏损交易，找规律"""
import pandas as pd, numpy as np

df_raw = pd.read_parquet("data/btc_multidim.parquet")
df_raw.columns = [c.lower() for c in df_raw.columns]
d = df_raw.resample("1h").agg({"open":"first","high":"max","low":"min","close":"last","volume":"sum"}).dropna()

O,H,L,C,V = d["open"].values,d["high"].values,d["low"].values,d["close"].values,d["volume"].values
O1,H1,L1,C1 = np.roll(O,1),np.roll(H,1),np.roll(L,1),np.roll(C,1)
n = len(d)

dd = df_raw.resample("1D").agg({"close":"last"}).dropna()
dd["ma20"] = dd["close"].rolling(20).mean()
dd["trend_up"] = dd["close"] > dd["ma20"]
d_ts = d.index
trend_1h = np.array([dd["trend_up"].reindex([ts], method="ffill").values[0] if ts >= dd.index[0] else True for ts in d_ts])

prev_l20 = pd.Series(L).shift(1).rolling(20).min().values
prev_h20 = pd.Series(H).shift(1).rolling(20).max().values
near_s = abs(L - prev_l20) / (prev_l20 + 1e-9) < 0.008
near_r = abs(H - prev_h20) / (prev_h20 + 1e-9) < 0.008

bull_engulf = (C1<O1) & (C>O) & (O<=C1) & (C>=O1)
nbull = np.roll(C,-1) > np.roll(O,-1)
long_raw = bull_engulf & near_s & nbull

swup = (H>pd.Series(H).shift(1).rolling(20).max().values) & (C<pd.Series(H).shift(1).rolling(20).max().values)
nbear = np.roll(C,-1) < np.roll(O,-1)
short_raw = swup & near_r & nbear

lsig = long_raw & trend_1h
ssig = short_raw & (~trend_1h)

vol_mean20 = pd.Series(V).rolling(20).mean().values
split = int(n * 0.67)
SL, TP, MB = 0.015, 0.045, 48

# ── 收集每笔交易的详细信息 ──
trades = []

for period, st, en in [("样本内",0,split), ("样本外",split,n)]:
    for mask, dirc in [(lsig,1), (ssig,-1)]:
        for i in range(st, min(en,n)):
            if not mask[i]: continue
            if i+MB>=n: continue
            
            entry = C[i]
            
            # 开仓时的各种特征
            vol_ratio = V[i] / vol_mean20[i]  # 当前量/均值
            k_line_range = H[i] - L[i]  # K线振幅
            body_size = abs(C[i] - O[i])  # K线实体
            body_ratio = body_size / (k_line_range + 1e-9)  # 实体占比
            
            # 关键位距离（相对于入场价）
            sup_dist = abs(C[i] - prev_l20[i]) / C[i]  # 距支撑
            res_dist = abs(C[i] - prev_h20[i]) / C[i]  # 距阻力
            
            # 近期走势
            ret_1 = C[i]/C[i-1]-1
            ret_3 = C[i]/C[i-3]-1 if i>=3 else 0
            ret_6 = C[i]/C[i-6]-1 if i>=6 else 0
            
            # 前一根K线
            prev_ret = C[i-1]/C[i-2]-1 if i>=2 else 0
            prev_body = abs(C[i-1]-O[i-1])
            prev_vol_ratio = V[i-1] / vol_mean20[i-1] if i>0 else 0
            
            # 确认K线
            confirm_ret = C[i+1]/C[i]-1  # 确认方向
            confirm_body = abs(C[i+1]-O[i+1])
            
            # ── 回测这笔交易 ──
            closed = False
            bar_count = 0
            max_favor = 0  # 最大浮盈
            max_against = 0  # 最大浮亏
            
            for j in range(1, MB+1):
                if i+j>=n: break
                ret = (C[i+j]/entry-1)*dirc
                bar_count = j
                if ret > max_favor: max_favor = ret
                if ret < max_against: max_against = ret
                
                if ret>=TP:
                    trades.append({
                        "period": period, "dirc": "long" if dirc==1 else "short",
                        "time": d.index[i], "entry": entry,
                        "exit": C[i+j], "pnl": TP-0.001,
                        "bars": bar_count, "reason": "TP",
                        "max_favor": max_favor, "max_against": max_against,
                        "vol_ratio": vol_ratio, "body_ratio": body_ratio,
                        "k_range": k_line_range, "sup_dist": sup_dist, "res_dist": res_dist,
                        "ret_1": ret_1, "ret_3": ret_3, "ret_6": ret_6,
                        "prev_ret": prev_ret, "prev_vol": prev_vol_ratio,
                        "confirm_ret": confirm_ret,
                        "trend": "up" if trend_1h[i] else "down",
                    })
                    closed=True; break
                if ret<=-SL:
                    trades.append({
                        "period": period, "dirc": "long" if dirc==1 else "short",
                        "time": d.index[i], "entry": entry,
                        "exit": C[i+j], "pnl": -SL-0.001,
                        "bars": bar_count, "reason": "SL",
                        "max_favor": max_favor, "max_against": max_against,
                        "vol_ratio": vol_ratio, "body_ratio": body_ratio,
                        "k_range": k_line_range, "sup_dist": sup_dist, "res_dist": res_dist,
                        "ret_1": ret_1, "ret_3": ret_3, "ret_6": ret_6,
                        "prev_ret": prev_ret, "prev_vol": prev_vol_ratio,
                        "confirm_ret": confirm_ret,
                        "trend": "up" if trend_1h[i] else "down",
                    })
                    closed=True; break
            
            if not closed:
                fr = (C[min(i+MB,n-1)]/entry-1)*dirc
                trades.append({
                    "period": period, "dirc": "long" if dirc==1 else "short",
                    "time": d.index[i], "entry": entry,
                    "exit": C[min(i+MB,n-1)], "pnl": fr-0.001,
                    "bars": MB, "reason": "timeout",
                    "max_favor": max_favor, "max_against": max_against,
                    "vol_ratio": vol_ratio, "body_ratio": body_ratio,
                    "k_range": k_line_range, "sup_dist": sup_dist, "res_dist": res_dist,
                    "ret_1": ret_1, "ret_3": ret_3, "ret_6": ret_6,
                    "prev_ret": prev_ret, "prev_vol": prev_vol_ratio,
                    "confirm_ret": confirm_ret,
                    "trend": "up" if trend_1h[i] else "down",
                })

df_trades = pd.DataFrame(trades)
print(f"共 {len(df_trades)} 笔交易")
print(f"\n各原因分布:")
print(df_trades.groupby("reason").agg(
    笔数=("pnl","count"), 胜率=("pnl",lambda x: (x>0).mean()),
    均收益=("pnl",lambda x: f"{x.mean()*100:.2f}%"),
    累计=("pnl",lambda x: f"{np.prod(1+x):.3f}")
))

print(f"\n{'='*70}")
print(f"📊 盈利 vs 亏损 对比（只看样本外）")
print(f"{'='*70}")

out = df_trades[df_trades["period"]=="样本外"]
wins = out[out["pnl"]>0]
losses = out[out["pnl"]<0]

print(f"\n盈利: {len(wins)}笔  亏损: {len(losses)}笔")

features = ["vol_ratio","body_ratio","k_range","sup_dist","res_dist",
            "ret_1","ret_3","ret_6","prev_ret","confirm_ret","bars"]

for feat in features:
    w_mean = wins[feat].mean() if feat in wins.columns else 0
    l_mean = losses[feat].mean() if feat in losses.columns else 0
    w_median = wins[feat].median() if feat in wins.columns else 0
    l_median = losses[feat].median() if feat in losses.columns else 0
    
    diff_pct = ((w_mean - l_mean) / (abs(l_mean)+1e-9)) * 100
    star = " ⭐" if abs(diff_pct) > 15 else ""
    print(f"  {feat:15s}: 盈利均值={w_mean:.4f}  亏损均值={l_mean:.4f}  差异={diff_pct:+.0f}%{star}")
    print(f"   {'':15s}  盈利中位={w_median:.4f}  亏损中位={l_median:.4f}")

# 找出最有区分度的特征
print(f"\n{'='*70}")
print(f"🔍 特征分析——按特征分组看胜率")
print(f"{'='*70}")

# 放量维度
for threshold in [0.8, 1.0, 1.2, 1.5, 2.0]:
    sub = out[out["vol_ratio"]>threshold]
    if len(sub)>=3:
        wr = (sub["pnl"]>0).mean()
        print(f"  放量>{threshold:.1f}x均值: {len(sub)}笔  胜率={wr:.1%}")

print()
# 前一根K线收益
for threshold in [-0.005, 0, 0.005, 0.01]:
    sub = out[out["prev_ret"]>threshold] if threshold>=0 else out[out["prev_ret"]<threshold]
    dir_str = ">" if threshold>=0 else "<"
    if len(sub)>=3:
        wr = (sub["pnl"]>0).mean()
        print(f"  前K收益{dir_str}{threshold:+.4f}: {len(sub)}笔  胜率={wr:.1%}")

print()
# 入场前短期走势
for threshold in [-0.01, -0.005, 0, 0.005, 0.01]:
    sub = out[out["ret_3"]>threshold] if threshold>=0 else out[out["ret_3"]<threshold]
    dir_str = ">" if threshold>=0 else "<"
    if len(sub)>=3:
        wr = (sub["pnl"]>0).mean()
        print(f"  3h涨幅{dir_str}{threshold:+.4f}: {len(sub)}笔  胜率={wr:.1%}")

# 近因分析：最近几个月
print(f"\n{'='*70}")
print(f"📅 时间维度分析")
print(f"{'='*70}")
out["month"] = pd.to_datetime(out["time"]).dt.to_period("M")
monthly = out.groupby("month").agg(笔数=("pnl","count"), 胜率=("pnl",lambda x: (x>0).mean()), 累计=("pnl",lambda x: np.prod(1+x)))
print(monthly)

# 交易时长分析
print(f"\n{'='*70}")
print(f"⏱ 持仓时间分析")
print(f"{'='*70}")
for b in [6, 12, 24, 36, 48]:
    sub = out[out["bars"]<=b]
    if len(sub)>=3:
        wr = (sub["pnl"]>0).mean()
        cum = np.prod(1+sub["pnl"])
        print(f"  持仓<={b}h: {len(sub)}笔  胜率={wr:.1%}  累计={cum:.3f}")