15 KiB
Polymarket 套利机器人 — 中文使用手册
适用版本:v0.1.0 · Python 3.12+ · Windows / Linux / macOS
本文从环境准备到日常运维,按真实使用顺序逐步讲解。
目录
1. 项目简介
Polymarket NegRisk 多结果套利机器人。Polymarket 的某些分类事件(例如"2028 大选谁赢")每个结果独立挂牌交易。当所有结果的卖一价加总 < $1 时,买入一整套结果,结算时一定收回 $1 → 无风险套利。
本机器人扫描所有活跃 negRisk 事件,实时计算套利空间,提供两种模式:
| 模式 | 资金风险 | 用途 |
|---|---|---|
| Paper | $0 | 模拟成交,验证策略,观察 PnL |
| Live | 实盘资金 | 真实下单,需提供钱包私钥 |
2. 系统要求
| 项目 | 要求 |
|---|---|
| Python | 3.12 或更高 |
| 操作系统 | Windows 10+ / Linux / macOS |
| 内存 | ≥ 512 MB |
| 磁盘 | ≥ 1 GB(含 SQLite 与日志) |
| 网络 | 必须能访问 polymarket.com(国内需配置代理) |
| 钱包(仅 Live) | Polygon 上的专用 EOA,持有 USDC.e |
国内用户注意:Polymarket 服务器在国内无法直连,必须配置 HTTP 代理(详见 §4.2 网络代理)。
3. 快速安装
3.1 克隆项目
git clone https://github.com/matthewnyc2/arbitrage
cd arbitrage
3.2 创建虚拟环境
Windows (PowerShell):
python -m venv .venv
.\.venv\Scripts\Activate.ps1
Linux / macOS:
python3 -m venv .venv
source .venv/bin/activate
3.3 安装依赖
pip install -e ".[dev]"
⚠️ 重要:默认会装
websockets>=13.0,pip 可能会拉到 15.x 版本,但该版本与项目不兼容(参见 §10.3 websockets 版本问题)。显式锁版本:pip install "websockets==14.2"
3.4 验证安装
arb --help
应显示:init / discover / scan / web / resolve 五个子命令。
4. 首次配置
4.1 复制环境变量模板
cp .env.example .env
.env 关键字段(Paper 模式默认值即可运行):
ARB_MODE=paper # paper = 模拟盘;live = 实盘
ARB_CLOB_HOST=https://clob.polymarket.com
ARB_GAMMA_HOST=https://gamma-api.polymarket.com
ARB_PROXY= # 国内用户填代理,见下文
4.2 网络代理
国内 / 防火墙环境下必须配置,否则 arb discover 会报 httpx.ConnectTimeout。
PowerShell 临时设置(仅当前会话):
$env:HTTPS_PROXY="http://127.0.0.1:7890" # 改成你的代理地址
$env:HTTP_PROXY="http://127.0.0.1:7890"
永久设置(写入 .env):
ARB_PROXY=http://127.0.0.1:7890
常见代理端口:Clash 默认 7890,V2Ray 默认 10809,SSR 默认 1080。
配置完成后 httpx(REST)和 websockets(WS)都会通过代理连接。
4.3 验证代理可用
arb discover
预期输出:
seen=2000 negRisk=928 upserted=894 malformed=34
如果仍超时,回到 §10.1 网络连通性。
5. 首次运行
5.1 初始化数据库
arb init
创建 SQLite 表结构(含 events / outcomes / opportunities / baskets / fills / live_orders / resolutions / denylist / daily_pnl)。
5.2 发现事件
arb discover
从 Polymarket Gamma API 拉取所有活跃 negRisk 事件。需要约 10–20 秒。
持续发现(生产部署推荐,每 180 秒刷新):
arb discover --loop --interval 180
5.3 启动扫描
arb scan
开始监听 CLOB WebSocket,实时检测套利机会,写入 paper baskets。
预期日志:
scan loop started (885 events hydrated)
ws subscribed to N tokens
5.4 启动 Web 仪表板(另一终端)
arb web
打开浏览器访问 http://127.0.0.1:8000。
6. 日常使用(Paper 模式)
6.1 标准三进程部署
| 终端 | 命令 | 作用 |
|---|---|---|
| 终端 1 | arb discover --loop --interval 180 |
每 3 分钟刷新事件列表 |
| 终端 2 | arb scan |
实时扫描 + 模拟成交 |
| 终端 3 | arb web |
Web 仪表板 |
Linux/macOS 后台运行:
nohup arb discover --loop --interval 180 > logs/discover.log 2>&1 &
nohup arb scan > logs/scan.log 2>&1 &
6.2 CLI 命令速查
| 命令 | 功能 |
|---|---|
arb init |
创建 SQLite schema |
arb discover |
单次拉取事件 |
arb discover --loop |
持续拉取 |
arb scan |
启动扫描 |
arb web |
启动仪表板(默认 127.0.0.1:8000) |
arb resolve <event_id> --winner <token_id> |
手动标记事件结算结果 |
arb resolve <event_id> |
标记为 invalid |
6.3 停止服务
正常停止:在运行终端按 Ctrl+C。
强制清理残留进程(Windows):
Get-Process python | Where-Object { $_.StartTime -gt (Get-Date).AddHours(-1) } | Stop-Process -Force
7. Web 仪表板
仪表板每 2–3 秒自动刷新(HTMX 轮询),无需手动操作。
7.1 主要面板
| 面板 | 显示内容 |
|---|---|
| Paper PnL | 已实现盈亏、各状态组合数、Kill Switch 按钮 |
| Baskets | 最近 25 个组合:ID、事件、份数、成本、状态、PnL |
| Recent Opportunities | 最近 25 个检测到的机会:Σ asks、净边际、最大组合、预期利润 |
7.2 关键指标解读
Σ asks < $1 → 存在套利空间。典型值:
0.98→ 净边际 ~2%(扣费前)0.95→ 净边际 ~5%(扣费前)< 0.90→ 非常罕见的深度套利
net edge bps:扣除手续费 + 分摊 gas 后的净边际。低于 50 bps 会被 ARB_MIN_NET_EDGE_BPS 过滤。
status:
| 状态 | 含义 |
|---|---|
pending_resolution |
等待事件结算 |
redeemed |
已结算,PnL 入账 |
failed |
部分腿未成交(paper 模拟时深度消失) |
invalid |
事件被标记为无效 |
7.3 Kill Switch
仪表板右下角红色 kill 按钮,点击后立即创建 ./KILL 文件,执行器会拒绝所有新单。再次点击 unkill 删除文件即可恢复。
也可在终端手动:
# Windows
New-Item -Path .\KILL -ItemType File
# Linux/macOS
touch ./KILL
8. 切换到 Live 模式
8.1 准备工作
- 专用钱包:在 Polygon 上创建一个新的 EOA,不要复用个人钱包
- 充值:向钱包转入 USDC.e(建议 ≥ $200,含 gas)
- 批准授权:按
docs/api/order-signing.md§8 的脚本,对 CTF Exchange + NegRisk Exchange + NegRisk Adapter 三个合约授权
8.2 派生 L2 API 凭证
按 docs/api/order-signing.md §2 的 bootstrap_clob_creds.py 脚本执行一次,生成:
CLOB_API_KEYCLOB_SECRETCLOB_PASSPHRASE
这三个凭证无法恢复,丢失需重新派生。
8.3 修改 .env
ARB_MODE=live
ARB_PRIVATE_KEY=0x... # 钱包私钥(0x 前缀)
ARB_FUNDER_ADDRESS=0x... # 资金地址(EOA 模式 = 私钥对应地址)
ARB_SIGNATURE_TYPE=0 # 0=EOA, 1=Polymarket proxy, 2=Gnosis Safe
ARB_API_KEY=...
ARB_API_SECRET=...
ARB_API_PASSPHRASE=...
# 风险上限(强烈建议保持默认值)
ARB_MAX_BASKET_USD=50
ARB_MAX_OPEN_BASKETS=3
ARB_DAILY_LOSS_STOP_USD=100
8.4 首次实盘(强烈建议 dry_run 验证)
第 1 步:先用 dry_run 验证签名链路:
# 在 Python REPL 中手动测试
from arbitrage.engine.live_executor import LiveExecutor, RiskLimits
from arbitrage.book.l2 import BookRegistry
books = BookRegistry()
ex = LiveExecutor(books=books, dry_run=True) # 只签名不提交
第 2 步:把 cli.py:87 的 dry_run=False 保持不变(默认就是 False),但先把 ARB_MAX_BASKET_USD 设为 5:
ARB_MAX_BASKET_USD=5
ARB_MAX_OPEN_BASKETS=1
第 3 步:观察 1–2 天无异常后,再逐步放大到默认值。
9. 监控与运维
9.1 日志
日志写在 logs/arbitrage.jsonl(结构化 JSON,每天 0 点轮转,保留 7 天)。
实时查看:
# Linux/macOS
tail -f logs/arbitrage.jsonl | jq .
# Windows PowerShell
Get-Content logs\arbitrage.jsonl -Wait
按事件过滤:
grep "new_market" logs/arbitrage.jsonl | tail -20
9.2 数据库
位置:./arbitrage.db(SQLite + WAL 模式)
直接查询:
sqlite3 arbitrage.db "SELECT status, COUNT(*) FROM baskets GROUP BY status;"
sqlite3 arbitrage.db "SELECT * FROM opportunities ORDER BY detected_at DESC LIMIT 10;"
备份:
cp arbitrage.db arbitrage.db.bak-$(date +%Y%m%d)
重置(清空所有 paper 数据):
rm arbitrage.db
arb init
arb discover
9.3 进程监控
检查运行中的 arb 进程:
# Windows
Get-Process | Where-Object { $_.Name -eq "python" -and $_.Path -like "*Python312*" }
# Linux
ps aux | grep arb
查看资源占用:
# 内存占用(正常 100-300 MB)
Get-Process python | Select-Object Id, @{n='Mem(MB)';e={[int]$_.WorkingSet64/1MB}}
9.4 升级
cd arbitrage
git pull
pip install -e ".[dev]"
# 重启 arb scan / arb web
10. 故障排查
10.1 网络连通性
症状:httpx.ConnectTimeout,arb discover 卡住。
排查:
Test-NetConnection -ComputerName gamma-api.polymarket.com -Port 443
如果失败,确认 ARB_PROXY 设置正确,或切换代理节点。
10.2 WebSocket 反复重连
症状:ws disconnect (TimeoutError); reconnecting in 1.0s 大量重复。
根因:WebSocket 没有走代理。
修复:确认 .env 中设置了 ARB_PROXY=http://...,代码会自动通过 HTTP CONNECT 隧道建立 WS 连接。
10.3 websockets 版本问题
症状:AttributeError: 'ClientConnection' object has no attribute 'recv_messages',或 got an unexpected keyword argument 'proxy'。
根因:websockets 15.0 与项目不兼容。
修复:
pip install "websockets==14.2"
10.4 日志 PermissionError
症状:PermissionError: [WinError 32] 另一个程序正在使用此文件
根因:loguru 在 Windows 上的 50MB 轮转触发 close() → os.rename() 竞态。
修复(已默认配置):rotation="1 day" + retention="7 days",避免高并发期轮转。
如果仍出现:
# 清理残留进程
Get-Process python | Where-Object { $_.Path -like "*Python312*" } | Stop-Process -Force
10.5 残留进程占用文件
症状:杀掉 arb scan 后,新进程仍报 PermissionError。
排查:
Get-Process | Where-Object { $_.Name -eq "python" }
清理:
Get-Process python -ErrorAction SilentlyContinue | Stop-Process -Force
10.6 仪表板 404 / 端口冲突
症状:浏览器访问 http://127.0.0.1:8000 返回 404 或连接拒绝。
排查:
Test-NetConnection -ComputerName 127.0.0.1 -Port 8000
Get-NetTCPConnection -LocalPort 8000 -State Listen
修复:更换端口启动:
arb web --port 8888
10.7 没有任何套利机会
症状:仪表板显示 recent opportunities 为空或 net edge bps 全部 < 50。
原因:
- 当前 Polymarket 没有负空间(正常 — 套利机会稀少)
- WS 数据未刷新(检查
ws subscribed日志) ARB_MIN_NET_EDGE_BPS设得太高(默认值 50 合理)
11. 安全建议
11.1 私钥保护
- 永远不要把
.env提交到 Git(已在.gitignore中) - 实盘私钥使用专用钱包,与其他资产隔离
- 服务器上
.env文件权限设为chmod 600(Linux) - 考虑使用硬件钱包或多签
11.2 Web 仪表板
- 默认绑定
127.0.0.1,不要改为0.0.0.0后暴露到公网 kill/unkill端点无身份认证,暴露即等于把钱包控制权交给攻击者- 如果需要远程访问,使用 SSH 隧道:
ssh -L 8000:127.0.0.1:8000 user@server
11.3 依赖管理
- 锁定关键依赖版本,避免供应链风险:
pip install "websockets==14.2" "py-clob-client==0.34.6" - 定期升级时检查 changelog
11.4 Live 模式额外建议
- 先用 ≥ $10 的小资金跑 1 周
- 每日检查 realized PnL,确认与 paper 结果趋势一致
- 设置价格告警(Discord webhook / Telegram bot 等)
- 监控
daily_pnl表,日亏损接近ARB_DAILY_LOSS_STOP_USD时手动 kill
附录:环境变量参考
完整 .env 配置项:
| 变量 | 默认值 | 说明 |
|---|---|---|
ARB_MODE |
paper |
paper / live |
ARB_CLOB_HOST |
https://clob.polymarket.com |
CLOB API |
ARB_GAMMA_HOST |
https://gamma-api.polymarket.com |
Gamma REST |
ARB_DATA_HOST |
https://data-api.polymarket.com |
Data API |
ARB_WS_URL |
wss://ws-subscriptions-clob.polymarket.com/ws/market |
WS 端点 |
ARB_POLYGON_RPC |
https://polygon-rpc.com |
Polygon RPC |
ARB_PROXY |
空 | HTTP 代理(REST + WS 共享) |
ARB_PRIVATE_KEY |
空 | 钱包私钥(Live 必填) |
ARB_FUNDER_ADDRESS |
空 | 资金地址(Live 必填) |
ARB_SIGNATURE_TYPE |
0 |
0=EOA / 1=proxy / 2=Safe |
ARB_API_KEY |
空 | CLOB L2 API key |
ARB_API_SECRET |
空 | CLOB L2 API secret |
ARB_API_PASSPHRASE |
空 | CLOB L2 API passphrase |
ARB_MIN_NET_EDGE_BPS |
50 |
最低净边际(基点) |
ARB_MAX_BASKET_USD |
50 |
单笔组合上限 USD |
ARB_MAX_OPEN_BASKETS |
3 |
全局未结算组合上限 |
ARB_DAILY_LOSS_STOP_USD |
100 |
日亏损止损 USD |
ARB_KILL_SWITCH_FILE |
./KILL |
Kill switch 文件路径 |
ARB_PAPER_LATENCY_MS |
250 |
Paper 模拟延迟(毫秒) |
ARB_DB_PATH |
./arbitrage.db |
SQLite 路径 |
ARB_WEB_HOST |
127.0.0.1 |
Web 监听地址 |
ARB_WEB_PORT |
8000 |
Web 端口 |
ARB_LOG_LEVEL |
INFO |
控制台日志级别 |
联系与反馈
- 项目主页:https://matthewnyc2.github.io/arbitrage/
- GitHub Issues:https://github.com/matthewnyc2/arbitrage/issues
- API 参考:
docs/api/order-signing.md、docs/api/negrisk.md - 设计文档:
DESIGN.md