Skip to main content
跨场馆做市需要同时拿到四样东西:价格、深度、将订单送回场馆所需的标识符,以及对「这条报价还作数吗」的诚实回答。四者都在同一条赔率行上到达,因此新增一个场馆只是改一个过滤条件,而不是一个集成项目。 本指南讲的是建立在该数据流之上的交易决策。负载结构见 odds 频道页。

每条价格上带来什么

无需二次查询,也无需按场馆分支解析:阶梯在每个交易所与预测市场上语义一致,back 的首条即盘口顶部,与 price 一致。结构细节见高级元数据。

构建跨场馆视图

按选项分组 —— 同一选项在两个场馆上的键,只有场馆那一段不同:
然后在您有权限的场馆中取最高 back 与最低 lay。即便您只会吃单边,两侧也都要保留 —— 最窄的价差显示共识落在哪里,而报在其外的场馆要么携带了信息,要么携带了一条陈旧价格。判断是哪一种要看时间戳,价格本身给不出答案。
最优 back 恒等于 price。而这里的 lay 一侧离它极远 —— 100.0 上只有 15 单位的意愿,这是一个单边盘口,而不是您能报在其内的价差。 三个容易踩的坑:
  • 交叉盘口是信号,而不是机会。 若某场馆的最优 back 高于另一场馆的最优 lay,先核对双方的 changedAt。真实交叉会在毫秒级内消失;持续存在的交叉意味着其中一方已停止更新。
  • 深度按场馆计,绝不可汇总。 您无法用一个场馆的订单去吃另一个场馆的队列。请按场馆建模可执行规模,再在选项层面汇总,而不是在盘口层面。
  • size 以场馆的基础货币计价。 比较跨加密货币场馆的深度前,先通过 currencies 频道换算,否则同样的敞口会读成两个不同的数字。

定量:limit 与深度各司其职

  • limit 约束单笔订单 —— 场馆在这个价格上最多接受多少。参见投注限额。
  • 阶梯约束成交结果 —— 触及价之后还挂着多少量,以及清掉某个规模要付出多少成本。
请沿阶梯走到目标规模,并以成交量加权均价而非触及价来给这笔成交定价:
这条阶梯上共挂着 550,因此目标规模 100 会以 6.369 成交 30、以 6.20 成交 70 —— 均价为 6.251,而不是屏幕上的 6.369。limit 约束的完全是另一回事:无论盘口多深,单笔订单都不得超过 50。 限额下调以普通赔率更新的形式、在同一个 oddsId 上到达,且往往是更早出现的那个信号。完整论述(包括 limit 是唯一规模信号的传统博彩商)参见 sharp 线路交易与 CLV。

门控:这条报价可交易吗

新鲜度与价格价值是两个独立问题,而判断错时真正付出代价的是前者。四个标志位可以否决,且彼此独立: 其中两项来自与价格不同的频道,而这正是那种故障的样子 —— 一条既完美无缺又不可交易的报价:
staleOdds 是最容易被漏掉的一个,因为您收到的最后一条价格看上去毫无异常 —— 您手上的价格可能已在场馆侧变动,而我们无从告知。在它变回 false 之前,请撤回报价而不是重新定价。参见自动化交易关键字段。 再加一道属于您自己的第五关 —— 对照博彩商在 GET /bookmakers 上公布的 maxDelayLiveInSec / maxDelayPregameInSec 做时效检查。在最初几秒里,一个安静的场馆和一个故障的场馆看起来是一样的。参见状态信号。请把这五项作为同一个判定在每次更新时求值,而不是靠定时器。
在赛事盘口上,participantsRotated 是性质不同的第六道检查:为 true 时,该场馆的主客场分配与我们相反,这会颠倒基于方向的 outcome 含义,并翻转让分的符号。它影响的是正确性而非新鲜度 —— 而如果您按位置而不是按 ID 映射 outcome,它的影响是无声的。

延迟预算

您的反应时间由四段构成,其中您能掌控的只有一段: 每条消息都携带前三个时间戳,因此这一拆分可以按场馆实测,而不必只凭信任:
因此「对所有场馆采用统一报价策略」是错的:同一标的上,一个 0.05 秒的场馆与一个约 1 秒的场馆理应对应不同的价差,而用于参数化这一点的数值是公布出来的,不需要推测。若某场馆重新定价的速度快于您闭环的速度,就报在其后或减小规模 —— 不要去追它的盘口顶部。

熬过数据空档

最糟糕的状态是以为某个盘口是最新的并据此报价,而事实并非如此。所以:先撤报价,再做对账。
  • 服务端发起的重连 —— 发布前我们会推送 reconnect 控制帧,并在一小段宽限期内继续推送。请对这个帧作出反应,而不是等待随后的套接字错误。
  • 在重放窗口内 —— 携带每频道游标(serverEpoch + entryId)重连,遗漏的更新会被无缝重放。
  • 超出窗口 —— 网关发出 snapshot_required;用一次 REST 快照恢复。这是最坏情况有界的既定路径,而不是错误。
  • serverEpoch 发生变化 —— 旧游标已失去意义;请重新快照而不是恢复。
机制见恢复和重放。请按场馆维护一个「最后已知良好」时间戳,并让它独立于套接字是否连着来门控报价 —— 套接字活着、背后场馆却已冻结,才是真正会造成损失的那种故障。

将订单路由回场馆

场馆原生 ID 就挂在价格本身上,因此您决策的那一刻,不是需要再做一次查询的时刻:
后两个字段就是 Polymarket 自己的盘口与选项标识符,且已在您手中:这笔订单就是以 price 报在 bookmakerOutcomeId 上,投注额不超过 limit。 在赛事层面,GET /fixtures/mapping 支持双向解析 —— 传入 fixtureIds 获取场馆 ID,传入 bookmakerFixtureIds 反查回来。bookmakers 频道同样携带 bookmakerFixtureId 与 fixturePath,因此人工交易台也能直接打开场馆自己的页面。

跨场馆定价

定价之前先按 marketId 分组:同一 marketId 下的所有 outcome 构成完整的概率空间,计算水位与做完整性检查都需要它 —— 而每个线值都是独立的 marketId,因此一个盘口绝不会悄悄混入不同线值。 先在各场馆内归一化,再跨场馆合并。有两种权重是数据显式支持的:
  • 按规模加权 —— 展示出真实深度、limit 也较高的场馆,比在同一价格上只挂象征性数量的场馆构成更强的观测。
  • 按延迟加权 —— 实测上界在 100 毫秒以内的场馆与上界为数秒的场馆,其当前程度并不相等。
成交审计、回测与收盘线请用 REST 历史赔率与 CLV 接口,它们与实时数据流共用同一 oddsId 键,因此决策与其审计轨迹无需任何转换即可关联。

非体育市场即期货

政治、选举、金融、加密货币与天气被建模为 sportId 69+ 的运动,且仅以期货形式存在 —— 每个冠军盘口对应一个期货,走 futures 与 oddsFutures 频道,交付语义相同,订单簿 meta 也相同。上文内容全部原样适用。
某个期货问的是哪个问题由 market.marketId 给出 —— 即 futureId 末尾同样携带的 5 位 futureMarketId,按运动分配(69002 = 政治 Prediction)。某条价格对应哪个选择项取决于盘口的形态: 单个可分解期货盘口会跨越多条线值,且与赛事盘口不同,让分位于 outcome 上而非盘口上。请从显式字段读取二者,而不要拆分 oddsId —— 参见期货赔率ID与期货如何运作。

接入步骤

1

订阅数据流

连接 wss://v5.oddspapi.io/ws,并以您交易的频道、运动和场馆登录。请在订阅 odds 的同时订阅 bookmakers —— 没有它,您有价格但没有陈旧度信号。
2

快照

在更新已经流入的情况下,通过 REST(/fixtures/odds 或 /futures/odds)初始化,并按键以较新的 changedAt 合并。先连接是初始化无空档的原因 —— 不存在从 REST 带到 WebSocket 的游标,也不需要。
3

应用更新

以 oddsId 为键就地覆盖。每条消息是状态,而非一次跳动。
4

门控

在每次更新时、按场馆求值报价判定函数,再让价格进入下游任何环节。
5

恢复

将 reconnect 与 snapshot_required 当作既定路径来处理。
在登录时过滤 —— sportIds、tournamentIds 和 bookmakers 削减消息量的效果远好于客户端过滤 —— 并在规模化时于 odds 上优先使用 receiveType: "zstd"(压缩)。登录报文结构与可运行的客户端示例见 odds 频道页与快速开始。

您可以依赖的保证

  • 只有一种订单簿结构,而不是每个场馆一种。 meta.back / meta.lay 在所有场馆上都是语义一致的 { price, size } 数组,因此您只需写一个解析器。未知的 meta 键属于增量扩展;back / lay 核心不会被改作他用。
  • 场馆原生 ID 就挂在价格本身上。 将订单回送至场馆无需二次查询,也不需要您自建反向映射表。
  • 成交量是一等字段。 limit 在各家博彩商间已归一化,且几乎每家 sharp 博彩商都携带。
  • 失联会被上报,而不是被掩盖。 staleOdds 正是「撤回报价」与「在不知情的情况下对着一个冻结的盘口交易」之间的差别。