"""Step 18:两条存活路径的正面对比与尾部检验。 路径一 同级别中枢突破(step13) 1389 笔 PF 1.63 路径二 区间套快速三买(step17) 239 笔 PF 1.52 样本量差 6 倍,但真正决定能否上实盘的是尾部依赖: step14 已发现路径一剔掉最赚的 5% 后 t 值就从 6.45 塌到 1.60。 本步用同一把尺子量路径二。 """ from __future__ import annotations import sys import warnings from pathlib import Path import numpy as np import pandas as pd warnings.filterwarnings("ignore") pd.set_option("display.width", 260) OUT = Path(__file__).parent / "out" FEE = 0.0008 def trim_curve(r: np.ndarray, label: str) -> list[dict]: rows = [] for k in (0, 1, 2, 5, 10): v = r if k == 0 else r[r <= np.quantile(r, 1 - k / 100)] win, loss = v[v > 0], v[v <= 0] pf = win.sum() / abs(loss.sum()) if len(loss) and loss.sum() != 0 else np.inf sd = v.std(ddof=1) rows.append({ "路径": label, "剔除最赚": f"{k}%", "笔数": len(v), "均收益": f"{v.mean() * 100:+.3f}%", "PF": f"{pf:.2f}", "t值": f"{v.mean() / (sd / np.sqrt(len(v))):+.2f}", }) return rows def profile(r: np.ndarray, label: str) -> dict: win, loss = r[r > 0], r[r <= 0] sd = r.std(ddof=1) return { "路径": label, "笔数": len(r), "胜率": f"{(r > 0).mean() * 100:.1f}%", "均收益": f"{r.mean() * 100:+.3f}%", "中位数": f"{np.median(r) * 100:+.3f}%", "PF": f"{win.sum() / abs(loss.sum()):.2f}", "偏度": f"{pd.Series(r).skew():.2f}", "t值": f"{r.mean() / (sd / np.sqrt(len(r))):+.2f}", } def main() -> None: p1 = pd.read_csv(OUT / "step13_all_trades.csv", parse_dates=["date"]) p2 = pd.read_csv(OUT / "step17_fast_bsp3_trades.csv", parse_dates=["date"]) r1, r2 = p1["ret"].to_numpy(), p2["ret"].to_numpy() # 区间套的最优组合:1h 同向 + 浅回抽 dq = p2["depth"].quantile(0.66) best = p2[(p2["h1_agree"] == 1) & (p2["depth"] >= dq)] r3 = best["ret"].to_numpy() print("########## 1. 总体画像 ##########") print(pd.DataFrame([ profile(r1, "同级别中枢突破"), profile(r2, "区间套快速三买"), profile(r3, "区间套(同向+浅回抽)"), ]).to_string(index=False)) print("\n 中位数为正说明多数交易在赚钱,为负则说明靠尾部。") print("\n########## 2. 尾部依赖检验 ##########") rows = trim_curve(r1, "中枢突破") + trim_curve(r2, "区间套三买") d = pd.DataFrame(rows).pivot(index="剔除最赚", columns="路径", values=["PF", "t值"]) print(d.to_string()) print("\n########## 3. 成本敏感性 ##########") rows = [] for mult, name in [(1, "0.08%"), (2, "0.16%"), (3, "0.24%"), (5, "0.40%")]: for r, lab in ((r1, "中枢突破"), (r2, "区间套三买")): v = r - (mult - 1) * FEE win, loss = v[v > 0], v[v <= 0] sd = v.std(ddof=1) rows.append({ "成本": name, "路径": lab, "PF": f"{win.sum() / abs(loss.sum()):.2f}", "t值": f"{v.mean() / (sd / np.sqrt(len(v))):+.2f}", }) print(pd.DataFrame(rows).pivot(index="成本", columns="路径", values=["PF", "t值"]).to_string()) print("\n########## 4. 收益分位对比 ##########") qs = [0.05, 0.25, 0.5, 0.75, 0.95] print(pd.DataFrame({ "分位": [f"P{int(q * 100)}" for q in qs], "中枢突破": [f"{np.quantile(r1, q) * 100:+.2f}%" for q in qs], "区间套三买": [f"{np.quantile(r2, q) * 100:+.2f}%" for q in qs], }).to_string(index=False)) print("\n########## 5. 交易频率 ##########") for r, t, lab in ((r1, p1, "中枢突破"), (r2, p2, "区间套三买")): yrs = (t["date"].max() - t["date"].min()).days / 365.25 print(f" {lab:>10}:{len(r) / yrs:.0f} 笔/年 " f"覆盖 {t['date'].min().date()} -> {t['date'].max().date()}") if __name__ == "__main__": main()