问题描述
解决方案
在 QMT 中,默认的 handlebar(ContextInfo) 函数是由主图品种(即你在界面上选择的那个品种)的行情驱动的。如果主图品种没有成交(例如停牌或冷门股),或者你想在其他股票有行情变动时立即触发逻辑,仅依靠 handlebar 是不够的。
要实现实时获取多只股票的行情更新,最标准且高效的方法是使用 ContextInfo.subscribe_quote() 接口配合回调函数。
核心方案:使用 subscribe_quote 进行订阅
该接口允许你订阅任意数量股票的行情(通常是 Tick 分笔数据)。当这些股票有新的行情推送时,系统会立即调用你指定的回调函数,而不需要等待主图的 handlebar 刷新。
代码实现示例
以下是一个完整的策略代码示例,展示了如何订阅多只股票的 Tick 数据并在回调函数中处理:
# -*- coding: gbk -*-
def init(ContextInfo):
"""
初始化函数:在这里进行行情订阅
"""
# 1. 定义需要订阅的股票列表
# 注意:实盘中建议不要一次性订阅过多(如几千只),以免阻塞回调处理
target_stocks = ['600000.SH', '000001.SZ', '600519.SH']
# 2. 遍历列表进行订阅
# 参数说明:
# stock_code: 股票代码
# period: 'tick' (分笔数据), '1m' (1分钟线) 等。实时监控通常用 'tick'
# dividend_type: 'none' (不复权)
# callback: 数据推送时触发的函数名
for stock in target_stocks:
ContextInfo.subscribe_quote(stock, 'tick', 'none', on_quote_update)
print(f"已完成订阅: {target_stocks}")
def on_quote_update(datas):
"""
行情推送回调函数
当订阅的股票有新行情时,此函数会被自动调用
参数 datas: 字典格式 {code: dataframe}
"""
# 遍历推送过来的数据(通常一次推送一只或多只)
for stock_code, df in datas.items():
# df 是一个 pandas DataFrame,包含该股票的行情数据
if not df.empty:
# 获取最新的一行数据
last_row = df.iloc[-1]
# 提取需要的字段,例如最新价、时间、成交量
last_price = last_row['lastPrice']
timetag = last_row['time'] # 时间戳
# 打印输出或执行交易逻辑
print(f"【行情更新】{stock_code} | 时间: {timetag} | 最新价: {last_price}")
# 示例:可以在这里直接写简单的监控逻辑
# if last_price > 100:
# print(f"{stock_code} 价格突破 100元!")
def handlebar(ContextInfo):
"""
主图K线驱动函数
如果使用了 subscribe_quote,这里的逻辑可以留空,
或者只处理与主图品种相关的逻辑。
"""
pass
关键点解析
-
ContextInfo.subscribe_quote:- 这是实现非主图驱动的核心。
- period='tick': 设置为
'tick'可以获得最高频率的更新(分笔成交)。 - callback=on_quote_update: 必须传入一个函数对象(不要加括号),当数据到达时,QMT 底层会把数据打包传给这个函数。
-
回调函数 (
on_quote_update):- 入参
datas是一个字典,Key 是股票代码,Value 是包含行情数据的pandas.DataFrame。 - 这个函数是在独立于
handlebar的事件循环中运行的,因此反应速度最快。
- 入参
-
数据字段:
- 返回的 DataFrame 包含标准的 Tick 字段,如
lastPrice(最新价),amount(成交额),volume(成交量),askPrice(卖价列表),bidPrice(买价列表) 等。
- 返回的 DataFrame 包含标准的 Tick 字段,如
另一种补充方式:主动查询 (Polling)
如果你不需要毫秒级的“推送”,也可以在 handlebar 中使用 ContextInfo.get_full_tick() 主动批量查询。但这种方式受限于主图的刷新频率。
# -*- coding: gbk -*-
def handlebar(ContextInfo):
# 获取当前时刻多只股票的最新 Tick 快照
stock_list = ['600000.SH', '000001.SZ']
tick_data = ContextInfo.get_full_tick(stock_list)
for stock, data in tick_data.items():
print(f"{stock} 最新价: {data['lastPrice']}")
注意:这种方式只有在主图品种产生新 K 线或 Tick 时才会执行,实时性不如 subscribe_quote。
总结
要实现实时监控多只股票,请务必使用 ContextInfo.subscribe_quote 配合回调函数。这是 QMT 提供的标准事件驱动模式。
Q&A
Q: subscribe_quote 订阅的数量有限制吗?
A: 理论上没有硬性限制,但受限于计算机性能和网络带宽。如果订阅全市场几千只股票的 Tick 数据,回调函数处理不过来会导致卡顿或延迟。建议只订阅策略关注的股票池(例如几百只以内)。
Q: 回调函数里可以直接下单吗?
A: 可以。在 on_quote_update 里判断出信号后,可以直接调用 passorder 或 order_shares 等交易函数进行下单。这是实现高频或网格交易的常用做法。
Q: 为什么我的回调函数没有打印数据?
A: 请检查:1. 是否在 init 中正确调用了 subscribe_quote;2. 当前是否为交易时间;3. 策略运行模式是否为“实盘”或“模拟交易”(回测模式下,Tick 级别的回调可能受限于回测数据的精度和机制,通常回测主要依靠 handlebar)。