Files

562 lines
15 KiB
Markdown
Raw Permalink Normal View History

2026-07-22 18:53:44 +08:00
# Polymarket 套利机器人 — 中文使用手册
> 适用版本:v0.1.0 · Python 3.12+ · Windows / Linux / macOS
>
> 本文从环境准备到日常运维,按真实使用顺序逐步讲解。
---
## 目录
1. [项目简介](#1-项目简介)
2. [系统要求](#2-系统要求)
3. [快速安装](#3-快速安装)
4. [首次配置](#4-首次配置)
5. [首次运行](#5-首次运行)
6. [日常使用(Paper 模式)](#6-日常使用paper-模式)
7. [Web 仪表板](#7-web-仪表板)
8. [切换到 Live 模式](#8-切换到-live-模式)
9. [监控与运维](#9-监控与运维)
10. [故障排查](#10-故障排查)
11. [安全建议](#11-安全建议)
12. [附录:环境变量参考](#附录环境变量参考)
---
## 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 网络代理](#42-网络代理))。
---
## 3. 快速安装
### 3.1 克隆项目
```bash
git clone https://github.com/matthewnyc2/arbitrage
cd arbitrage
```
### 3.2 创建虚拟环境
**Windows (PowerShell)**
```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
```
**Linux / macOS**
```bash
python3 -m venv .venv
source .venv/bin/activate
```
### 3.3 安装依赖
```bash
pip install -e ".[dev]"
```
> **⚠️ 重要**:默认会装 `websockets>=13.0`pip 可能会拉到 **15.x** 版本,但该版本与项目不兼容(参见 [§10.3 websockets 版本问题](#103-websockets-版本问题))。**显式锁版本**:
> ```bash
> pip install "websockets==14.2"
> ```
### 3.4 验证安装
```bash
arb --help
```
应显示:`init / discover / scan / web / resolve` 五个子命令。
---
## 4. 首次配置
### 4.1 复制环境变量模板
```bash
cp .env.example .env
```
`.env` 关键字段(Paper 模式默认值即可运行):
```ini
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 临时设置**(仅当前会话):
```powershell
$env:HTTPS_PROXY="http://127.0.0.1:7890" # 改成你的代理地址
$env:HTTP_PROXY="http://127.0.0.1:7890"
```
**永久设置**(写入 `.env`):
```ini
ARB_PROXY=http://127.0.0.1:7890
```
> **常见代理端口**Clash 默认 7890V2Ray 默认 10809SSR 默认 1080。
>
> 配置完成后 httpxREST)和 websocketsWS)都会通过代理连接。
### 4.3 验证代理可用
```bash
arb discover
```
预期输出:
```
seen=2000 negRisk=928 upserted=894 malformed=34
```
如果仍超时,回到 [§10.1 网络连通性](#101-网络连通性)。
---
## 5. 首次运行
### 5.1 初始化数据库
```bash
arb init
```
创建 SQLite 表结构(含 events / outcomes / opportunities / baskets / fills / live_orders / resolutions / denylist / daily_pnl)。
### 5.2 发现事件
```bash
arb discover
```
从 Polymarket Gamma API 拉取所有活跃 negRisk 事件。需要约 1020 秒。
**持续发现**(生产部署推荐,每 180 秒刷新):
```bash
arb discover --loop --interval 180
```
### 5.3 启动扫描
```bash
arb scan
```
开始监听 CLOB WebSocket,实时检测套利机会,写入 paper baskets。
预期日志:
```
scan loop started (885 events hydrated)
ws subscribed to N tokens
```
### 5.4 启动 Web 仪表板(另一终端)
```bash
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 后台运行**
```bash
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):
```powershell
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** 删除文件即可恢复。
也可在终端手动:
```bash
# Windows
New-Item -Path .\KILL -ItemType File
# Linux/macOS
touch ./KILL
```
---
## 8. 切换到 Live 模式
### 8.1 准备工作
1. **专用钱包**:在 Polygon 上创建一个新的 EOA,**不要复用个人钱包**
2. **充值**:向钱包转入 USDC.e(建议 ≥ $200,含 gas
3. **批准授权**:按 `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_KEY`
- `CLOB_SECRET`
- `CLOB_PASSPHRASE`
**这三个凭证无法恢复,丢失需重新派生。**
### 8.3 修改 `.env`
```ini
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
# 在 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`**
```ini
ARB_MAX_BASKET_USD=5
ARB_MAX_OPEN_BASKETS=1
```
**第 3 步**:观察 1–2 天无异常后,再逐步放大到默认值。
---
## 9. 监控与运维
### 9.1 日志
日志写在 `logs/arbitrage.jsonl`(结构化 JSON,每天 0 点轮转,保留 7 天)。
**实时查看**
```bash
# Linux/macOS
tail -f logs/arbitrage.jsonl | jq .
# Windows PowerShell
Get-Content logs\arbitrage.jsonl -Wait
```
**按事件过滤**
```bash
grep "new_market" logs/arbitrage.jsonl | tail -20
```
### 9.2 数据库
位置:`./arbitrage.db`SQLite + WAL 模式)
**直接查询**
```bash
sqlite3 arbitrage.db "SELECT status, COUNT(*) FROM baskets GROUP BY status;"
sqlite3 arbitrage.db "SELECT * FROM opportunities ORDER BY detected_at DESC LIMIT 10;"
```
**备份**
```bash
cp arbitrage.db arbitrage.db.bak-$(date +%Y%m%d)
```
**重置**(清空所有 paper 数据):
```bash
rm arbitrage.db
arb init
arb discover
```
### 9.3 进程监控
**检查运行中的 arb 进程**
```powershell
# Windows
Get-Process | Where-Object { $_.Name -eq "python" -and $_.Path -like "*Python312*" }
# Linux
ps aux | grep arb
```
**查看资源占用**
```bash
# 内存占用(正常 100-300 MB
Get-Process python | Select-Object Id, @{n='Mem(MB)';e={[int]$_.WorkingSet64/1MB}}
```
### 9.4 升级
```bash
cd arbitrage
git pull
pip install -e ".[dev]"
# 重启 arb scan / arb web
```
---
## 10. 故障排查
### 10.1 网络连通性
**症状**`httpx.ConnectTimeout``arb discover` 卡住。
**排查**
```powershell
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` 与项目不兼容。
**修复**
```bash
pip install "websockets==14.2"
```
### 10.4 日志 PermissionError
**症状**`PermissionError: [WinError 32] 另一个程序正在使用此文件`
**根因**loguru 在 Windows 上的 50MB 轮转触发 `close() → os.rename()` 竞态。
**修复**(已默认配置):`rotation="1 day"` + `retention="7 days"`,避免高并发期轮转。
如果仍出现:
```powershell
# 清理残留进程
Get-Process python | Where-Object { $_.Path -like "*Python312*" } | Stop-Process -Force
```
### 10.5 残留进程占用文件
**症状**:杀掉 `arb scan` 后,新进程仍报 PermissionError。
**排查**
```powershell
Get-Process | Where-Object { $_.Name -eq "python" }
```
**清理**
```powershell
Get-Process python -ErrorAction SilentlyContinue | Stop-Process -Force
```
### 10.6 仪表板 404 / 端口冲突
**症状**:浏览器访问 `http://127.0.0.1:8000` 返回 404 或连接拒绝。
**排查**
```powershell
Test-NetConnection -ComputerName 127.0.0.1 -Port 8000
Get-NetTCPConnection -LocalPort 8000 -State Listen
```
**修复**:更换端口启动:
```bash
arb web --port 8888
```
### 10.7 没有任何套利机会
**症状**:仪表板显示 `recent opportunities` 为空或 net edge bps 全部 < 50。
**原因**
1. 当前 Polymarket 没有负空间(正常 — 套利机会稀少)
2. WS 数据未刷新(检查 `ws subscribed` 日志)
3. `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 隧道:
```bash
ssh -L 8000:127.0.0.1:8000 user@server
```
### 11.3 依赖管理
- 锁定关键依赖版本,避免供应链风险:
```bash
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`