Skip to content
survivorff's blog
Go back

同一个事件,在两个平台是两个世界——预测市场聚合器的第一个难题

11 min read

做预测市场聚合器之前,我以为难点会在交易链路上——签名、下单、撮合、结算,这些是我熟的东西。

真正把我卡住的,是一个听起来很蠢的问题:

怎么确认 Polymarket 上的这个市场,和 predict.fun 上的那个市场,说的是同一件事?

这个问题没解决,后面所有功能都是空中楼阁。因为聚合器的全部价值——比价、找最优执行、发现跨平台价差——都建立在”这两个市场可以拿来比”这个前提上。前提错了,你不是在帮用户省钱,是在帮用户亏钱。

这篇讲清楚这个问题为什么难,以及我最后是怎么拆的。

背景:预测市场本身是什么、为什么 2025 年爆发,我写在《预测市场的 2026:从”赌博网站”到 $1275 亿的全球概率基础设施》。这篇假设你已经知道”份额价格 = 隐含概率”这件事。


为什么没有一个共同 ID

如果两个平台共享某种全局事件 ID,这篇文章就不用写了。现实是没有。

Polymarket 和 predict.fun 在架构上其实高度同构——都用 Gnosis 的条件代币框架(CTF)、都是 ERC-1155、都是链下 CLOB 撮合 + 链上原子结算。你可能会以为,同构就意味着标识符可以对齐。

恰恰相反。 看一眼 CTF 的 ID 派生链路:

questionId  = keccak256(问题元数据)
conditionId = keccak256(oracle 地址, questionId, outcomeSlotCount)
tokenId     = keccak256(抵押品合约地址, collectionId)

三层里每一层都带着平台自己的东西:

所以结论很硬:

哪怕两个平台对同一个现实事件,写了一模一样的问题文案、设了一模一样的截止时间,它们的 questionId / conditionId / tokenId 也必然完全不同。

链上标识符在这里帮不了你。不要试图用 tokenId 做跨平台的 key,这是我最早走的弯路。

那用什么?只剩下问题本身的语义。而语义是脏的。


脏在哪:四种会咬人的差异

我把踩过的坑归成四类,从”容易发现”到”最阴”排序。

1. 文案差异(最容易,也最容易让人放松警惕)

同一件事,两个平台的写法可能是:

大小写、缩写(BTC / Bitcoin)、数字格式($120,000 / $120K)、日期格式、有没有问号。这一层用规范化 + 模糊匹配基本能搞定,是最不值得担心的一层。

但它危险的地方在于:它会让你产生”这个问题就是个字符串匹配问题”的错觉,然后你就会栽在下面三层。

2. 阈值与比较符差异(开始要命)

看这两个:

文案上差一个字符,实际是两个不同的市场。如果 BTC 最终精确收在 $120,000.00,一个赔付 YES,一个赔付 NO。

同类的还有:

差异点例子
开闭区间 vs >between 3-4% 含不含端点
单位口径$120K vs 120,000 USD vs 以某交易所报价计
精度保留几位小数、四舍五入还是截断

这一层已经不能靠文本相似度判断了,必须把阈值和比较符抽成结构化字段单独比。

3. 时间口径差异(很阴)

这一层我吃过亏。两个市场都写着”9 月 30 日”,但:

结果就是:两个”同一个事件”的市场,可能在不同的时刻停止交易、在不同的时刻结算。 对聚合器意味着什么?意味着你以为可以两边同时平掉的仓位,实际上有一段时间是单边裸敞口

4. 结算规则与数据源差异(最阴,也是真正的身份)

这是我最后想明白的一层,也是整篇文章我最想说的一句话:

一个预测市场的真正身份,不是它的问题文案,而是它的结算规则。

同样问”BTC 是否突破 $120K”,两个平台可能:

我在整理两个平台的资料时注意到一个结构性差异:Polymarket 的长期事件走 UMA 乐观预言机,有提议 + 争议窗口;而 predict.fun 除了乐观预言机路径,还对短期价格市场用 Chainlink 做自动结算(据其 2026 年 4 月的公开公告,从 BTC 的 15 分钟市场开始)。

这意味着同一个”BTC 涨跌”的问题,在两个平台可能走完全不同的裁定路径——一个可能因为争议拖上数天,一个到点即结。

如果你把这两个市场当成同一个来做对冲,你对冲的不是同一个风险。


所以我不敢只用 LLM

一开始我很自然地想:这不就是语义匹配吗,扔给模型不就完了。

试完的结论是:LLM 适合做召回,绝对不能单独做终判。

原因很具体:

  1. 它对文案敏感,对规则不敏感。 两个市场文案几乎一样但结算数据源不同,模型大概率给你一个很高的相似度分
  2. > 这种细节,恰恰是模型最容易抹平的——它倾向于认为这是”表达差异”
  3. 它会幻觉出自信。 你要的是”我不确定”,它给你的是一个 0.93
  4. 错误代价不对称。 漏掉一个可匹配的市场,损失是少一个机会;错配一对市场,损失是用户真金白银的裸敞口

第 4 点是关键。在这个场景里,假阳性(错配)的代价远高于假阴性(漏配)。 任何一个倾向于”给出答案”的方案,方向上就是错的。


我最后的做法:三层漏斗 + 置信度

我把它做成一条从宽到严的漏斗,每一层负责不同的事。

候选池(两个平台的全部活跃市场)


① 粗召回:规范化文本 + 关键实体          ← 要「宽」,宁可多召
      │  标的(BTC/SOL/选举/球队)、方向、数字、日期

② 结构化硬校验:把市场解析成一个规范对象   ← 要「严」,一票否决
      │  { 标的, 比较符, 阈值, 单位, 截止时间(UTC), 判定时点, 数据源, 结果数 }

③ 结算规则比对 + 置信度分级              ← 要「诚实」,允许说不确定


   高置信 → 自动配对
   中置信 → 只展示行情,不允许跨平台对冲操作
   低置信 → 进人工复核队列,默认不配对

几个我认为关键的设计决定:

第一,把市场解析成一个”规范对象”,而不是比字符串。

核心字段大概是这样:

{
  "subject": "BTC",              // 标的
  "metric": "spot_price",        // 判定的量
  "comparator": "gte",           // 比较符:gt / gte / lt / lte / between
  "threshold": 120000,
  "unit": "USD",
  "closeAt": "2026-09-30T23:59:59Z",   // 停止交易,统一转 UTC
  "resolveAt": "2026-09-30T23:59:59Z", // 判定时点,可能 ≠ closeAt
  "resolutionSource": "...",     // 数据源
  "outcomeCount": 2              // 2 = 二元;>2 走多结果(negRisk)路径
}

能不能解析出这个对象,本身就是一道闸。 解析不出来(文案太自由、规则写在一大段散文里)就直接进人工队列,不猜。

第二,硬字段一票否决。

comparatorthresholdunitoutcomeCount 只要有一个不一致,无论文本多像、模型多自信,直接判不匹配。这几个字段没有”差不多”这回事。

第三,closeAtresolveAt 分开存,并且允许有容差但要显式声明。

两个平台的 closeAt 差 8 小时,不代表不是同一件事,但必须把这个差值带到下游——下游做跨平台对冲时要知道”这里有 8 小时的单边敞口窗口”。把差值吞掉是最危险的做法。

第四,置信度必须落到”能不能下单”这个动作上,而不只是一个展示用的分数。

这是我觉得最重要的一条。置信度如果只是 UI 上一个小标签,它就没有意义。它必须真的卡住操作权限

置信度允许做什么
聚合行情 + 跨平台比价 + 允许对冲/套利操作
聚合行情 + 比价,禁止一键跨平台操作
两个市场分开展示,不声称它们相关

宁可少给一个功能,不要给一个错的对冲。

第五,多结果市场(negRisk)单独处理。

两个平台都有多结果市场的机制(一个事件下多个互斥选项,比如多候选人选举)。这时匹配不是”一对一”,而是要匹配整个结果集合:选项数量、每个选项的语义、以及”是否互斥且完备”都要对上。

一个很实际的坑:A 平台把选举拆成”候选人 A / 候选人 B / 其他”,B 平台只有”候选人 A / 候选人 B”。这两个事件不能整体对齐——虽然”候选人 A 获胜”这个子市场看起来能对上,但两边的概率归一化基数不同。


这件事的工程量,比它听起来大得多

写到这我想说个可能反直觉的判断:

事件对齐不是聚合器的”数据预处理步骤”,它就是聚合器的核心资产。

理由:

这和我之前拆 Meme 交易平台时的结论是同一个形状:头部平台真正的护城河不是前端,是 Indexer。预测市场聚合器的护城河,也不在下单按钮上,在事件对齐的正确率和它的诚实度上。


几条我会给自己的提醒

如果你也在做类似的东西:

  1. 别用链上 ID 做跨平台 key。 tokenId 里混着抵押品地址,conditionId 里混着 oracle 地址,同一个事件在两个平台必然不同
  2. 把结算规则当成市场的真正身份,文案只是它的显示名
  3. > 要单独存字段,这不是文案细节,这是两个不同的赔付函数
  4. 时间统一转 UTC,closeAtresolveAt 分开,差值要传给下游而不是吞掉
  5. LLM 只做召回,硬字段做终判,并且允许系统输出”我不确定”
  6. 置信度要卡住操作权限,不能只是个展示标签
  7. 假阳性远比假阴性贵。 在这个场景里,保守是正确的工程价值观

小结

聚合器看起来是个”接两个 API 然后并排展示”的活。真做下去会发现,最难的部分不在任何一个平台的 API 文档里——它在两个平台对同一个现实事件的不同描述之间的缝隙里。

而这个缝隙,是没有 API 能帮你填的。

下一篇写另一面:既然两个平台架构如此同构(都是 CTF + CLOB),为什么”一套代码跑两个平台”依然会到处漏——以及那些藏在常量里的坑。


延伸阅读


预测市场聚合器实战系列,持续更新。订阅 RSS关注 X


Share this post on:

Previous Post
两条链,一套代码:Polymarket 与 predict.fun 的同构与陷阱
Next Post
Solana 没有 mempool,为什么还是被 MEV 收割了几亿美元

继续阅读

如果觉得有用

订阅更新,每次发新文章第一时间收到。不发广告、不搞推销。