Polymarket零风险模拟交易引擎:AI智能体与量化策略的实战沙盒
在量化交易与AI智能体开发领域,构建一个既能反映真实市场微观结构、又能保障资金安全的测试环境至关重要。传统的回测工具往往基于简化模型或历史数据回放,难以模拟交易执行层面的真实影响,如滑点、订单簿冲击和动态手续费。Polymarket-paper-trader项目通过深度绑定真实Polymarket预测市场的实时订单簿,提供了一个高保真的零风险模拟交易引擎。其核心价值在于,它不仅仅模拟价格序列,更精
1. 项目概述:让AI智能体成为Polymarket预测市场的零风险交易员
如果你正在研究AI智能体(AI Agent)的自主决策能力,或者想构建一个能理解并参与复杂金融市场的算法交易策略,那么你很可能需要一个既安全又真实的测试环境。传统的回测工具要么数据是模拟的,要么交易逻辑过于简化,导致在模拟环境中表现优异的策略,一旦投入真金白银就“见光死”。这正是 polymarket-paper-trader 这个开源项目要解决的核心痛点:它不是一个玩具,而是一个与真实Polymarket预测市场订单簿深度绑定的、零风险的模拟交易引擎。
简单来说,这个工具给你的AI智能体或交易脚本提供了一个“沙盒”。你初始化一个账户,比如给它1万美元的模拟资金,它就能通过命令行或标准的MCP协议,去交易Polymarket上真实的、正在流动的市场。你的每一次“买入”或“卖出”指令,都会按照Polymarket实时的、多层次的订单簿进行模拟撮合,计算精确的手续费和滑点。最终,你的模拟盈亏(P&L)会无限接近真实交易的盈亏(扣除运气和极端市场冲击)。这就像给你的AI交易员提供了一个全真的飞行模拟器,而不是一个简单的电子游戏。
这个项目特别适合几类人: AI智能体开发者 ,想测试智能体在动态市场环境下的决策与执行能力; 量化交易策略研究者 ,尤其是对新兴的预测市场(如政治、加密货币、体育赛事结果)感兴趣,需要快速验证想法;以及 对算法交易和DeFi感兴趣的程序员 ,想通过一个结构清晰、接口友好的项目来学习实战。它用Python写成,基于SQLite存储交易数据,并通过MCP协议为Claude等AI助手提供了26个可直接调用的工具,让“AI驱动交易”从概念变成了几行命令就能跑起来的实验。
2. 核心设计思路:为何要模拟“真实订单簿”而非“随机价格”?
市面上很多模拟交易工具,其价格生成机制要么是随机漫步,要么是基于历史数据的简单回放。 polymarket-paper-trader 的设计哲学截然不同: 它追求的是交易执行层面的真实性,而不仅仅是价格序列的真实性 。这背后有一个深刻的洞见:在流动性并非无限的市场(尤其是像Polymarket这样的新兴预测市场)中,你的交易行为本身就会影响成交结果,而不仅仅是你的买卖方向判断对了就能赚钱。
2.1 订单簿驱动的执行引擎
项目的核心是一个 订单簿执行模拟器 。当你下达一个市价单(Market Order)买入“YES”份额时,引擎不会简单地用一个中间价(Mid Price)成交。它会实时拉取Polymarket上该市场“YES”结果的真实卖单(Ask)订单簿。然后,从最优(最低)的卖价开始,逐层“吃掉”订单,直到满足你的购买金额。这个过程完全模拟了真实交易所的撮合逻辑。
举个例子,假设“比特币年底能否突破10万美元”这个市场的“YES”订单簿如下:
- 卖单1:价格 0.65,数量 200份
- 卖单2:价格 0.66,数量 150份
- 卖单3:价格 0.67,数量 300份
如果你下了一个市价单,买入价值100美元的“YES”份额。引擎会先计算:
- 以0.65的价格,购买200份,需要
200 * 0.65 = 130美元。但你的订单只有100美元,所以只能部分成交。实际成交份额为100 / 0.65 ≈ 153.85份。第一档订单被部分消耗。 - 由于第一档订单的流动性已经满足了你的全部金额,交易就此停止。你的 成交均价是0.65 ,而不是订单簿上显示的0.66或0.67。
这个细节至关重要。如果你的策略是频繁交易,或者单笔金额较大,这种“吃单”行为会导致你的实际成交价总是比你看见的“最佳卖价”更差(对于买单)或更好(对于卖单),这个差值就是 滑点 。项目会精确记录每一笔交易的滑点(以基点bps为单位),这是评估策略交易成本的关键指标。
注意 :这里模拟的是“市价单”的吃单行为。对于“限价单”,逻辑则相反:你的订单会挂在订单簿的相应价位上,等待市场价格波动来“触发”它。项目完整实现了GTC(一直有效直至取消)和GTD(指定日期前有效)两种限价单状态机。
2.2 精确的费用模型与多结果市场支持
另一个体现真实性的设计是手续费计算。Polymarket的手续费模型不是简单的百分比,而是 bps/10000 × min(price, 1-price) × shares 。 polymarket-paper-trader 严格复现了这个公式。这意味着,在价格接近0.5(最不确定)时,手续费率最高;在价格接近0或1(结果几乎确定)时,手续费率最低。你的策略盈亏计算已经扣除了这部分费用,使得模拟结果更具参考价值。
此外,项目原生支持 多结果市场 。Polymarket上不仅有简单的YES/NO二元市场,还有“哪个候选人会赢得选举?”(A, B, C, D)或“比特币价格落在哪个区间?”这类多选项市场。引擎能够处理这种复杂结构,为策略开发打开了更广阔的空间。
2.3 架构分离:数据、逻辑与接口
从代码架构看,项目清晰地分为了三层:
- 数据层 :基于SQLite,持久化存储账户余额、持仓、订单、交易记录。这种轻量级设计使得多账户管理和本地回测非常高效。
- 引擎层 :核心的交易逻辑、订单簿模拟、风险计算(如检查余额是否充足)都在这里。它向上提供统一的Python API。
- 接口层 :
- CLI :为人类用户提供直观的命令行操作。
- MCP Server :为AI智能体提供标准化工具调用接口。这是项目作为“AI智能体训练场”的关键,使得Claude、GPT等模型能像调用函数一样直接进行交易操作。
这种分离让策略开发者可以专注于引擎层的调用,而无需关心数据如何存储或命令如何解析。
3. 从零开始:环境搭建与核心操作详解
3.1 安装与初始化
安装过程非常简单,推荐使用 pip ,这是最通用的Python包管理方式。
# 1. 确保你使用的是 Python 3.10 或更高版本
python --version
# 2. 安装 polymarket-paper-trader
pip install polymarket-paper-trader
# 3. 初始化你的第一个模拟交易账户,命名为“my_bot”,并注入10000美元模拟资金
pm-trader --account my_bot init --balance 10000
执行成功后,会在你的用户目录下(或通过 --data-dir 指定的路径)创建一个SQLite数据库文件,所有账户数据都将存储于此。你可以通过环境变量 PM_TRADER_ACCOUNT=my_bot 来避免每次命令都指定 --account 。
实操心得 :我建议在项目初期就创建多个账户,例如
my_bot_aggressive和my_bot_conservative,用于测试不同风险偏好的策略。账户间完全隔离,方便进行A/B测试。
3.2 探索市场与获取信息
在开始交易前,你需要先熟悉市场。Polymarket上的市场都有唯一的 slug (URL标识符),如 will-bitcoin-hit-100k 。
# 查看当前最活跃(按流动性排序)的市场列表
pm-trader --account my_bot markets list --sort liquidity --limit 10
# 搜索你感兴趣的主题,比如“ethereum”
pm-trader --account my_bot markets search "ethereum"
# 获取某个特定市场的详细信息,包括所有可能的结果、当前价格、交易量等
pm-trader --account my_bot markets get will-bitcoin-hit-100k
# 查看某个市场的实时订单簿,深度为5档
pm-trader --account my_bot book will-bitcoin-hit-100k --depth 5
# 监控一个或多个市场的价格实时变动(每2秒刷新一次)
pm-trader --account my_bot watch will-bitcoin-hit-100k trump-wins-2024
markets get 和 book 命令返回的信息是策略决策的基础。你需要关注 yes_price 、 no_price (两者之和应为1,加上手续费影响)、 liquidity (流动性深度)以及订单簿的价差(Spread)。流动性差的市场滑点会很大,不适合大资金或高频策略。
3.3 执行交易:市价单与限价单
交易命令直观易懂,但背后的执行逻辑需要清楚。
市价单 :立即以当前市场最优价格成交。
# 买入价值500美元的“YES”份额
pm-trader --account my_bot buy will-bitcoin-hit-100k yes 500
# 卖出50份“YES”份额(注意这里是份额数,不是美元价值)
pm-trader --account my_bot sell will-bitcoin-hit-100k yes 50
市价单可以附加 --type fok (全部成交否则取消)或 --type fak (部分成交剩余取消)指令,这在流动性不足时用于控制风险。
限价单 :指定一个价格,等待市场达到该价格时成交。
# 在0.60的价格下,限价买入价值200美元的“YES”份额
pm-trader --account my_bot orders place will-bitcoin-hit-100k yes buy 200 0.60
下单后,你可以用 orders list 查看所有待成交的限价单,用 orders cancel <order_id> 取消它。一个重要的后台操作是 orders check ,这个命令会检查当前市场价格是否触发了任何待执行的限价单,在运行自动化策略时需要定期调用。
3.4 管理头寸与评估绩效
交易后,你需要时刻关注账户状态。
# 查看账户总览:现金、持仓市值、总盈亏
pm-trader --account my_bot balance
# 查看详细的持仓列表,包含每个仓位的成本价、市价、浮动盈亏
pm-trader --account my_bot portfolio
# 查看交易历史记录
pm-trader --account my_bot history --limit 20
# 生成全面的绩效统计:胜率、投资回报率、总利润、最大回撤等
pm-trader --account my_bot stats
# 生成一个可分享的绩效卡片(适用于社交媒体)
pm-trader --account my_bot stats --card
stats 命令的输出是评估策略好坏的关键。 投资回报率 和 总利润 固然重要,但 最大回撤 更能反映策略的风险控制能力。一个回撤过大的策略,在实际操作中很可能因为心理压力而被提前终止。
4. 策略开发实战:从示例到自定义
项目自带了三个经典策略示例,它们是极好的学习起点。我们以 mean_reversion (均值回归)策略为例,深入拆解其逻辑。
4.1 剖析均值回归策略
这个策略基于一个假设:价格围绕其“公平价值”(对于二元市场,通常是0.5)波动,当价格偏离过大时,有很高的概率会回归。
# 摘自 examples/mean_reversion.py 的核心逻辑
def run(engine: Engine) -> None:
markets = engine.api.search_markets("crypto") # 1. 寻找市场
for market in markets:
if market.closed: # 跳过已关闭的市场
continue
yes_price = market.yes_price
if yes_price is None:
continue
# 2. 计算偏离程度:当前价格低于0.5多少?
deviation = 0.5 - yes_price
# 3. 核心信号:如果YES价格低于0.38(即偏离超过0.12),则买入
if deviation > 0.12: # 买入信号:价格过低
# 计算买入金额:这里用了账户现金的5%,是一种仓位管理
cash = engine.get_balance().cash
amount = cash * 0.05
if amount > 10: # 最小交易单位限制
engine.buy(market.slug, "yes", amount)
log.info(f"Bought {amount:.2f} of YES on {market.slug} at {yes_price:.3f}")
# 4. 止盈逻辑:如果持有该市场的YES仓位,且价格上涨到偏离小于0.02,则卖出
position = engine.get_position(market.slug, "yes")
if position and position.shares > 0:
if deviation < 0.02: # 价格已回归至0.48以上
engine.sell(market.slug, "yes", position.shares)
log.info(f"Sold {position.shares:.2f} YES on {market.slug} at {yes_price:.3f}")
策略逻辑拆解 :
- 选股 :只关注“crypto”相关的市场,缩小决策范围。
- 信号生成 :使用固定的阈值(0.12)作为触发条件。这是一个非常简单的规则,在实战中可能需要根据市场波动率动态调整。
- 仓位管理 :使用固定比例(5%)下单,这是一种防止单笔亏损过大的风险控制方法。
- 退出机制 :设置了明确的止盈条件(回归至0.48),但没有设置止损。这是一个风险点,如果价格继续下跌(比如市场出现永久性结构变化),策略将承受巨大浮亏。
运行这个策略:
pm-trader --account mean_reversion_bot init --balance 5000
pm-trader --account mean_reversion_bot benchmark run examples.mean_reversion.run
benchmark run 命令会调用策略函数,并模拟一个运行周期(默认会持续运行直到手动停止)。你需要在一个终端长期运行它,或者将其部署为后台服务。
4.2 编写你的第一个自定义策略
假设你想尝试一个“突破”策略:当YES价格从下方突破20日均线时买入,跌破均线时卖出。
# my_breakout_strategy.py
import asyncio
from datetime import datetime, timedelta
from pm_trader.engine import Engine
from pm_trader.data import PriceHistory
class BreakoutStrategy:
def __init__(self, engine: Engine):
self.engine = engine
self.price_history = {} # 缓存市场历史价格
async def update_history(self, market_slug: str):
"""获取最近20天的价格历史(需要项目支持历史数据查询,此处为示例逻辑)"""
# 此处为示例,实际可能需要调用 engine.api 的某个历史数据接口
# 假设我们有一个 get_historical_prices 方法
end_time = datetime.utcnow()
start_time = end_time - timedelta(days=30)
# prices = await self.engine.api.get_historical_prices(market_slug, start_time, end_time)
# self.price_history[market_slug] = prices
pass
def calculate_sma(self, market_slug: str, window: int = 20) -> float:
"""计算简单移动平均线"""
if market_slug not in self.price_history:
return None
prices = self.price_history[market_slug]
if len(prices) < window:
return None
recent_prices = prices[-window:]
return sum(recent_prices) / window
async def run(self):
"""主策略循环"""
while True:
markets = self.engine.api.search_markets("politics") # 关注政治市场
for market in markets:
if market.closed:
continue
await self.update_history(market.slug)
sma_20 = self.calculate_sma(market.slug, 20)
current_price = market.yes_price
if sma_20 is None or current_price is None:
continue
position = self.engine.get_position(market.slug, "yes")
# 突破买入信号:当前价上穿均线,且未持仓
if current_price > sma_20 and (position is None or position.shares == 0):
cash = self.engine.get_balance().cash
amount = cash * 0.1 # 用10%仓位
if amount > 10:
self.engine.buy(market.slug, "yes", amount)
print(f"[BUY] {market.slug} at {current_price:.3f}, SMA20={sma_20:.3f}")
# 跌破卖出信号:当前价下穿均线,且持有仓位
elif current_price < sma_20 and position and position.shares > 0:
self.engine.sell(market.slug, "yes", position.shares)
print(f"[SELL] {market.slug} at {current_price:.3f}, SMA20={sma_20:.3f}")
# 每隔5分钟检查一次
await asyncio.sleep(300)
def run(engine: Engine):
"""供 benchmark run 调用的入口函数"""
strategy = BreakoutStrategy(engine)
asyncio.run(strategy.run())
编写策略的关键要点 :
- 状态管理 :你的策略类需要妥善管理每个市场的持仓状态、价格历史等信息,避免重复下单。
- 错误处理 :网络请求、API限流、市场关闭等情况都需要考虑,确保策略能稳定运行。
- 循环与休眠 :策略主循环需要设置合理的休眠间隔,过于频繁的请求可能触发API限制,也浪费资源。
- 日志记录 :清晰的日志对于事后复盘和调试至关重要。
运行你的策略:
pm-trader --account breakout_bot init --balance 10000
pm-trader --account breakout_bot benchmark run my_breakout_strategy.run
4.3 多账户管理与策略对决
polymarket-paper-trader 强大的一个功能是支持多账户并行和策略对决。
# 创建两个不同策略的账户
pm-trader --account strategy_a init --balance 5000
pm-trader --account strategy_b init --balance 5000
# 在后台分别运行两个策略 (使用 & 在Linux/macOS后台运行,Windows可用start)
pm-trader --account strategy_a benchmark run examples.momentum.run &
pm-trader --account strategy_b benchmark run examples.mean_reversion.run &
# 运行一段时间后,比较两个账户的绩效
pm-trader benchmark compare strategy_a strategy_b
# 或者,进行一场“对决”,生成直观的比较卡片
pm-trader pk strategy_a strategy_b
这种A/B测试能力对于量化研究来说是无价的。你可以快速验证一个策略的修改是否带来了正向提升,或者比较两种完全不同交易理念的优劣。
5. 高级集成:通过MCP协议让AI智能体自主交易
对于AI智能体开发者,MCP集成是项目的杀手级功能。它允许像Claude Code这样的AI编程助手直接调用交易工具,实现“自然语言驱动交易”或“自主决策交易”。
5.1 配置MCP服务器
首先,确保你的 polymarket-paper-trader 已安装,并且MCP服务器可执行文件在系统路径中。然后,在你的AI助手配置中(例如Claude Desktop的 claude_desktop_config.json )添加:
{
"mcpServers": {
"polymarket_paper_trader": {
"command": "pm-trader-mcp",
"args": ["--account", "claude_agent"]
}
}
}
重启你的AI助手后,它就能识别出这26个工具了。
5.2 AI智能体交易场景示例
现在,你可以直接向AI助手发出如下指令:
“帮我搜索所有关于‘美联储加息’的活跃预测市场,按流动性排序,列出前三个。”
AI助手在后台会调用 search_markets 和 list_markets 工具,获取并整理信息返回给你。
更进一步,你可以授权AI进行半自主决策:
“分析当前关于‘特朗普赢得2024大选’的市场数据。如果YES价格低于0.45,且最近24小时交易量超过10万美元,就用我账户里10%的资金买入YES份额。然后告诉我你的操作理由。”
AI助手会依次调用 get_market 、 get_order_book (或许还有历史数据工具)进行分析,如果满足条件,则调用 buy 工具执行交易,最后生成一份报告。
5.3 构建完全自主的AI交易员
通过将MCP工具与AI的规划、推理能力结合,你可以构建一个循环运行的智能体:
- 感知 :定期调用
watch_prices或list_markets监控市场动态。 - 分析 :基于获取的数据,结合内置的金融知识或外部新闻API,判断市场情绪和机会。
- 决策 :根据预设的风险规则(如单笔最大亏损、总仓位限制)或学习到的策略,决定交易动作(买/卖/观望)。
- 执行 :调用
buy,sell,place_limit_order等工具执行决策。 - 复盘 :调用
portfolio,stats评估绩效,调用history分析交易记录,从中学习并调整策略。
这种模式将 polymarket-paper-trader 从一个单纯的模拟器,升级为了一个 AI智能体的强化学习环境 。智能体可以在这个零风险的环境中,通过海量的模拟交易来学习市场规律和风险管理。
6. 常见问题、故障排查与进阶技巧
在实际使用中,你肯定会遇到各种问题。这里我整理了一些踩过的坑和解决方案。
6.1 安装与运行问题
问题1: pip install 失败,提示依赖冲突或找不到版本。
- 原因 :Python包依赖环境混乱。
- 解决 :强烈推荐使用
uv或poetry等现代包管理工具创建虚拟环境。# 使用 uv uv venv .venv source .venv/bin/activate # Linux/macOS # .venv\Scripts\activate # Windows uv pip install polymarket-paper-trader
问题2:运行 pm-trader 命令提示“command not found”。
- 原因 :Python脚本的安装目录不在系统的PATH环境变量中。
- 解决 :
- 找到Python的
Scripts目录(Windows)或bin目录(Linux/macOS),例如C:\Users\YourName\AppData\Local\Programs\Python\Python311\Scripts或~/.local/bin。 - 将该目录添加到系统的PATH环境变量中。
- 或者,直接使用
python -m pm_trader.cli来替代pm-trader命令。
- 找到Python的
6.2 交易与策略执行问题
问题3:下单失败,提示“Insufficient balance”(余额不足)。
- 原因 :购买金额超过了账户可用现金。
- 排查 :
- 使用
pm-trader balance确认可用现金。 - 注意,购买价值$100的份额,实际需要的现金可能略高于$100,因为需要支付手续费。引擎会提前计算并检查。
- 检查是否有未成交的限价单冻结了部分资金?限价单在成交前会预冻结相应资金。
- 使用
问题4:限价单一直没有成交。
- 原因 :市场价格从未达到你设定的限价。
- 排查 :
- 使用
pm-trader orders list查看所有待成交订单及其限价。 - 使用
pm-trader price <slug>查看当前市场价格。 - 使用
pm-trader book <slug>查看订单簿,你的买单限价是否高于当前最佳卖价(对于买单)?或者卖单限价是否低于当前最佳买价(对于卖单)?如果不是,订单将无法成交。 - 重要 :确保你定期或在策略循环中运行了
pm-trader orders check命令。这个命令是主动检查并执行符合条件的限价单的触发器。
- 使用
问题5:策略回测结果与实盘模拟差异巨大。
- 原因 :这是最常见也最棘手的问题。
- 排查清单 :
- 滑点 :回测时是否使用了精确的订单簿模型?如果回测只是用中间价成交,会严重低估交易成本。确保你的回测引擎使用了与
polymarket-paper-trader相同的订单簿吃单逻辑。 - 手续费 :回测是否扣除了正确的手续费?
- 流动性 :回测假设的流动性是否与历史实际情况相符?在小流动性市场,大额订单的冲击成本会非常高。
- 未来函数 :确保你的策略在回测中没有使用到“未来的数据”。例如,在计算移动平均线时,只能使用当前K线及之前的数据。
- 滑点 :回测时是否使用了精确的订单簿模型?如果回测只是用中间价成交,会严重低估交易成本。确保你的回测引擎使用了与
6.3 性能与数据管理
问题6:数据库文件越来越大,导致操作变慢。
- 原因 :交易历史、订单历史等数据不断累积。
- 解决 :
- 定期清理旧数据。你可以编写脚本,将
trades和orders表中已结算(resolved)且超过一定时间的记录导出到归档文件后删除。 - 使用
pm-trader export trades --format csv导出历史数据后,使用pm-trader reset --confirm(谨慎!这会清空所有数据) 重置账户,然后重新初始化。 - 对于纯粹的回测需求,考虑每次回测都使用一个全新的、独立的数据库文件(通过
--data-dir指定)。
- 定期清理旧数据。你可以编写脚本,将
问题7:运行自动化策略时,网络不稳定导致API调用失败。
- 解决 :在你的策略代码中必须加入 重试机制和异常处理 。
import time from requests.exceptions import RequestException def safe_api_call(api_func, *args, max_retries=3, **kwargs): for i in range(max_retries): try: return api_func(*args, **kwargs) except RequestException as e: if i == max_retries - 1: raise e wait_time = 2 ** i # 指数退避 print(f"API调用失败,{wait_time}秒后重试... 错误: {e}") time.sleep(wait_time)
6.4 进阶技巧
技巧1:利用 benchmark pk 进行快速策略迭代 不要只满足于运行单个策略。将你的策略核心逻辑封装成一个函数,然后用 benchmark pk 让新旧版本策略使用相同的历史数据或市场环境进行对决,胜者晋级。这是量化开发中高效的进化方法。
技巧2:结合外部数据源 polymarket-paper-trader 提供了市场数据接口,但更复杂的策略可能需要链上数据、社交媒体情绪、新闻事件等。你可以在策略中集成 requests 库调用其他API,构建多因子决策模型。例如,当Twitter上关于某事件的讨论热度飙升时,在相关预测市场提前布局。
技巧3:精细化仓位管理 示例策略中简单的固定比例仓位(如5%)只是开始。更高级的做法包括:
- 凯利公式 :根据胜率和赔率动态计算最优仓位。
- 波动率调整 :在市场波动大时降低仓位。
- 投资组合优化 :在不同相关性的市场间分散投资,降低整体风险。
技巧4:日志与监控 将策略的每次决策、交易执行、账户变动都详细记录到文件或日志服务中。这不仅便于调试,更是事后进行归因分析(Performance Attribution)的宝贵材料。你可以清楚地知道,盈利是来自选市场、择时还是仓位管理。
我个人在长时间使用这个工具进行AI智能体交易策略开发后,最大的体会是: 模拟环境的真实性直接决定了策略迁移到实盘时的生存概率 。 polymarket-paper-trader 在订单簿和费用模型上的较真,强迫我在策略设计阶段就必须考虑流动性、滑点、手续费这些“微观结构”因素,而这些往往是新手策略开发者最容易忽略的“魔鬼细节”。它不仅仅是一个工具,更像是一位严格的教练,提前让你体验真实交易中所有可能遇到的挑战。
更多推荐




所有评论(0)