research: 低滞后信号口径定稿与实盘前偏差审计
fast_bsp3 改用 tol=-1 + require_touch=False,信号滞后从 5.8 根降到 2.2 根。 滞后与收益严格单调(年化 370% -> 906%,同一份数据同一套成本), 这是本轮提升的主因,也意味着实盘延迟会直接侵蚀收益。 新增 step31~39 验证策略能否落地: - 跨品种样本外——8 个未参与调参的币,PF 2.73 / t 28.5,无一为负 - 时点重建——只喂到信号那一根重算,同根命中 100%,确认无未来函数; 1m 在 2000 根窗口即饱和,计算耗时 0.20s - 偏差审计——多空对称、中枢生效时刻零回退、滑点稳健至 30bp、持仓几乎不重叠 - 消融——alpha 来自缠论中枢的上下文定位,而非「收盘转强」这个触发动作 补 research/HANDOFF.md:记录确切口径与参数、已排除的偏差、 已验证无效因而不必重做的方向,以及下一步用影子交易器实测执行滑点的方案。 清理 step1~20 的输出:早期方法论已被推翻(存在未来函数偏差), 其结论不再被引用;脚本保留,需要时可重跑。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,8 +4,17 @@
|
||||
此时价格已从回抽低点反弹完毕,入场价被吃掉。
|
||||
|
||||
但三买的形态条件本身是实时可判的:
|
||||
中枢已成 -> 收盘突破 zg -> 回抽最低不跌回中枢(low >= zg) -> 重新上行
|
||||
最后一步发生的当根就能下单,滞后 1~2 根。
|
||||
中枢已成 -> 收盘突破 zg -> 收盘未跌回中枢 -> 重新上行
|
||||
最后一步发生的当根就能下单,滞后约 2 根。
|
||||
|
||||
require_touch 控制是否强求回抽碰到中枢边界。step32/33 的实测表明
|
||||
强求反而更差:这等于排除掉「突破后一去不回头」的强势段,而那正是
|
||||
缠论里最强的趋势形态。故默认 False(笔数 +21%、滞后 -1 根、PF 2.26→2.37)。
|
||||
|
||||
判据本身(收盘越过前一根极值)没有独立预测力:裸用 15 万笔样本 PF 0.95,
|
||||
把中枢换成「近20根高点」这类伪阻力位后 PF 0.90。alpha 全部来自中枢结构,
|
||||
判据只负责在这个已知价位上确认动能恢复。它也不能用于识别笔端点——
|
||||
入场前的回抽极值命中笔端点±2根的比例 19.3%,低于随机基准 22%。
|
||||
|
||||
全部判定只使用当根及之前的数据,无未来函数。
|
||||
"""
|
||||
@@ -20,9 +29,10 @@ def find_fast_bsp3(
|
||||
zones: pd.DataFrame,
|
||||
scan: int = 200,
|
||||
pullback_win: int = 30,
|
||||
tol: float = 0.003,
|
||||
tol: float = -1.0,
|
||||
max_per_zone: int = 1,
|
||||
diag: dict | None = None,
|
||||
require_touch: bool = False,
|
||||
) -> pd.DataFrame:
|
||||
"""扫描每个中枢,找突破后回抽不回中枢的入场点。
|
||||
|
||||
@@ -30,6 +40,11 @@ def find_fast_bsp3(
|
||||
max_per_zone > 1 时,同一中枢在首次入场后继续往后找二次、三次突破回抽,
|
||||
用来检验「趋势里同一中枢反复给机会」是否值得做。
|
||||
|
||||
tol 是「算作回抽中」的边界容差。require_touch=False 时它不再是入场门槛,
|
||||
仅决定哪些K线被视为回抽中而跳过转强判定,故 tol 越大入场越晚。
|
||||
默认负值 = 完全禁用该跳过,突破后每根都检查转强,滞后压到 2.2 根。
|
||||
step34 实测滞后与收益严格单调:9.9根 PF1.88 / 5.8根 2.37 / 2.2根 2.86。
|
||||
|
||||
返回列:
|
||||
entry_idx 实时可下单的K线
|
||||
direction +1 三买 / -1 三卖
|
||||
@@ -108,12 +123,14 @@ def find_fast_bsp3(
|
||||
pb_ext, pb_idx = ext, j
|
||||
continue
|
||||
# 回抽后重新顺势:收盘创出前一根之上(三买)/ 之下(三卖)
|
||||
if touched and pb_idx is not None:
|
||||
# require_touch=False 时不强求回抽碰到中枢边界,
|
||||
# 这样「突破后一去不回头」的强势段也能收进来。
|
||||
if (touched and pb_idx is not None) or not require_touch:
|
||||
go = close[j] > high[j - 1] if d == 1 else close[j] < low[j - 1]
|
||||
if go:
|
||||
entry_idx = j
|
||||
break
|
||||
if entry_idx is None or pb_ext is None:
|
||||
if entry_idx is None:
|
||||
if occ == 1:
|
||||
note("×突破后跌回中枢" if fell_back
|
||||
else "×回抽未触及边界" if not touched
|
||||
@@ -121,6 +138,12 @@ def find_fast_bsp3(
|
||||
# 这次突破没走成,从突破点之后继续找下一次
|
||||
cursor = bo_idx + 1
|
||||
continue
|
||||
if pb_ext is None:
|
||||
# 未触及边界就转强(require_touch=False):取突破至入场间的实际极值
|
||||
seg = slice(bo_idx + 1, entry_idx + 1)
|
||||
pb_ext = float(low[seg].min() if d == 1 else high[seg].max())
|
||||
pb_idx = int((low[seg].argmin() if d == 1 else high[seg].argmax())
|
||||
+ bo_idx + 1)
|
||||
if occ == 1:
|
||||
note("√成交")
|
||||
|
||||
@@ -138,4 +161,10 @@ def find_fast_bsp3(
|
||||
})
|
||||
cursor = entry_idx + 1
|
||||
|
||||
return pd.DataFrame(rows)
|
||||
out = pd.DataFrame(rows)
|
||||
if out.empty:
|
||||
return out
|
||||
# 相邻中枢可能突破到同一根K线,同一时刻只能有一个仓位,保留最早成型的那个
|
||||
return (out.sort_values(["entry_idx", "occ", "zone_i"])
|
||||
.drop_duplicates("entry_idx", keep="first")
|
||||
.reset_index(drop=True))
|
||||
|
||||
Reference in New Issue
Block a user