用 ETF 验证缠论三买:一次回测应该怎样避免自我欺骗
从 CZSC 的 Signal、Event 与 Position 分层出发,设计可复核的 ETF 三买实验,并识别短样本、重复信号和复权陷阱。
“现在有没有三买?”是一个很容易得到答案、却很难得到可信答案的问题。一次历史 Codex 会话里,我用 CZSC 的现成示例对 ETF 分钟线做三买研究。跑出交易列表后,比信号本身更值得复盘的是:预热区间如何处理、不同三买算法如何比较、重复触发是否被算成多笔交易、复权价格能不能用于实际下单。
本文只讨论研究方法,不提供当前买卖结论,也不构成投资建议。
信号、事件和仓位是三层对象
CZSC 的底层 signal 只描述某个时刻的技术状态,例如 30 分钟级别是否出现三买。上层 Event 把一个或多个 signal 组合成“开多/平多”条件,Position 再加入止损、超时、最小开仓间隔、T+0 约束和状态机。
这三层不能混在一起:
1
2
3
4
K 线与缠论结构
→ Signal:此刻符合哪种三买
→ Event:哪些 signal 组合触发操作
→ Position:当前是否允许开仓、如何退出
同一个三买 signal 连续多根 K 线成立,不代表每天都能建立一笔新仓。若没有最小间隔、去重或单仓约束,回测可能把一个结构重复计算成多次独立机会。
三种“三买”并不等价
项目中可用于实验的实现至少包括:
cxt_third_buy_V230228:纯笔结构三买;cxt_third_bs_V230318:均线辅助的三买/三卖;cxt_third_bs_V230319:增加均线形态确认。
比较时应把它们视为不同策略定义,而不是同一个指标的三个版本号。更严格的规则通常信号更少、回撤可能更低,但小样本中一次交易就会显著改变胜率和收益。
合理的实验表应同时给出:触发次数、完整交易数、持有时间、胜率、盈亏分布、最大回撤、暴露时间和未完成持仓。只展示累计收益,会隐藏规则究竟靠高频重复、单次偶然大赚还是稳定小优势。
预热数据不能进入绩效区间
缠论笔、中枢和多周期状态需要足够历史。若研究窗口从 6 月开始,不能只从 6 月第一天取数据,否则开头一段结构处于冷启动。
正确做法是向前额外拉取数月作为 warm-up,让分析器建立状态,但只统计目标 as-of 区间内产生的操作。报告中应同时写:
- 数据加载起点;
- 绩效统计起点;
- 截止时间与最后完整 bar;
- 基础周期与目标周期;
- warm-up 是否参与收益。
把预热期的优秀交易偷偷算进目标区间,是一种隐蔽的样本选择偏差。
分钟线质量会直接改变三买结构
三买依赖笔和中枢,缺一根 bar、时间标签错一档或午休分桶不一致,都可能改变分型。研究前至少检查:
- 每个完整交易日 bar 数;
- 时间从开盘到收盘是否按结束时刻标记;
- 1 分钟合成与供应商原生目标周期是否一致;
- 停牌、零成交与缺失数据如何处理;
- 代码和 ETF 上市日期是否 point-in-time 正确。
短期上市 ETF 尤其危险:样本可能只有一百多个交易日,恰好又处于单一市场阶段。此时漂亮胜率首先是案例描述,不是泛化证据。
复权序列用于信号,不用于委托
前复权与后复权通常保持形态和比例关系,适合连续历史分析;不复权价格才是当时真实成交尺度。建议把三者职责分开:
- 信号研究:固定一种复权口径并记录因子版本;
- 绩效:用真实可交易收益、手续费、滑点与涨跌停约束;
- 操作明细:同时展示信号用价格与当时不复权价格;
- 实盘委托:重新读取不复权盘口,绝不直接使用后复权价。
如果复权因子使用了查询截止日之后的信息,也会产生 point-in-time 泄漏。回测数据应在每个历史时点只使用当时可获得的公司行动与行情。
当前无信号也是有效结果
策略研究很容易为了“有内容”而更换标的、窗口或参数,直到出现想要的信号。这其实是在结果之后选择问题。
更诚实的流程是先固定:标的集合、截止时间、周期、三买版本、退出规则和成本,再运行一次。当前没有信号,就报告无信号以及距离上次触发的时间;不要临时放宽规则并把新结果与原策略混在一起。
下一步验证应跨多个 ETF、多个市场阶段和滚动区间,分离开发样本与留出样本。参数只在训练期选择,留出期一次性评估;再做手续费、滑点、延迟和容量敏感性分析。
一个回测的价值,不是证明“三买有效”,而是让别人可以复现你在什么数据、什么规则和什么限制下看到了什么。能明确说出“当前没有信号、样本太短、结论不能外推”,往往比一条漂亮净值线更接近研究。
项目地址:cyijun/czsc