"""缠论 sample-in vs sample-out"""
import pandas as pd, numpy as np

df_raw = pd.read_parquet("data/btc_multidim.parquet")
d = df_raw.resample("1h").agg({"open":"first","high":"max","low":"min","close":"last"}).dropna()
H, L, C = d["high"].values, d["low"].values, d["close"].values; n = len(d)

d4h = df_raw.resample("4h").agg({"close":"last"}).dropna()
d4h["ma50"] = d4h["close"].rolling(50).mean()
d4h_up = d4h["close"] > d4h["ma50"]

fx = []
for i in range(1, n-1):
    if H[i] > H[i-1] and H[i] > H[i+1] and L[i] > L[i-1] and L[i] > L[i+1]:
        fx.append((i, "顶", H[i]))
    elif L[i] < L[i-1] and L[i] < L[i+1] and H[i] < H[i-1] and H[i] < H[i+1]:
        fx.append((i, "底", L[i]))

bi_all = []
i = 0
while i < len(fx) - 1:
    f1, j = fx[i], i+1
    while j < len(fx):
        f2 = fx[j]
        if f2[1] != f1[1] and f2[0] - f1[0] >= 2:
            if (f1[1]=="底" and f2[2]>f1[2]) or (f1[1]=="顶" and f2[2]<f1[2]):
                bi_all.append((f1[0], f2[0], "up" if f1[1]=="底" else "down", f1[2]))
                i = j; break
        j += 1
    if j == len(fx): break

def test(sl, tp, mb, htf, bi_list):
    trades = []
    for start_idx,_,dir_label,fx_px in bi_list:
        for j in range(start_idx+1, min(start_idx+12, n)):
            if abs(C[j]-fx_px)/fx_px > 0.012: continue
            dirc = 1 if dir_label=="up" else -1
            if htf:
                ts = d.index[j]
                hv = d4h_up.reindex([ts],method="ffill").values[0]
                if dirc==1 and not hv: continue
                if dirc==-1 and hv: continue
            entry, w, l = C[j], False, False
            for k in range(1,min(mb,n-j-1)):
                r = (C[j+k]/entry-1)*dirc
                if r <= -sl: trades.append(-sl-0.001); l=True; break
                elif r >= tp: trades.append(tp-0.001); w=True; break
            if not w and not l:
                trades.append((C[min(j+mb,n-1)]/entry-1)*dirc-0.001)
            break
    if len(trades) < 5: return None
    return {"n":len(trades), "wr":sum(1 for r in trades if r>0)/len(trades),
            "cum":np.prod([1+r for r in trades]), "avg":np.mean(trades)*10000}

split = int(n * 0.67)
bi_in = [b for b in bi_all if b[0] < split]
bi_out = [b for b in bi_all if b[0] >= split]

print(f"笔: {len(bi_all)} (样本内{len(bi_in)}/{len(bi_out)}样本外)")
print(f"\n{'参数':22s} {'样本内':>18s}  {'样本外':>18s}")
print(f"{'':22s} {'n胜率累计':>18s}  {'n胜率累计':>18s}")
print("-"*60)

for sl,tp,mb,htf,label in [
    (0.01,0.03,48,False,"SL1% TP3%"),
    (0.01,0.03,48,True,"SL1% TP3% +4H"),
    (0.015,0.045,72,True,"SL1.5% TP4.5% +4H"),
    (0.02,0.06,96,True,"SL2% TP6% +4H"),
]:
    ri = test(sl,tp,mb,htf,bi_in)
    ro = test(sl,tp,mb,htf,bi_out)
    if ri and ro:
        print(f"{label:22s} {ri['n']:3d} {ri['wr']:.0%} {ri['cum']:.3f}   {ro['n']:3d} {ro['wr']:.0%} {ro['cum']:.3f}")
