IB Paper Trading 手册 + 延迟测试脚本
背景:IB 无官方订单延迟 benchmark,需自测 order-to-ack 基线。本文含 Paper 账户开通/使用手册 + 完整测试脚本。
📘 IB Paper Trading 手册
1. 为什么需要账号(无公开测试端点)
你的脚本 → 本地 TWS/IB Gateway(必须登录账号)→ IBKR 服务器
API 没有独立公开端点,连接必须经过本地运行的 TWS/Gateway,且 Gateway 必须用账号登录。
2. Paper 账户开通流程
- 官网 interactivebrokers.com 注册 Individual 账户
- 登录 Account Management → 开启 Paper Trading(无需真实入金)
- 模拟资金:100 万美元
- 本地安装 TWS 或 IB Gateway,登录时选择 Paper 环境
3. 端口与连接参数
| 环境 | 端口 | 说明 |
|---|---|---|
| Paper Trading | 7496 | 模拟环境,可随意测试 |
| Live 实盘 | 7497 | 真实账户(/ 4001 加密) |
# Gateway 启动参数
ibgateway # 登录时选 Paper 环境;API 设置勾选 Enable ActiveX and Socket Clients
# 连接 clientId 任意(0-31),脚本断开后注意释放
4. 各指标在 Paper 的可信度
| 指标 | Paper 可信度 | 原因 |
|---|---|---|
| order-to-ack | ✅ 高 | 提交→IBKR 确认的处理路径与真实账户几乎一致,延迟量级可信 |
| order-to-fill | ⚠️ 低 | Paper 成交由模拟引擎撮合(近似盘口),成交速度参考意义弱于真实市场 |
正确用法:Paper 测 order-to-ack 拿延迟基线(p50/p95);order-to-fill 和滑点用真实小仓位测(实盘策略日志直接可用)。
🧪 order-to-ack 延迟测试脚本
方案 A:ib_insync(推荐,简洁)
from ib_insync import IB, Stock, LimitOrder
import time, statistics, asyncio
times = [] # (submitted, ack) 秒
ib = IB()
ib.connect('127.0.0.1', 7496, clientId=1, timeout=10)
contract = Stock('AAPL', 'SMART', 'USD')
order = LimitOrder('BUY', 100, 100.0) # 远离市价的限价单,不会成交
for i in range(50):
t_submit = time.perf_counter()
trade = ib.placeOrder(contract, order)
# 等待 orderStatus 回调到达 Submitted
ib.sleep(0.5)
t_ack = time.perf_counter()
times.append((t_ack - t_submit) * 1000) # ms
ib.cancelOrder(order)
ib.sleep(0.2)
ib.disconnect()
p50 = statistics.median(times)
p95 = sorted(times)[int(len(times) * 0.95) - 1]
print(f"order-to-ack: p50={p50:.1f}ms p95={p95:.1f}ms n={len(times)}")
方案 B:原生 ibapi(无第三方依赖)
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.order import Order
import time, threading, statistics
class LatencyTest(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.times = []
self.t_submit = 0
self.pending = 0
def orderStatus(self, orderId, status, filled, remaining,
avgFillPrice, permId, parentId, lastFillPrice,
clientId, whyHeld, mktCapPrice):
if status == 'Submitted':
self.times.append((time.perf_counter() - self.t_submit) * 1000)
self.pending -= 1
if self.pending <= 0:
self.disconnect()
test = LatencyTest()
test.connect('127.0.0.1', 7496, clientId=2)
threading.Thread(target=test.run, daemon=True).start()
contract = Contract()
contract.symbol = 'AAPL'
contract.secType = 'STK'
contract.exchange = 'SMART'
contract.currency = 'USD'
order = Order()
order.action = 'BUY'
order.orderType = 'LMT'
order.totalQuantity = 100
order.lmtPrice = 100.0 # 远离市价,不会成交
test.pending = 50
for i in range(50):
test.t_submit = time.perf_counter()
test.placeOrder(1000 + i, contract, order)
time.sleep(0.1)
import time as t
while test.isConnected():
t.sleep(0.1)
times = test.times
print(f"order-to-ack: p50={statistics.median(times):.1f}ms "
f"p95={sorted(times)[int(len(times)*0.95)-1]:.1f}ms n={len(times)}")
测试要点
- 挂远离市价的限价单(如 AAPL 挂 100.0)——确保不成交,只测 ack 路径
- 测 50 次以上取 p50/p95,单次测量无意义
- 每次测完 cancelOrder 释放
- 用 paper(7496)测,不碰实盘
- 如果测 order-to-fill:用真实小仓位,从策略日志的 placeOrder 时间戳 vs execDetails 时间戳
📈 结果解读
| p50 order-to-ack | 含义 |
|---|---|
| < 10 ms | 网络+IBKR 处理良好,接近本地最优 |
| 10-50 ms | 正常量级(跨区域网络为主) |
| 100 ms+ | 跨国网络 RTT 主导,延迟敏感策略需考虑服务器就近部署(AWS/VPS 就近 IBKR 接入点) |
📎 来源:本文基于 IBKR 官方文档(TWS API Guide:连接端口 7496/7497;Paper Trading 说明)与社区延迟测量实践整理(2026-08-06)。IB 官方未发布延迟 benchmark,数值需自测确认。