"""日线找底 - 周线确认（修复索引映射）"""
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")

# 日线数据
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

# 周线均线
w_sma20_arr = pd.Series(w["c"].values).rolling(20).mean().values

# 对每个日线找到对应周线位置（前向填充）
d["week_end"] = d.index + pd.Timedelta(days=6 - d.index.dayofweek)
d = d.merge(w[["c"]].rename(columns={"c":"w_close"}), left_on="week_end", right_index=True, how="left", suffixes=("","_drop"))
# 前向填充
d["w_close"] = d["w_close"].ffill()

# 周线指标
w["w_sma20"] = w["c"].rolling(20).mean()
w["w_rsi14"] = 100 - 100 / (1 + w["c"].diff().clip(lower=0).rolling(14).mean() / (w["c"].diff().clip(upper=0).abs().rolling(14).mean() + 1e-9))

d = d.merge(w[["w_sma20","w_rsi14"]], left_on="week_end", right_index=True, how="left", suffixes=("","_drop2"))
d["w_sma20"] = d["w_sma20"].ffill()
d["w_rsi14"] = d["w_rsi14"].ffill()

# ── 周线级别状态 ──
d["in_bear"] = d["close"] < d["w_sma20"]
d["w_rsi_low"] = d["w_rsi14"] < 30

# ── 日线找底形态 ──
h_l = d["high"] - d["low"] + 1e-9
body = abs(d["close"] - d["open"])
d["hammer"] = (d["close"] > d["open"]) & ((d["low"] - d["close"] + body) / h_l > 0.6) & (body / h_l < 0.3)
d["engulf_bull"] = (d["close"].shift(1) < d["open"].shift(1)) & (d["close"] > d["open"]) & (d["open"] <= d["close"].shift(1)) & (d["close"] >= d["open"].shift(1))
d["piercing"] = (d["close"].shift(1) < d["open"].shift(1)) & (d["close"] > d["open"]) & (d["open"] < d["low"].shift(1)) & (d["close"] > (d["open"].shift(1)+d["close"].shift(1))/2)

vol_ma20 = d["volume"].rolling(20).mean()
ret_1 = d["close"].pct_change()
d["vol_surge"] = d["volume"] > vol_ma20 * 1.5
d["reversal"] = (ret_1.shift(1) < -0.02) & (ret_1 > 0.02) & d["vol_surge"]

# ── 信号 ──
d["sig1"] = d["in_bear"] & d["hammer"]  # 锤子线+熊市
d["sig2"] = d["in_bear"] & (d["engulf_bull"] | d["piercing"])  # 吞没+熊市
d["sig3"] = d["in_bear"] & d["reversal"]  # 放量反转
d["sig_all"] = d["sig1"] | d["sig2"] | d["sig3"]

# ── 回测 ──
test_start = "2023-01-01"
train = d.index < test_start
test = d.index >= test_start

C_arr = d["close"].values
nd_arr = len(C_arr)

print("="*70)
print("🔥 日线找底 - 周线熊市确认")
print("="*70)
print(f"数据: {nd_arr}根日线 训练<2023 测试>=2023")

for sig_name, sig_col in [("锤子线", "sig1"), ("吞没/刺透", "sig2"), ("放量反转", "sig3"), ("全部", "sig_all")]:
    train_valid = [i for i in np.where(sig_col & train) if i+20 < nd_arr] if hasattr(sig_col, 'values') else []
    # 用values
    col_vals = d[sig_col].values
    train_vals = train.values
    
    train_idxs = [i for i in range(nd_arr) if col_vals[i] and train_vals[i] and i+20 < nd_arr]
    test_idxs = [i for i in range(nd_arr) if col_vals[i] and not train_vals[i] and i+20 < nd_arr]
    
    for period_name, idxs in [("训练", train_idxs), ("测试", test_idxs)]:
        if len(idxs) < 3: continue
        fwd = np.array([C_arr[min(i+20, nd_arr-1)]/C_arr[i]-1 for i in idxs])
        wr = sum(1 for r in fwd if r > 0.05) / len(idxs)
        avg = np.mean(fwd)*100
        print(f"  {sig_name:<15s} {period_name}: {len(idxs):>3d}笔 涨>5%胜率{wr:>3.0%} 均收益{avg:.0f}%")

# 最佳方案详情（测试集）
print(f"\n{'='*70}")
print("🏆 最佳方案：锤子线+熊市")
print(f"{'='*70}")

test_idxs = [i for i in range(nd_arr) if col_vals[i] and not train_vals[i] and i+20 < nd_arr]
for col_name in ["sig1", "sig2", "sig3"]:
    col_vals2 = d[col_name].values
    tidxs = [i for i in range(nd_arr) if col_vals2[i] and not train_vals[i] and i+20 < nd_arr]
    if len(tidxs) < 3: continue
    
    print(f"\n  {col_name} ({len(tidxs)}笔):")
    for days in [5, 10, 20, 30]:
        fwd = np.array([C_arr[min(i+days, nd_arr-1)]/C_arr[i]-1 for i in tidxs])
        wr = sum(1 for r in fwd if r > 0) / len(tidxs)
        avg = np.mean(fwd)*100
        print(f"    {days:>2d}天后: 胜率{wr:.0%} 均收益{avg:+.1f}%")
    
    # 固定SL/TP回测
    rets = []
    for i in tidxs:
        entry = C_arr[i]
        hit = False
        for j in range(1, min(21, nd_arr-i)):
            r = C_arr[i+j]/entry - 1
            if r >= 0.06: rets.append(0.06); hit=True; break
            if r <= -0.03: rets.append(-0.03); hit=True; break
        if not hit: rets.append(C_arr[min(i+20, nd_arr-1)]/entry - 1)
    
    wr = sum(1 for r in rets if r>0)/len(rets)
    cum = np.prod([1+r for r in rets])
    lev10 = np.prod([1+r*10 for r in rets])
    print(f"    SL3% TP6%: {wr:.0%} 累计{cum:.2f} 10x杠杆{lev10:.1f}x")