预测市场套利机:8岗3刹,扫797个市场,0笔成交
先给结论:这套系统跑了一轮,扫了 797 个市场,开了 0 单。我认为 0 是它正常的读数。这篇讲的就是为什么。
大多数人做预测市场自动化,第一反应是让模型预测结果。我也先写了那台,它偶尔对,然后错,第三周把我打回原形——因为它赌的是“谁赢”,而不是“价格有没有算错”。后来我换了个问题:有没有一种交易,根本不需要我知道结果?有,而且它慢一点也没关系。
01 先关掉那台会赌的
第一版很符合直觉:让它读新闻、看赔率、判断哪个市场被低估。问题在于,你的对手也是这么想的。
预测市场的价格不是 K 线,是一条推文几秒钟就能改完的数字。你跟别人拼“谁先读懂新闻”,拼的是信息差,而信息差在这里的保质期是分钟级。等你的模型把一篇报道读完、想清楚、算完,价格早就贴到新位置了。
更麻烦的是:你不知道自己是对的还是运气好。一周十笔,六笔赚,你没有任何办法判断那六笔来自模型还是来自硬币。方向策略的问题不是不准,是不可验证。
02 换成三条式子
预测市场有一个别的市场没有的性质:同一个事件的不同结果,价格加起来必须等于 1。因为到期时只有一条会中,中一条付 1 块。
下面三条式子都不需要你猜谁会赢:
1. 在一个市场里,YES 和 NO 都买,到期必收 1 块。两边合计小于 1,就是白捡差价。
2. 在一个互斥事件组(比如“谁当选”)里,所有候选的 YES 都买一份,到期必有一条中。合计小于 1,同样白捡。
3. 反过来,所有 YES 的卖价加起来大于 n−1 时,卖光整组等于买齐 NO,收益 n−1。
代码只有三行(示意):
# 核心逻辑:价格合计偏离 1 即套利机会
if sum(prices) < 1: buy_all_shares()
elif sum(prices) > len(prices) - 1: sell_all_shares()
else: pass
这套东西赚的钱,不来自另一个人的亏损,来自两个报价之间的裂缝。它不需要比你聪明,只需要比你算得细。
而且它不是速度游戏。真出现这种裂缝,通常能挂几分钟——慢一分钟,货还在。这一点比“抢区块”友好太多。
03 拆成八个岗位
一个 bot 同时做“发现机会”和“判断风险”,出问题的时候你不知道是哪一环坏了。所以按岗位拆,每个岗位只做一件事:
- HEAD:排流程、催交接、出晚报,绝不判断机会好坏。
- SEARCH:扫全场,产出候选,绝不推荐进场。
- WHALE:看大户集中度定仓位。
- SHILL:看成交与流动性热度,把热度当确认。
- RISK:复核腿数、门槛、敞口,绝不放宽自己的线。
- SNIPER:备单、出票签字,绝不补仓、摊平。
- EXIT:止盈、止损、到期前撤。
- RUG:盯规则变更、流动性塌方,决定平不平。
数据流是一条直线,没有回头路:
HEAD → SEARCH → WHALE → SHILL → RISK → SNIPER → EXIT → RUG
第九个岗位不在图里:你。只做一件事——签字。
04 三道刹车,全是撞出来的
第一次真跑,它立刻报了一个机会:一个互斥组,4 条腿合计 0.804。看起来是白捡 19.6%。我差点就写了“这是印钞机”。
拉出整个事件一看,那组一共 28 条腿,我只看到 4 条。补齐之后再算:合计 1.003,边际 −0.3%,归零。少算的那 24 条腿,就是全部的利润。
于是有了第一道刹车:必须先把整个事件的所有腿补齐,再算合计。
第二道来自另一个观察:真套利停留不了几分钟。如果一个机会算出来有 10 美分以上,先假设是你的数据错了,不要假设是市场错了。
第三道不是代码,是权限设计:机器只备单,把票写到 outbox/,签名永远在你的钱包里。一个拿着私钥自动签名的 bot,出事的时候不是亏钱,是清零。
05 跑起来只要四条命令
零依赖,Python 3.9+,标准库加 sqlite3。默认模拟盘,不碰私钥、不下真单。
# 安装与启动示意
python setup.py # 初始化配置
python run.py --scan # 扫描市场
python run.py --report # 生成晚报
python run.py --paper # 模拟盘运行
某一轮的真实输出(节选):
scanned: 797 markets
candidates: 3
after risk check: 0
all orders: 0 filled
门槛全在一个配置文件里,改数字不用改代码:
# config.ini
min_spread = 0.03 # 最低价差
min_liquidity = 500 # 最低流动性
max_legs = 8 # 最多腿数
exit_before_expiry_days = 3
06 看板
不想盯命令行就开网页看板。只绑 127.0.0.1,不对外网开放,没有登录——它只服务本机。
左边数据源健康,中间待批准和持仓,右边是晚报原文。待批准那一行有“出票”按钮,点了只把 ticket 写进 outbox/,签名仍然在你的钱包里。
07 “0 笔”到底该怎么读
这是全篇最容易被误读的地方。0 笔不是成绩,0 笔是一个待解释的现象。 要判断它是有纪律还是坏了,去看拒单原因分布:
- 大多数死在 thin_liquidity / horizon:门槛和机会池错配。该换扫描面(冷门段),不是降门槛。
- 有零星 group_incomplete:护栏在工作。这比多抓到十个机会更值得高兴。
- 一笔都不立项,但 scan 能看到 0.98 的价差:那说明你的过滤在误杀,去查 RISK 而不是查市场。
反过来,如果它开始什么都过,那不是机会变多了,是你的线松了。
08 它替不了你的事
写清楚比写漂亮重要:
- 只接只读接口。下单要 KYC 和密钥,默认关掉。
- 不自动签名。要全自动,得自己装 py-clob-client 并想清楚私钥放哪——这一步我不建议交出去。
- paper 成交按成本价算,高估收益。这是已知偏差,别拿模拟盈亏当策略有效。
- 非 negRisk 的“事实互斥”组识别不了。数学上互斥、规则上不互斥的组,腿数对不齐,会漏也会错。
- 规则改字才发现,改意思发现不了。条款歧义只能人工读,机器只做提示。
- 到期前 3 天平仓,避开结算风险,代价是放弃最后一段收敛收益。
三个数字
- 797 — 一轮扫过的真实市场
- 0 — 立项数
- 19.6% — 差点上钩的假机会
本教程不代表任何投资建议。