"""找顶找底：让数据告诉我们真正的顶部底部特征"""
import pandas as pd, numpy as np

d = pd.read_parquet("/root/quant_pipeline/data/btc_daily.parquet")
w = pd.read_parquet("/root/quant_pipeline/data/btc_weekly.parquet")

# ── 周线数据 ──
WO,WH,WL,WC,WV = w["o"].values,w["h"].values,w["l"].values,w["c"].values,w["v"].values
nw = len(w)
w_idx = w.index

# ── 日线数据 ──
DO, DH, DL, DC, DV = d["o"].values,d["h"].values,d["l"].values,d["c"].values,d["v"].values
nd = len(d)
d_idx = d.index

# ═══════════════════════════════════
# 1. 先定义什么是"顶"和"底"
# ═══════════════════════════════════

# 底部：未来12周涨幅>20%
fwd_12w = np.roll(WC, -12) / WC - 1
true_bottom = (fwd_12w > 0.2)  # 未来12周涨超20%才是真底

# 顶部：未来12周跌幅>15%
true_top = (fwd_12w < -0.15)

print("="*70)
print("🔥 BTC周线找底找顶 - 特征分析")
print("="*70)
print(f"数据: {nw}根周线 (2017-2024)")
print(f"真底部(12周后涨>20%): {true_bottom.sum()}次")
print(f"真顶部(12周后跌>15%): {true_top.sum()}次")

# ═══════════════════════════════════
# 2. 周线特征
# ═══════════════════════════════════
# RSI(14)
delta_w = pd.Series(WC).diff()
gain_w = delta_w.clip(lower=0).rolling(14).mean()
loss_w = (-delta_w.clip(upper=0)).rolling(14).mean()
rsi_w = (100 - 100/(1+gain_w/(loss_w+1e-9))).values

# 均线
w_sma20 = pd.Series(WC).rolling(20).mean().values
w_sma50 = pd.Series(WC).rolling(50).mean().values
w_ema20 = pd.Series(WC).ewm(span=20).mean().values

# 成交量
w_vol_ma20 = pd.Series(WV).rolling(20).mean().values

# 周线级别涨跌幅
w_ret_1w = WC / np.roll(WC,1) - 1
w_ret_4w = WC / np.roll(WC,4) - 1
w_ret_8w = WC / np.roll(WC,8) - 1

# 布林带
w_ma20 = pd.Series(WC).rolling(20).mean().values
w_std20 = pd.Series(WC).rolling(20).std().values

print(f"\n{'='*70}")
print("📊 单因子预测能力（底部）")
print(f"{'='*70}")
print(f"{'特征':<30s} {'信号数':>5s} {'胜率':>7s} {'基准':>6s} {'提升':>7s}")
print("-"*60)

base_bottom_wr = true_bottom[50:].mean()  # 避开初期指标未初始化
base_top_wr = true_top[50:].mean()

# 底部候选特征
bottom_features = [
    ("RSI<30", rsi_w < 30),
    ("RSI<25", rsi_w < 25),
    ("RSI<20", rsi_w < 20),
    ("低于20周线", WC < w_sma20),
    ("低于50周线", WC < w_sma50),
    ("前4周跌>10%", w_ret_4w < -0.1),
    ("前8周跌>15%", w_ret_8w < -0.15),
    ("周线吞没", (np.roll(WC,1)<np.roll(WO,1)) & (WC>WO) & (WO<=np.roll(WC,1)) & (WC>=np.roll(WO,1))),
    ("放量下跌", (WV>w_vol_ma20*1.5) & (w_ret_1w<-0.03)),
    ("布林下轨", WC < w_ma20 - w_std20*2),
    ("放量+RSI<30", (WV>w_vol_ma20*1.5) & (rsi_w<30)),
    ("前8周跌>20%", w_ret_8w < -0.2),
    ("RSI<30+布林下轨", (rsi_w<30) & (WC < w_ma20-w_std20*2)),
    ("周线长下影", (WH-WL>0) & ((WC-WL)/(WH-WL+1e-9)>0.7)),
]

for name, mask in bottom_features:
    idxs = np.where(mask)[0]
    valid = [i for i in idxs if i+12 < nw and i > 50]
    if len(valid) < 5: continue
    wr = sum(1 for i in valid if true_bottom[i]) / len(valid)
    lift = wr - base_bottom_wr
    print(f"  {name:<28s} {len(valid):>3d}笔 {wr:>5.0%} {base_bottom_wr:>5.0%} {lift:>+5.0%}")

print(f"\n{'='*70}")
print("📊 单因子预测能力（顶部）")
print(f"{'='*70}")
print(f"{'特征':<30s} {'信号数':>5s} {'胜率':>7s} {'基准':>6s} {'提升':>7s}")
print("-"*60)

top_features = [
    ("RSI>75", rsi_w > 75),
    ("RSI>80", rsi_w > 80),
    ("RSI>85", rsi_w > 85),
    ("高于20周线2x", WC > w_sma20*2),
    ("前4周涨>15%", w_ret_4w > 0.15),
    ("前8周涨>25%", w_ret_8w > 0.25),
    ("周线看跌吞没", (np.roll(WC,1)>np.roll(WO,1)) & (WC<WO) & (WO>=np.roll(WC,1)) & (WC<=np.roll(WO,1))),
    ("放量上涨", (WV>w_vol_ma20*1.5) & (w_ret_1w>0.03)),
    ("布林上轨", WC > w_ma20 + w_std20*2),
    ("RSI>75+布林上轨", (rsi_w>75) & (WC>w_ma20+w_std20*2)),
    ("前8周涨>40%", w_ret_8w > 0.4),
    ("放量+RSI>75", (WV>w_vol_ma20*1.5) & (rsi_w>75)),
]

for name, mask in top_features:
    idxs = np.where(mask)[0]
    valid = [i for i in idxs if i+12 < nw and i > 50]
    if len(valid) < 5: continue
    wr = sum(1 for i in valid if true_top[i]) / len(valid)
    lift = wr - base_top_wr
    print(f"  {name:<28s} {len(valid):>3d}笔 {wr:>5.0%} {base_top_wr:>5.0%} {lift:>+5.0%}")

# ═══════════════════════════════════
# 3. 最佳组合（找顶/找底）
# ═══════════════════════════════════
print(f"\n{'='*70}")
print("🏆 最佳找底组合")
print(f"{'='*70}")

best_bottom = [
    ("RSI<25+低于50周线", (rsi_w<25) & (WC<w_sma50)),
    ("RSI<30+前8周跌>15%", (rsi_w<30) & (w_ret_8w<-0.15)),
    ("RSI<25+前8周跌>15%", (rsi_w<25) & (w_ret_8w<-0.15)),
    ("RSI<30+低于20周线", (rsi_w<30) & (WC<w_sma20)),
    ("RSI<25+长下影", (rsi_w<25) & ((WC-WL)/(WH-WL+1e-9)>0.6)),
    ("RSI<20+布林下轨", (rsi_w<20) & (WC<w_ma20-w_std20*2)),
    ("RSI<30+放量+低于20周", (rsi_w<30) & (WV>w_vol_ma20*1.2) & (WC<w_sma20)),
]

for name, mask in best_bottom:
    idxs = np.where(mask)[0]
    valid = [i for i in idxs if i+12 < nw and i > 50]
    if len(valid) < 3: continue
    wr = sum(1 for i in valid if true_bottom[i]) / len(valid)
    avg_r = np.mean([fwd_12w[i] for i in valid])
    print(f"  {name:<35s} {len(valid):>2d}笔 胜率{wr:>3.0%} 均收益{avg_r*100:+.0f}%")

    # 显示详情
    if len(valid) <= 10:
        for i in valid:
            print(f"    {w_idx[i].date()}: ${WC[i]:.0f} RSI={rsi_w[i]:.0f} → 12周后{fwd_12w[i]:+.0%}")

print(f"\n{'='*70}")
print("🏆 最佳找顶组合（做空）")
print(f"{'='*70}")

fwd_12w_short = -fwd_12w  # 做空看跌

best_top = [
    ("RSI>80+前8周涨>25%", (rsi_w>80) & (w_ret_8w>0.25)),
    ("RSI>75+布林上轨", (rsi_w>75) & (WC>w_ma20+w_std20*2)),
    ("RSI>80+放量", (rsi_w>80) & (WV>w_vol_ma20*1.5)),
    ("RSI>75+高于20周线2x", (rsi_w>75) & (WC>w_sma20*2)),
    ("RSI>85+布林上轨", (rsi_w>85) & (WC>w_ma20+w_std20*2)),
    ("RSI>80+前4周涨>15%", (rsi_w>80) & (w_ret_4w>0.15)),
]

for name, mask in best_top:
    idxs = np.where(mask)[0]
    valid = [i for i in idxs if i+12 < nw and i > 50]
    if len(valid) < 3: continue
    wr = sum(1 for i in valid if true_top[i]) / len(valid)
    avg_r = np.mean([-fwd_12w[i] for i in valid])
    print(f"  {name:<35s} {len(valid):>2d}笔 胜率{wr:>3.0%} 均收益{avg_r*100:+.0f}%")
    if len(valid) <= 10:
        for i in valid:
            fwd = -fwd_12w[i]
            print(f"    {w_idx[i].date()}: ${WC[i]:.0f} RSI={rsi_w[i]:.0f} → 12周后{fwd:+.0%}")