"""一类反手(fade B1/S1)是不是真的——逐币、分时段、与 B4 的重叠。 step55 的反向对照给出 5m/15m 上 PF 2.35~3.03、t +10~+13,且多空两边都正。 数字太好,先按 §3.392 的教训做证伪:那次「周末效应」在 1m 上显著,换到 7 年 5m/15m 样本就消失且符号反转。任何单一样本上的漂亮结果都要先过三关。 逐币 5 个币是不是都成立,还是被某一个币带起来的 分时段 前后半段样本各自是否成立(时间外样本) 与 B4 重叠 如果它只是换个名字的 B4,那就没有增量价值 """ from __future__ import annotations import sys import warnings from pathlib import Path import numpy as np import pandas as pd warnings.filterwarnings("ignore") HERE = Path(__file__).resolve().parent sys.path.insert(0, str(HERE)) sys.path.insert(0, str(HERE.parent)) from lib.exit_model import fee_of, taker_notional # noqa: E402 SRC = HERE / "out" / "step55_bsp12.feather" SL = 2.0 def stats(g: pd.DataFrame) -> dict: """反手口径的统计。f_* 是 step55 里用相反方向重跑出场得到的。""" net = g.f_g.values - fee_of(g.f_r.values, g.f_c.values) gR = g.f_g.values / (SL * g.atr_pct.values) R = net / (SL * g.atr_pct.values) tn = taker_notional(g.f_r.values, g.f_c.values) w, o = net[net > 0].sum(), -net[net <= 0].sum() return { "笔数": len(g), "胜率": f"{(net > 0).mean()*100:.1f}%", "毛R": round(gR.mean(), 3), "净均R": round(R.mean(), 3), "PF": round(w / o, 2) if o > 0 else np.inf, "余量bp": round(net.mean() / tn.mean() * 1e4, 2), "t值": round(gR.mean() / (gR.std(ddof=1) / np.sqrt(len(g))), 2), } def main() -> None: d = pd.read_feather(SRC) if "f_g" not in d.columns: print("step55 数据里没有反手列,先重跑 step55") return d["date_ext"] = pd.to_datetime(d["date_ext"]) one = d[d.type.isin(["B1", "S1"])].copy() for tf, x in one.groupby("tf"): print("\n" + "#" * 92) print(f"########## {tf} · 一类反手 ##########") print("\n【逐币】任何一个币独自撑起来的结果都不能要") print(pd.DataFrame([{"币": s, **stats(g)} for s, g in x.groupby("sym")]).to_string(index=False)) print("\n【分时段】按信号时间中位数切两半,后半段是时间外样本") cut = x.date_ext.median() for nm, g in (("前半", x[x.date_ext <= cut]), ("后半", x[x.date_ext > cut])): r = stats(g) print(f" {nm} {g.date_ext.min():%Y-%m-%d}~{g.date_ext.max():%Y-%m-%d}" f" {r}") print("\n【分方向】B1反手=做空,S1反手=做多。只有一边成立就是单边行情") print(pd.DataFrame([{"原类型": t, **stats(g)} for t, g in x.groupby("type")]).to_string(index=False)) print("\n【逐年】") rows = [] for y, g in x.groupby(x.date_ext.dt.year): if len(g) >= 40: rows.append({"年": y, **stats(g)}) if rows: print(pd.DataFrame(rows).to_string(index=False)) if __name__ == "__main__": main()