把“未来函数”防护写成单元测试,而不是一句承诺
“我很小心”不是一种控制。扰动未来、断言当下不动——这是对“未来函数”的直接、机械的检测,而且会随代码库演进持续生效。
一句无法审计的承诺
每个回测都声称自己不偷看未来。可这种声称通常不可证伪——它埋在索引、移位(shift)和连接(join)里,这些地方极易出微妙的错,事后又很难检查。“我很小心”不是控制,是侥幸。
让它大声失败
把承诺变成测试。取输入序列,把决策点之后的每一根未来收益人为翻倍,再重新计算信号。如果策略没有用到任何未来信息,信号必须与之前逐位(bit-for-bit)完全一致:未来变了,当下却毫无察觉。只要有一个信号动了,就说明下游某处在向前读取数据,测试失败。
它为什么有效
未来泄漏——也就是交易软件语境里的“未来函数”:一个偷偷用了不该有的数据、事后重绘的指标——本质上就是“当前输出依赖于未来输入”。扰动未来、断言当下不变,正是对这种依赖最直接、最机械的检测。不需要人工 code review,而且会随代码库演进持续抓出回归。
落地
把它接成 CI 里的标准单元测试,紧挨着它所守护的 shift/lag 逻辑。再配一个显式、独立的 shift(1) 步骤,让滞后集中在一个看得见的地方,而不是散落在整条管线里。原则和这套工作的其余部分一脉相承:一个你能跑的控制,胜过一个你只是声称的控制。