site logo

Marico's space

完整 Polymarket Bot 架构:市场数据、策略、风险与执行

算法解析 2026-09-24 17:34:04 4

最近折腾 Polymarket 量化交易 Bot,踩了几个坑,这篇把核心架构问题说清楚。

当一个 Bot 开始真正做交易决策的时候,它就开始变得难以维护了。

拉取订单簿容易,发送订单也容易。真正的工程难题在于:市场状态、策略状态、订单状态、仓位、风险控制、执行行为这些模块全都在异步变化,你怎么保持它们之间的一致性?

这才是正经的 Polymarket Bot 架构要解决的问题。

作者:Bo$onaX

Polymarket 交易机器人 | 量化交易 | Rust | Web3 基础设施

GitHub:https://github.com/n9xdev/poly-alpha-lab
Telegram:https://t.me/bosonax
YouTube:https://youtube.com/@bosonax
X:https://x.com/xxniiinxx
Polymarket:https://polymarket.com/@bosona

我会实际搭建的系统

用六个边界来思考:

Market Discovery ↓
Market Data ───────→ Strategy Engine ↓ ↓
State Store ←──────── Decision ↓ ↓
Risk Engine ───────→ Execution Engine ↓ Polymarket CLOB ↓ Order / Fill Events ↓ Reconciliation

关键细节是底部的这个反馈循环。

Bot 不应该假设 HTTP 响应成功就意味着交易状态正确。一笔订单可能保持挂起、部分成交、完全成交、被取消,或者与 Bot 本地假设不一致。因此执行层需要把事件反馈到状态系统和风险系统。

1. 市场发现不是执行

Polymarket 将市场信息与交易基础设施分开。

当前的开发者文档将市场发现和市场元数据与 CLOB 交易分开暴露,有专门的概念处理市场、事件、价格、订单簿、仓位、订单和结算。

一个有用的发现服务应该维护:

  • 市场和事件标识符
  • 结果/代币标识符
  • 市场状态
  • 交易参数
  • 结算信息
  • 策略特定的适配性

在策略循环之前完成这些。

策略应该接收一个已经标准化过的市场对象,而不是在每次交易决策时重复查询元数据。

2. 实时数据应该驱动热路径

轮询 REST 接口适合初始化、恢复和定期对账。但作为对延迟敏感的决策循环的基础,它就差点意思了。

Polymarket 通过 WebSocket 基础设施提供实时市场数据和认证订单更新。官方文档也暴露了专门的实时数据和订单更新部分。

所以 Rust 实现可以这样分开:

WebSocket task ↓
event parser ↓
normalized event ↓
single-writer market state ↓
strategy

策略永远不应该直接修改原始 WebSocket 表示。

将交易所事件转换为内部类型,比如:

struct BookUpdate { token_id: String, best_bid: f64, best_ask: f64, timestamp_ns: u64,
}

对于生产级交易,用定点数或 Decimal 运算比随手用浮点数处理价格和数量要好得多。

3. 策略应该产出意图,而不是下单

这是值得保护的核心架构边界之一。

不要这样做:

strategy → API → order

应该这样做:

strategy → OrderIntent → risk → execution

比如:

struct OrderIntent { token_id: String, side: Side, price: Decimal, size: Decimal, reason: StrategyReason,
}

策略回答的是:

"我想要这个敞口。"

风险引擎回答的是:

"这个敞口允许吗?"

执行引擎回答的是:

"这个意图应该怎么到达交易所?"

这种分离让纸交易、回放测试、策略实验和紧急关停都变得简单得多。

4. 风险属于策略和交易所之间

一个盈利的信号仍然可能产生一个搞砸的交易系统。

风险层至少应该检查:

  • 当前仓位
  • 可用保证金
  • 最大仓位规模
  • 市场流动性
  • 订单集中度
  • 过时市场数据
  • 重复意图
  • 未完成订单
  • 策略级敞口
  • 全局熔断开关状态

Polymarket 自己也指出,当流动性不足时,期望的交易规模可能无法在不产生显著价格冲击的情况下执行。

这意味着仓位大小计算不能与实时订单簿分开。

一个有用的规则是:

signal strength ≠ permitted trade size

后者必须在风险和流动性约束应用后才能计算出来。

5. 执行是独立的子系统

执行引擎应该负责:

  • 订单构建
  • 签名/认证
  • 提交
  • 取消
  • 重试
  • 超时处理
  • 订单状态跟踪
  • 成交处理
  • 对账

当前 Polymarket 文档提供了认证、下单、订单管理和实时订单更新的专门工作流程。

不要把这些操作埋在策略代码里。

这样同一个策略可以使用不同的执行策略而不需要重写策略本身:

OrderIntent ├── passive limit execution ├── aggressive execution └── staged execution

执行策略也应该了解当前的费率规则。Polymarket 当前费率文档指出,费率根据市场类别而不同,在成交时收取,而做市商不收取交易费用。

6. 对账是 Bot 可靠性的保障

这是没经验的 Bot 通常会漏掉的组件。

维护两个概念:

Desired State
Actual Exchange State

然后持续对比它们。

比如:

local: order ABC = OPEN, 100 shares
remote: order ABC = FILLED, 63 shares

Bot 必须让自己的内部状态向交易所状态收敛,而不是盲目假设之前的命令成功了。

在重连、进程重启、网络故障或交易所端事件之后,对账就变成了恢复机制。

生产部署结构

一个实用的部署可以保持令人惊讶的小规模:

┌──────────────────────────────┐
│ Bot Process │
│ │
│ Discovery │
│ WebSocket Market Feed │
│ State Store │
│ Strategy │
│ Risk Engine │
│ Execution │
│ Reconciliation │
└──────────────┬───────────────┘ │ Polymarket APIs

不需要因为系统是交易 Bot 就搞二十个微服务。

只在故障隔离、扩展或运维归属真正需要的时候才拆分进程。

对于 Rust 实现,Tokio 提供了天然的异步运行时基础。保持热路径事件驱动,让状态转换显式,用关联 ID 记录每个决策,连接市场事件 → 策略决策 → 订单 → 成交。

值得测试的故障模式

在部署真实资金之前,刻意模拟:

  1. WebSocket 断连
  2. 重复市场事件
  3. 延迟订单确认
  4. 部分成交
  5. 取消失败
  6. 过时的订单簿状态
  7. 进程重启
  8. 交易所/接口超时
  9. 策略产生的重复订单
  10. 持仓期间风险引擎关闭

只在网络完美时才工作的 Bot 不是生产就绪的。

最重要的架构边界

最强的 Polymarket Bot 架构不是组件最多的那个。

而是每个重要状态转换都是显式的那个:

Market Event ↓
State Update ↓
Strategy Decision ↓
Risk Decision ↓
Execution ↓
Exchange Event ↓
Reconciliation

一旦这些边界清晰了,策略就变成了可替换的模块,而不是整个应用。

这就是好架构的真正优势:改变交易想法不应该需要重建周围的交易基础设施。

交易涉及执行、流动性、费率、模型和市场结算风险。本文中的例子描述的是工程架构,不代表预期的交易表现或盈利能力。