"""日线趋势跟踪：吃一周趋势"""
import pandas as pd, numpy as np

d = pd.read_parquet("/root/quant_pipeline/data/btc_daily.parquet")
O,H,L,C,V = d["o"].values,d["h"].values,d["l"].values,d["c"].values,d["v"].values
O1,C1 = np.roll(O,1),np.roll(C,1)
n = len(d)
idx = d.index

print(f"日线: {n}根  {idx[0].date()} ~ {idx[-1].date()}")

# ── 均线 ──
ema10 = pd.Series(C).ewm(span=10, adjust=False).mean().values
ema20 = pd.Series(C).ewm(span=20, adjust=False).mean().values
ema50 = pd.Series(C).ewm(span=50, adjust=False).mean().values
sma200 = pd.Series(C).rolling(200).mean().values

# ── 方向判断 ──
trend_up = ema10 > ema20  # 短期均线在长期均线上方=多头

# ── 入场：趋势+回调+回到均线 ──
# 回调到ema20附近（价格在ema20上下1.5%范围内）
near_ema20 = abs(C / ema20 - 1) < 0.015
# 确认回调：前一天跌/今天涨
ret_prev = C / np.roll(C,1) - 1
ret_prev2 = np.roll(C,1) / np.roll(C,2) - 1
pullback_end = (ret_prev2 < -0.01) & (ret_prev > 0)  # 前一天跌，今天涨

# 做多信号
long_sig = trend_up & near_ema20

# ── 持仓5天（一周交易日）──
SL = 0.02  # 2%止损
TP = 0.05  # 5%止盈
HOLD = 5  # 5个交易日

# 回测
def backtest(sig_mask, dirc):
    results = {"all": []}
    wins, losses = 0, 0
    sig_idx = np.where(sig_mask)[0]
    
    for i in sig_idx:
        if i + HOLD >= n: continue
        entry = C[i]
        closed = False
        for j in range(1, HOLD+1):
            if i+j >= n: break
            ret = (C[i+j]/entry-1) * dirc
            if ret >= TP:
                results["all"].append(TP)
                wins += 1; closed = True; break
            if ret <= -SL:
                results["all"].append(-SL)
                losses += 1; closed = True; break
        if not closed:
            fr = (C[min(i+HOLD,n-1)]/entry-1) * dirc
            results["all"].append(fr)
            if fr > 0: wins += 1
            else: losses += 1
    
    results["wins"] = wins
    results["losses"] = losses
    return results

print(f"\n{'='*60}")
print("🔥 日线趋势跟踪（均线回踩）")
print(f"{'='*60}")
print(f"入场: 趋势多头 + 价格在ema20附近")
print(f"持仓: 5个交易日  SL={SL*100:.0f}%  TP={TP*100:.0f}%")

r = backtest(long_sig, 1)
total = r["wins"] + r["losses"]
wr = r["wins"] / total if total > 0 else 0
cum = np.prod([1+r for r in r["all"]]) if r["all"] else 1
print(f"\n总信号: {total}笔  胜率{wr:.0%}  累计{cum:.2f}")

# 分年度
print(f"\n📊 分年度表现:")
d["year"] = d.index.year
for yr in sorted(d["year"].unique()):
    yr_mask = d.index.year == yr
    yr_idx = np.where(long_sig & yr_mask.values)[0] if hasattr(d.index, 'year') else []
    # 重新计算
    yr_wins, yr_losses = 0, 0
    for i in np.where(long_sig)[0]:
        if i + HOLD >= n: continue
        if d.index[i].year != yr: continue
        entry = C[i]; closed = False
        for j in range(1, HOLD+1):
            if i+j >= n: break
            ret = (C[i+j]/entry-1)
            if ret >= TP: yr_wins+=1; closed=True; break
            if ret <= -SL: yr_losses+=1; closed=True; break
        if not closed:
            fr = (C[min(i+HOLD,n-1)]/entry-1)
            if fr > 0: yr_wins+=1
            else: yr_losses+=1
    yr_total = yr_wins + yr_losses
    if yr_total >= 3:
        print(f"  {yr}: {yr_total}笔 胜率{yr_wins/yr_total:.0%}")

# 测试不同参数
print(f"\n📊 参数扫优化:")

best_params = []
for hold in [3, 5, 7, 10]:
    for sl in [0.015, 0.02, 0.03]:
        for tp_sl in [2, 2.5, 3]:
            tp = sl * tp_sl
            wins, losses = 0, 0
            sig_idx = np.where(long_sig)[0]
            for i in sig_idx:
                if i + hold >= n: continue
                entry = C[i]; closed = False
                for j in range(1, hold+1):
                    if i+j >= n: break
                    ret = (C[i+j]/entry-1)
                    if ret >= tp: wins+=1; closed=True; break
                    if ret <= -sl: losses+=1; closed=True; break
                if not closed:
                    fr = (C[min(i+hold,n-1)]/entry-1)
                    if fr > 0: wins+=1
                    else: losses+=1
            total = wins + losses
            if total >= 20:
                wr = wins/total
                pf = (wins*tp)/(losses*sl) if losses > 0 else 99
                best_params.append((hold, sl, tp, total, wr, pf))

best_params.sort(key=lambda x: x[4], reverse=True)  # 按胜率排
print(f"{'持有天数':>6s} {'SL':>5s} {'TP':>5s} {'笔数':>5s} {'胜率':>6s} {'ProfitFactor':>12s}")
print("-"*45)
for hold, sl, tp, n, wr, pf in best_params[:10]:
    print(f"{hold:>5d}天 {sl*100:>4.0f}% {tp*100:>4.0f}% {n:>4d} {wr:>5.0%} {pf:>11.2f}")

# 最优方案详情
print(f"\n{'='*60}")
print("🏆 最优方案：持有5天 SL=2% TP=5%")
print(f"{'='*60}")

sig_idx = np.where(long_sig)[0]
hold, sl, tp = 5, 0.02, 0.05
all_rets = []
for i in sig_idx:
    if i + hold >= n: continue
    entry = C[i]; closed = False
    for j in range(1, hold+1):
        if i+j >= n: break
        ret = (C[i+j]/entry-1)
        if ret >= tp: all_rets.append(tp); break
        if ret <= -sl: all_rets.append(-sl); break
    if not closed:
        all_rets.append((C[min(i+hold,n-1)]/entry-1))

wr = sum(1 for r in all_rets if r>0)/len(all_rets)
cum = np.prod([1+r for r in all_rets])
print(f"总{len(all_rets)}笔 胜率{wr:.0%} 累计{cum:.2f}")

# 模拟10x杠杆
lev_rets = [r * 10 for r in all_rets]
lev_cum = np.prod([1+r for r in lev_rets])
max_draw = 0; running = 1
for r in lev_rets:
    running *= (1+r)
for r in lev_rets:
    running = 1; peak = 1
    for r2 in lev_rets:
        running *= (1+r2)
        peak = max(peak, running)
    max_draw = min(max_draw, (running-peak)/peak)
print(f"10x杠杆: 累计{lev_cum:.1f}x")