股票策略有没有未来函数:用截断行情检查历史信号
确定性股票策略在删除或修改后续行情后,已经完成的历史信号应保持一致。做法是把实际生成函数分别运行于完整行情和多个历史前缀,逐行比较共同区间,再改变未来值。交付物是能定位到截断长度和具体行的失败表,不能只搜索几个可疑函数名就宣布没有未来函数。
本指南用合成收盘价提供一个因果参考函数和三个故意泄漏未来的函数。它不证明财务事实当年已经可得,不证明模型训练资料没有未来信息,也不证明完整交易系统无偏。CoTrading策略测试能力仍为规划或待核实,样例是独立的Python标准库验收工具。
先规定什么必须保持不变
设索引某行的完整收盘信号只能依赖从零到当前行的输入。先运行完整数据,再运行前若干行,在共同历史区间比较全部输出,包括前缀最后一条已完成行情。这个契约假设传入行已经完整,不适用于尚在变化的盘中蜡烛;输入完整性本身也要有明确边界。
如果策略有意把订单延后一交易日,要比较相同层。可以先验收延迟前的决策信号,也可以统一比较延迟后的目标。不能因为最后一行暴露错误,就把它临时豁免。确实需要未来成熟的标签,应按预先写好的输出契约排除,而不是看完失败才调整比较范围。
每次运行重置状态,固定配置、输入顺序、证券映射和源码版本。时钟调用、可变全局持仓、外部模型请求也可能改变结果,不一定直接读取了未来价格。这种差异仍需调查,但报告应先说明观察到什么,再追原因,不能把所有不一致都草率归为某一种未来函数。
先建立小型因果参考
参考规则为当前收盘严格大于当前与之前两条收盘的平均时输出一,前两行输出零。计算切片只到当前行,不会把后续价格纳入。函数没有随机、外部文件和网络依赖,适合隔离价格窗口这一条信息路径。
诊断输入为[10, 10, 10, 12, 1000, 1, 500]。后段夸张值是故意设计的扰动,不是价格预测,也不是实际历史行情。它们的作用是让隐藏依赖真正跨过布尔阈值。若未来值虽然改变均值,却没有改变最终零一信号,测试可能看不见问题。
参考函数通过全部测试前缀;把最后三条改为十三、九、八后,前四条输出仍一致。这个结果只覆盖给定实现与输入,不代表所有分支永远无误。真实策略加入缺值、同分、热身切换或多证券处理后,还要围绕这些边界增加可区分的样本。
三个不同机制的泄漏
第一种错误使用下一条收盘与当前收盘比较,类似对输入做负向位移。前缀最后一行暂时没有下一条,追加未来行情后,该历史信号就改变。零起点索引的报告为:截断长度三影响行二,长度四影响行三,长度六影响行五。这不是执行延迟问题,而是判断本身读了未出现的值。
第二种错误把每条收盘与全样本均值比较。只有前四条时,均值来自十、十、十、十二,十二高于均值;完整数据加入一千和五百后,同一历史十二不再高于均值。报告为截断长度四、行三失败。全局最大值、全样本标准差也可能走同一条信息路径,即使代码没有负位移。
第三种错误使用居中窗口,窗口包含下一条观察。前四条时,十二高于十和十二的平均;追加一千后,该行居中平均改变,信号翻转。失败位置同样是长度四、行三,但根因与全样本归一化不同。记录实际使用的输入切片,才能区分“全历史统计量”与“局部多看一行”。
比较器要输出能修复的信息
独立标准库文件为docs/growth/research/round-5/examples/R574.py,依次检查从三到完整长度减一的全部前缀。核心比较如下:
full = generate(closes)
for cutoff in range(3, len(closes)):
prefix = generate(closes[:cutoff])
changed = [i for i in range(cutoff) if prefix[i] != full[i]]
正式报告还应保存函数身份、截断长度、受影响行、前缀值、完整运行值和该行输入窗口。数值分数可以预先规定容忍度;本例是离散输出,要求精确一致。另外断言输出长度和时间戳,否则错位数组可能在截取时制造假通过。不要只打印一个总失败数,让修复者继续猜是哪一天。
运行python docs/growth/research/round-5/examples/R574.py。断言要求参考函数无失败,三种错误函数各有失败,未来扰动后因果历史相同,而全均值历史改变。这里故意触发的失败属于测试通过的证据。若为了输出好看而删除错误函数,反而使测试失去证明检测器能捕获问题的能力。
修复信息路径再全量重跑
把未来比较改成明确向后的决策定义,不能先算出泄漏信号,再简单延后一行就认为已经治好。全样本变换应改成只用允许观察拟合的扩展或滚动变换;当前收盘可用的决策通常应使用尾部窗口。每项修改都要核对经济规则是否仍相同,含义变化则更新策略规格。
先重跑原失败前缀,再重跑其他所有前缀。保留最小失败输入,让未来重构不能把错误重新带回来。Python测试官方文档说明了固定输入与检查的角色;本例用直接断言,保持独立文件无额外依赖。正式项目可以把同样案例组织成测试集,而不必改变验收逻辑。
反例说明通过结果的边界
普通序列[10, 10, 10, 12, 13, 9, 8]并不会让每个错误函数都改变零一输出。它说明带偏函数也可能通过选择不足的样例。更极端输入能够跨过阈值,才暴露全均值与居中窗口。一个前缀通过远弱于多边界、多种未来扰动同时通过,不能把未发现当成不存在。
最后检查上游数据。若预先合并的利润面板已经使用未来修订,完整运行和前缀运行都会读取同一个污染历史值,前缀测试仍可通过。模型也可能通过训练期资料编码后续信息,而不是现场读取追加行情。验收报告因此只能声称被测试代码路径通过了这些扰动,之后仍需核对来源可得日、训练区间与成交时点。增加新变换、外部依赖或输出约定时,同时更新测试,不让旧的绿色结果覆盖新的信息路径。
下载完整示例,保存为R574.py,使用Python 3.12及以上运行python R574.py。仅使用标准库与合成数据。
修正版也要成为独立验收工件
下载文件另有三个修正版:未来收盘比较改为当前与前一收盘比较,全局均值改为截至当前行的扩展均值,居中比较改为因果三观察尾部规则。它们明确改变决策定义,因此需要在策略规格中确认,不能伪装成无关格式修复。若原作者真正想预测下一日涨跌,那是标签用途,不能直接把尚未知的比较结果当当日持仓信号。
三个修正版逐一重跑相同前缀,每个失败列表必须为空;改变最后三条未来值后,前四条也必须一致。原错误函数和修正版同时保存,让后来检查者确认检测器确实能捕获旧错误,也能接受新的合法信息路径。只保留修正版而丢掉旧反例,会失去检查测试灵敏度的依据,后续重构可能让检测器本身退化却无人发现。
还需防止“永远输出零”的伪修复。它可以满足前缀不变,却破坏策略原意。因此除了时间一致,还要核对正常路径的预期信号。两项义务分别是“不读取未来”和“按确认规则决策”,通过前者不会自动通过后者。对于多证券策略,逐列保存标识与时间,排除列重排造成的假差异;对于有状态函数,每次从一致初始状态开始,避免把旧实例残留误判成行情前视。
最终报告同时列通过函数、被成功检出的错误函数和未覆盖依赖。这样读者不会把故意触发的失败误当成脚本坏了,也不会把修正版通过误当成全管线已经无偏。保留输入与源码指纹,后续再次运行才知道验证的是否仍是同一件事。
常见问题
搜索负位移是否足够?
不够。全样本统计量和居中窗口不需要负位移也会泄漏,隐藏依赖还会导致其他不一致。
全部通过是否证明回测无偏?
只能说明指定生成器通过这些输入扰动,不能证明上游全部历史信息真实可用。