研究文章
N / 260822

回测结果对了还不够:为什么 Polymarket Bot 生产代码必须逐笔复现

Polymarket Trading Bot 的研究脚本总收益对上并不代表策略实现正确。本文解释为什么我们检查逐笔时间、方向、STOP、状态与未改动区间的一致性。

假设研究脚本跑出来:

总得分 +1000

生产代码重放以后也是:

总得分 +1000

能不能说明实现正确?

不能。

因为两个总数完全可能通过不同错误互相抵消。

例如:

研究:A 赢,B 输
生产:A 输,B 赢

总分可能刚好一样。

但策略已经不是同一个策略。

这也是为什么我们现在对一个 Polymarket Bot 的验收,不只看最终结果,而是尽可能看逐笔一致性


研究策略和生产策略是两个不同系统

研究阶段通常追求:

  • 快速试验;
  • 批量统计;
  • 方便修改;
  • 容易切片;
  • 容易比较不同候选。

生产系统则需要:

  • 实时维护状态;
  • 处理数据异常;
  • 跟踪订单;
  • 持久化;
  • 恢复;
  • 并发;
  • 保证规则优先级。

即使两边“写的是同一个策略”,实现结构也可能完全不同。

所以一个非常现实的风险是:

研究里验证的是 A,生产里实际跑成了 A’。

这种偏差不一定会报错。

它可能安静地存在很久。


最危险的是“看起来差不多”

例如两个特征都叫:

“最近一段时间的方向切换次数”

研究脚本和生产代码可能各自都有一个名字很像的字段。

肉眼一看:

应该可以复用。

但只要定义里有一点差异:

  • 一个统计 K 线自身方向;
  • 一个统计相邻收盘变化;
  • 一个窗口边界多算一根;
  • 一个对平盘的处理不同;

它们就不是同一个特征。

这种 bug 很难靠总收益发现。

因为很多时候它只会改变少量边界事件。

但这些少量事件可能正好决定:

KEEP / ADJUST / STOP

所以验收不能只比较最终 PnL

我们的公开回测说明里,升级验收会检查:

  • 信号时间;
  • 目标窗口;
  • 来源;
  • 基础方向;
  • 后置动作;
  • 最终方向;
  • STOP;
  • 结果;
  • 数据连续性;
  • 未修改区间的逐笔一致性。

这里最关键的是最后一项。

如果我只改了一条非常局部的规则,我不仅要确认:

新规则命中的事件变成了预期结果。

还要确认:

本来不应该受影响的大量历史事件没有被我意外改掉。


一个公开的实际例子:4,098 条既有信号

在一次公开报告记录的增量刷新里,从 2025-10-01 到上一次截止点,共有 4,098 条已经验收过的既有信号

重新运行后,我们检查了:

  • 时间索引;
  • 关键决策字段。

结果保持一致。

长期状态数值中出现的差异只在浮点误差量级,并没有造成任何逐笔决策改变。

这个检查没有让回测“多赚一分”。

但它回答了一个更重要的问题:

我们只是更新数据,还是不小心改变了历史策略行为?


为什么总结果一致还可能隐藏 bug

还有一种常见情况:

研究规则设计成:

某类情况 → STOP

生产实现却因为优先级错误,变成:

先被另一条规则处理
→ 新 STOP 永远到不了

最终总得分甚至可能变化不大。

但你以为上线的逻辑,其实根本没有上线。

反过来也可能发生:

新规则插入得太早,意外覆盖了旧规则。

所以验收还要关心:

  • 规则插入位置;
  • 作用域;
  • 哪些历史事件应该被改变;
  • 哪些历史事件绝对不应该改变。

为什么逐笔复现比“重新写一份回测”更重要

如果研究脚本和生产代码是两套完全独立的逻辑,我们最终会面对:

research truth
vs
production truth

到底谁才是真的?

我更喜欢的做法是:

用生产代码本身去重放历史。

这样至少可以把一个问题消掉:

“上线的代码到底是不是你回测的那套代码?”

这并不能解决所有问题。

但它能显著降低研究实现和生产实现漂移。


逐笔一致也不等于实盘一致

这里还要再加一层限制。

生产代码历史重放能够证明:

生产决策逻辑在历史数据上复现了预期策略行为。

它不能证明:

真实订单会按相同价格和数量成交。

因为真实 Polymarket 执行还有:

  • order book;
  • fees;
  • latency;
  • GTD / FAK / FOK 等订单生命周期;
  • partial fill;
  • cancel;
  • API 状态。

Polymarket 官方的订单生命周期本身就是状态机,不是一个瞬时的 buy()

所以我会把:

策略一致性

和:

执行一致性

分开看。


我现在习惯把策略升级分成三次验收

高层可以理解成:

1. 研究验收

这个想法本身有没有足够证据?

2. 代码验收

生产实现有没有逐笔复现研究逻辑?

3. 运行验收

真实环境中的数据、订单和状态有没有按预期工作?

任何一层都可能让一个“好策略”最终变成坏结果。


最后:为什么这种细节值得写

从外面看,Polymarket Bot 很容易被简化成:

data
↓
signal
↓
order

真正长期做下去,最花时间的反而是这些:

两个看起来一样的定义到底是不是一样?

改一条规则有没有误伤别的历史事件?

总数相同是不是因为错误刚好抵消?

研究脚本和生产实现有没有漂移?

这些问题不会让标题变得很性感。

但它们决定了你到底在回测一个策略,还是在回测一个“你以为生产环境会运行的策略”。


公开回测与一致性方法:

Polymarket BTC 5m Public Backtest Report

Polymarket 官方执行参考:

相关阅读:

本文讨论策略验证方法,不公开内部公式、参数、规则优先级或可用于复现策略的代码。