问题描述
我在做策略的时候,使用了 get_full_tick 接口获取实时行情,200ms 执行一次,但是每次获取到的最新价格都存在延迟,大概 5s 左右,请问下怎么降低这个延迟呢?
解决方案
在 QMT 平台中,如果你通过定时器(如 run_time 或 Python 原生的 time.sleep)每 200ms 轮询调用 get_full_tick,出现 5 秒左右的延迟,通常是因为轮询机制与 QMT 底层行情推送机制不匹配,或者本地计算阻塞了行情接收线程。为了降低延迟,建议从以下几个方面进行优化:
1. 改用 subscribe_quote 行情订阅模式(强烈推荐)
QMT 提供了基于事件驱动的行情订阅接口 ContextInfo.subscribe_quote。相比于主动轮询,订阅模式会在底层接收到新 tick 数据时立即触发回调函数,这是获取最低延迟实时行情的最佳实践。
优化代码示例:
#coding:gbk
def init(ContextInfo):
# 订阅平安银行的 tick 行情,数据到来时自动触发 on_quote 回调
ContextInfo.sub_id = ContextInfo.subscribe_quote('000001.SZ', period='tick', dividend_type='none', callback=on_quote)
def on_quote(datas):
# datas 是一个字典,key 为合约代码,value 为包含行情数据的 DataFrame
for code, data in datas.items():
# 获取最新价
last_price = data['close'].iloc[-1]
print(f"收到 {code} 最新 tick,最新价: {last_price}")
def handlebar(ContextInfo):
pass
2. 利用 handlebar 的 Tick 驱动机制
QMT 的 handlebar 函数在实时行情下,是由主图品种的 tick 数据驱动的。如果你的策略只需要获取主图品种的最新价,可以直接在 handlebar 中处理,而不需要额外设置 200ms 的定时器。
#coding:gbk
def init(ContextInfo):
ContextInfo.set_universe(['000001.SZ'])
def handlebar(ContextInfo):
# 实时行情下,每个 tick 都会触发一次 handlebar
# 直接获取最新分笔数据
tick_data = ContextInfo.get_full_tick(['000001.SZ'])
if '000001.SZ' in tick_data:
last_price = tick_data['000001.SZ']['lastPrice']
print(f"当前最新价: {last_price}")
3. 避免在回调或主循环中执行耗时操作
如果你在 200ms 的轮询或 handlebar 中执行了复杂的计算、长时间的 I/O 操作(如写入本地文件、请求外部网络接口),会导致 QMT 的主线程被阻塞,底层的行情数据无法及时更新到 Python 层,从而产生严重的“积压延迟”。
- 解决方案:将耗时操作放入异步线程中处理,确保
handlebar或on_quote能够瞬间执行完毕。
4. 检查客户端行情源与网络状态
- 行情源节点:检查 QMT 客户端右下角的网络连接状态,尝试切换到延迟更低的行情服务器节点。
- Level-2 权限:普通的 Level-1 行情本身是 3 秒刷新一次(快照)。如果你需要毫秒级的真实逐笔数据,需要确保你的券商账户开通了 Level-2 行情权限,并在 QMT 中正确登录和启用了 L2 行情源。
总结:放弃 200ms 轮询 get_full_tick 的做法,改用 ContextInfo.subscribe_quote 订阅 tick 周期数据,并确保代码中没有阻塞主线程的耗时逻辑,通常可以将延迟降低到毫秒级别。