跨日滚动 Donchian 通道:让第一天就有有效信号
30 根 5 分钟 K 线的回看窗口若只在当日会话内计算,每个交易日前 2.5 小时不可能有任何信号。把通道滚动跨越会话边界可以找回开盘时段——代价是隔夜跳空对通道的扭曲,需要单独的处理策略。
盲区
5 分钟 K 线上的 30 根 Donchian 通道,需要 30 根已完成的 K 线才有定义。若只在当日会话内计算,意味着每个交易日前 2.5 小时不可能有任何有效信号——入场被构造性地挤进上午晚段和午盘,任何专属于开盘时段的优势在结构上不可观测。这是一种安静的时段选择偏差:回测根本看不见它排除掉的那个市场状态。
修复:rolling_rth
各 Donchian 项目采用的通道口径是 rolling_rth:对每根信号 K 线,回看窗口取此前已完成的 RTH K 线;当日不足 N 根时,向前借用上一交易日(必要时更早)的 RTH K 线。实现就是在连续多日的 RTH 数据帧上做普通滚动窗口:
out["channel_upper"] = out["high"].rolling(lookback, min_periods=lookback).max().shift(1)
out["channel_lower"] = out["low"].rolling(lookback, min_periods=lookback).min().shift(1)
.shift(1) 保证当前 K 线不进入自己的通道。两条边界是刻意保留的:
- **通道跨日滚动,信号不跨日。**每个会话的第一根 K 线被强制置零入场信号——不隔夜持仓,也不允许把开盘第一笔行情本身宣布为“突破”。
- 交易记录携带
bars_from_prior_sessions_in_channel与is_opening_signal,开盘时段的交易可以被单独审计。
修复带来的跳空问题
有隔夜跳空时,早盘的通道有一部分由昨天的波动范围构成。跳空高开几乎“天然突破”昨日通道;被跳空抬高的波幅又会把基于 ATR 的止损设得过宽。项目的评审流程明确标记了这一点,规格层面的回答是可配置的跳空策略——ATR 默认 intraday_true_range_only,敏感性变体含 include_gap 与 cap_gap_at_p95。SPX 是现货指数反而帮了忙:没有隔夜盘需要建模,只有收盘到开盘之间 17.5 小时的结构性空白。
必须与通道口径保持一致的配套细节:半日交易自动检测(最后一根 K 线在 14:00 前 → 截止从 15:50 改为 12:50);startup_no_trade_minutes 网格(0–30 分钟)控制开盘后多久允许入场——因为 0DTE 期权的价差在开盘头几分钟最宽。
教训
指标的 warmup 规则是策略决策,不是实现细节。“指标从什么时候开始有定义”决定了回测被允许观测哪些市场状态——把这个选择显式化、加上可审计的埋点,并对它制造的边界做压力测试。