一个 Polymarket REST 模拟器。目标是让策略代码尽量只替换 base_url 即可切换到本地仿真环境。
- FastAPI 服务 + SQLite 持久化
- 可控模拟时钟(设置起点、速度、暂停/恢复)
/_sim/*后台控制端点- 市场与 CLOB 风格公共端点
- CLOB 私有交易端点(下单、撤单、查订单、查成交)
- 价格时间优先撮合、部分成交、IOC/GTC、资金/仓位冻结与释放
- 基于历史订单簿回放的外部对手方成交
- 内置 WebUI:
/admin(后台控制 + 信息查询 + API probe)
pip install -e .[dev]
uvicorn app.main:app --reload --port 8080默认数据库文件:./pm_simulator.db
可通过环境变量 PM_SIM_DB_PATH 指定路径。
- 地址:
http://localhost:8080/admin - 静态资源:
/admin/assets/* - 默认轮询频率:
1s
WebUI 覆盖:
- 仿真控制:时间设置、速度调整、reset
- 信息查询:账户列表、账户成交记录、市场列表、book/price/midpoint/spread/history
- 可用性检测:关键 API 端点状态码/耗时 probe
- 图表详情:选中标的趋势线(全时域)、当前时间竖线、滚轮平移、Ctrl+滚轮缩放
- 请求追踪:最近 API 请求列表(服务级)
- 市场缓存:每行缓存指示灯 + 当前页“导入全部”串行拉取
说明:WebUI 查询严格复用现有接口,不新增后台聚合 API。
- 私有端点(如
/order、/data/*)要求POLY_API_KEY能映射到已创建账户 POLY_TIMESTAMP、POLY_SIGNATURE只做格式校验,不做真实签名验签- CLOB 公共端点(如
/time、/book、/price)无需鉴权头,可匿名访问
- 在上述基础上,额外要求:
- 必须提供
POLY_TIMESTAMP、POLY_SIGNATURE、POLY_NONCE - timestamp 在容忍窗口内(
PM_SIM_AUTH_TIMESTAMP_TOLERANCE_SEC) - nonce 去重并受 TTL 控制(
PM_SIM_AUTH_NONCE_TTL_SEC)
- 必须提供
- 创建测试账户
curl -X POST http://localhost:8080/_sim/accounts \
-H "Content-Type: application/json" \
-d '{"name":"test","initial_cash":10000}'- 下单(替换
${API_KEY})
curl -X POST http://localhost:8080/order \
-H "Content-Type: application/json" \
-H "POLY_API_KEY: ${API_KEY}" \
-H "POLY_TIMESTAMP: 1735689600" \
-H "POLY_SIGNATURE: 0123456789abcdef0123456789abcdef" \
-d '{"token_id":"token_yes","side":"BUY","price":0.55,"size":10,"order_type":"GTC"}'- 调整模拟时间
curl -X POST http://localhost:8080/_sim/time/set \
-H "Content-Type: application/json" \
-d '{"start_time":"2025-01-01T00:00:00Z","speed":20,"paused":false}'GET /healthz- 鉴权:无
- 返回:
{"ok": true}
GET /_sim/time- 鉴权:无
- 返回:时钟快照(
now/timestamp/start_sim_time/speed/paused...)
POST /_sim/time/set- 入参:
start_time(datetime),speed(>0),paused(bool)
- 入参:
POST /_sim/time/speed- 入参:
speed(>0)
- 入参:
POST /_sim/time/pausePOST /_sim/time/resumePOST /_sim/accounts- 入参:
name,initial_cash, 可选api_key/api_secret - 返回:账户与密钥
- 入参:
GET /_sim/accounts- 返回:
{"accounts":[...]}
- 返回:
POST /_sim/reset- 入参:
keep_history(默认true)
- 入参:
POST /_sim/ingest/bootstrap- 入参:
days,max_markets,fetch_books,fetch_prices - 返回:
markets_loaded/tokens_loaded/price_points_loaded/books_loaded/errors
- 入参:
POST /_sim/ingest/market- 入参:
market_id,days,fetch_books,fetch_prices - 返回:指定 market 的导入结果(
market_id/tokens/tokens_loaded/price_points_loaded/books_loaded/errors)
- 入参:
POST /_sim/ingest/status- 入参:
market_ids: string[] - 返回:每个 market 的缓存状态(是否同时具备价格历史与订单簿)
- 入参:
GET /_sim/requests?limit=&offset=- 返回:
{"requests":[...], "total": N}(最近请求日志)
- 返回:
GET /markets- Query:
limit,offset,active,closed,search - 返回:市场数组
- Query:
GET /markets/{market_id}- 返回:单市场详情(支持
id命中)
- 返回:单市场详情(支持
以下端点默认匿名可访问(无需 POLY_* 鉴权头):
GET /timeGET /book?token_id=...POST /books- Body(官方):
[{"token_id":"..."}] - Body(兼容):
{"token_ids":["..."]}
- Body(官方):
GET /price?token_id=...&side=BUY|SELLGET /prices?token_ids=a,b,c&side=BUY|SELLGET /midpoint?token_id=...GET /midpoints?token_ids=a,b,cGET /spread?token_id=...GET /spreads?token_ids=a,b,cGET /prices-history?market=...|token_id=...&startTs=&endTs=&fidelity=&limit=- 说明:实现里
market与token_id二选一解析,interval作为fidelity兼容别名
- 说明:实现里
GET /tick-size(返回minimum_tick_size)GET /fee-rate
以下端点均要求 POLY_API_KEY 对应账户(并受鉴权模式影响):
POST /order- Body:
token_id,side,price,size,order_type(GTC|IOC)
- Body:
DELETE /order/{order_id}GET /data/order/{order_id}GET /data/orders?status=&limit=&offset=GET /data/trades?limit=&offset=
- WebUI 当前已移除独立“私有查询”JSON 调试块;账户成交通过独立表格展示
- 当前不会验证官方真实签名,仅执行格式与模拟规则检查
- 当前未模拟限流行为