"""让数据说话：一周上涨的规律是什么？"""
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
n = len(d)
idx = d.index

fwd_5 = np.roll(C, -5) / C - 1  # 未来5天收益

# 把所有特征量化，看哪个最能预测5天上涨
features = {}

# 1. 价格形态
features["大阳线(实体>70%)"] = (C-O)/(H-L+1e-9) > 0.7
features["大阴线(实体>70%)"] = (O-C)/(H-L+1e-9) > 0.7
features["十字星(实体<10%)"] = abs(C-O)/(H-L+1e-9) < 0.1

# 2. 涨跌动量
ret_1 = C/np.roll(C,1)-1
features["连涨2天"] = (ret_1 > 0) & (np.roll(C,1)/np.roll(C,2)-1 > 0)
features["连跌2天"] = (ret_1 < 0) & (np.roll(C,1)/np.roll(C,2)-1 < 0)
features["大涨>3%"] = ret_1 > 0.03
features["大跌>3%"] = ret_1 < -0.03
features["涨>1.5%昨跌"] = (ret_1 > 0.015) & (np.roll(C,1)/np.roll(C,2)-1 < 0)  # 前一天跌今天涨

# 3. 成交量
vol_ma20 = pd.Series(V).rolling(20).mean().values
features["放量>1.5x"] = V > vol_ma20 * 1.5
features["放量>2x"] = V > vol_ma20 * 2
features["缩量<0.5x"] = V < vol_ma20 * 0.5

# 4. 布林带位置
ma20 = pd.Series(C).rolling(20).mean().values
std20 = pd.Series(C).rolling(20).std().values
features["布林下轨"] = C < ma20 - std20 * 2
features["布林上轨"] = C > ma20 + std20 * 2
features["布林中轨附近"] = abs(C/ma20-1) < 0.01

# 5. 关键位置
hk20 = pd.Series(H).rolling(20).max().values
lk20 = pd.Series(L).rolling(20).min().values
features["20日新高"] = C == hk20
features["20日新低"] = C == lk20
features["近高点(上5%)"] = C > hk20 * 0.95
features["近低点(下5%)"] = C < lk20 * 1.05

# 6. 趋势状态
ema20 = pd.Series(C).ewm(span=20).mean().values
ema50 = pd.Series(C).ewm(span=50).mean().values
ema200 = pd.Series(C).ewm(span=200).mean().values
features["多头(ema20>ema50)"] = ema20 > ema50
features["空头(ema20<ema50)"] = ema20 < ema50
features["多头(ema50>ema200)"] = ema50 > ema200

# 7. 波动率
atr14 = pd.Series(H-L).rolling(14).mean().values
atr_pct = atr14 / C
atr_ma20 = pd.Series(atr_pct).rolling(20).mean().values
features["波动放大"] = atr_pct > atr_ma20 * 1.5
features["波动缩小"] = atr_pct < atr_ma20 * 0.5

# 8. 价格形态组合
features["阳包阴(吞没)"] = (np.roll(C,1) < np.roll(O,1)) & (C > O) & (O <= np.roll(C,1)) & (C >= np.roll(O,1))
features["阴包阳(看跌吞没)"] = (np.roll(C,1) > np.roll(O,1)) & (C < O) & (O >= np.roll(C,1)) & (C <= np.roll(O,1))

print("="*75)
print("🔬 BTC日线：什么特征能预测未来5天上涨？")
print("="*75)
print(f"数据: {n}根日线 (2017-2024)")
print(f"基准胜率(随机猜涨): {(fwd_5>0).mean():.0%}")
print()
print(f"{'特征':<28s} {'信号数':>6s} {'胜率':>6s} {'均收益':>8s} {'vs基准':>7s}")
print("-"*60)

results = []
for name, mask in features.items():
    idxs = np.where(mask)[0]
    valid = [i for i in idxs if i+5 < n]
    if len(valid) < 10: continue
    wr = sum(1 for i in valid if fwd_5[i] > 0) / len(valid)
    avg = np.mean([fwd_5[i] for i in valid])
    base = (fwd_5[valid] > 0).mean()
    lift = wr - base
    results.append((name, len(valid), wr, avg, lift))

results.sort(key=lambda x: x[4], reverse=True)
for name, n, wr, avg, lift in results:
    flag = " 🔥" if lift > 0.05 else ""
    print(f"  {name:<28s} {n:>4d}笔 {wr:>5.0%} {avg*100:>+6.1f}% {lift:>+5.0%}{flag}")

# 最佳组合探索
print(f"\n{'='*75}")
print("🎯 特征组合（找>60%胜率的）")
print(f"{'='*75}")

combos = [
    ("放量大涨", (V > vol_ma20*1.5) & (ret_1 > 0.03)),
    ("布林下轨反弹", (C < ma20-std20*2) & (ret_1 > 0)),
    ("多头+回踩ema20", (ema20>ema50) & abs(C/ema20-1)<0.01),
    ("吞没+多头", features["阳包阴(吞没)"] & (ema20>ema50)),
    ("大跌后企稳", (ret_1 < -0.03) & (np.roll(C, -1) > np.roll(O, -1))),
    ("突破+放量", (C>hk20*0.99) & (V>vol_ma20*1.5)),
    ("连跌2天+今天涨", (np.roll(ret_1,1)<0)&(np.roll(C,1)/np.roll(C,2)-1<0)&(ret_1>0)),
    ("布林下轨+放量", (C<ma20-std20*2) & (V>vol_ma20*1.2)),
    ("3%涨幅+缩量", (ret_1>0.03) & (V<vol_ma20*0.8)),
    ("布林上轨+缩量做空", (C>ma20+std20*2) & (V<vol_ma20*0.5)),
]

for name, mask in combos:
    idxs = np.where(mask)[0]
    valid = [i for i in idxs if i+5 < n]
    if len(valid) < 8: continue
    wr = sum(1 for i in valid if fwd_5[i] > 0) / len(valid)
    avg = np.mean([fwd_5[i] for i in valid])
    print(f"  {name:<28s} {len(valid):>4d}笔 wr={wr:>5.0%} avg={avg*100:>+5.1f}%")

# 关键发现：信号+趋势过滤
print(f"\n{'='*75}")
print("🏆 关键发现：什么信号+趋势过滤最稳")
print(f"{'='*75}")

# 只看多头市场（ema20>ema50）中的信号
bull_market = ema20 > ema50
for name, mask in [
    ("放量大涨", (V>vol_ma20*1.5) & (ret_1>0.03)),
    ("吞没", features["阳包阴(吞没)"]),
    ("布林下轨反弹", (C<ma20-std20*2) & (ret_1>0)),
]:
    filtered = mask & bull_market
    idxs = np.where(filtered)[0]
    valid = [i for i in idxs if i+5 < n]
    if len(valid) < 5: continue
    wr = sum(1 for i in valid if fwd_5[i] > 0) / len(valid)
    avg = np.mean([fwd_5[i] for i in valid])
    print(f"  (多头){name}: {len(valid)}笔 wr={wr:.0%} avg={avg*100:+.1f}%")