🚀 AI 一键生成 qmt 策略代码

QMT 高级开发:如何使用 subscribe_quote 实现多品种行情推送?

qmt | 发布时间: 2025/12/20
以下内容由 EasyQuant 生成。

问题描述

如何订阅多个股票的实时行情并触发回调?

解决方案

在 QMT 中,订阅多个股票的实时行情并触发回调主要通过 ContextInfo.subscribe_quote 接口实现。

实现逻辑

  1. 定义回调函数:首先定义一个回调函数(例如 on_quote_callback),该函数接收一个参数(通常命名为 datas)。当订阅的股票有行情更新时,QMT 会自动调用此函数。datas 是一个字典,Key 是股票代码,Value 是包含最新行情的 Pandas DataFrame。
  2. 遍历订阅:在 init 初始化函数中,定义需要订阅的股票列表。通过循环遍历该列表,对每一个股票代码调用 ContextInfo.subscribe_quote
  3. 设置参数:调用订阅函数时,指定周期(如 'tick' 为分笔数据)、复权方式以及刚才定义的回调函数。

策略代码实现

以下是完整的策略代码示例:

# -*- coding: gbk -*-

def on_quote_callback(datas):
    """
    行情推送回调函数
    datas: {stock_code: data_dataframe}
    """
    # 遍历推送过来的数据字典
    for stock_code, df in datas.items():
        # df 是一个 pandas DataFrame,包含该股票的行情数据
        # 通常取最后一行作为最新数据
        if not df.empty:
            last_row = df.iloc[-1]
            
            # 打印接收到的行情信息
            print("=" * 30)
            print(f"收到行情推送 - 代码: {stock_code}")
            print(f"时间: {last_row.name}") # index通常是时间字符串
            print(f"最新价: {last_row.get('close', 0)}")
            print(f"成交量: {last_row.get('volume', 0)}")
            print(f"买一价: {last_row.get('bid1', 0)}") # 注意:字段名取决于周期,tick数据包含盘口
            print("=" * 30)

def init(ContextInfo):
    """
    初始化函数
    """
    print("策略初始化...")
    
    # 1. 定义需要订阅的股票列表
    stock_list = ['600000.SH', '000001.SZ', '600519.SH']
    
    # 2. 遍历列表进行订阅
    for code in stock_list:
        # subscribe_quote 参数说明:
        # stock_code: 股票代码
        # period: 周期,'tick'表示分笔数据,'1m'表示1分钟线等
        # dividend_type: 复权方式,'follow'跟随主图,'none'不复权
        # callback: 数据推送时的回调函数
        
        sub_id = ContextInfo.subscribe_quote(
            stock_code=code, 
            period='tick', 
            dividend_type='none', 
            callback=on_quote_callback
        )
        
        print(f"已订阅 {code}, 订阅ID: {sub_id}")

def handlebar(ContextInfo):
    """
    K线运行函数
    """
    # 必须存在,但在纯行情订阅模式下,逻辑主要在回调函数中处理
    pass

关键点说明

  1. ContextInfo.subscribe_quote

    • 这是核心接口。虽然它一次只接受一个股票代码字符串,但通过 for 循环可以轻松实现批量订阅。
    • period='tick':如果需要最高频率的实时行情(分笔成交、盘口挂单变化),请务必使用 'tick' 周期。如果设置为 '1m',则只会在每分钟结束生成新的 K 线时触发回调。
    • 返回值:该函数返回一个 int 类型的订阅号(subId),如果后续需要取消特定订阅,可以使用 ContextInfo.unsubscribe_quote(subId)
  2. 回调数据结构 (datas)

    • 回调函数的入参 datas 是一个字典 {code: DataFrame}
    • 即使你订阅了多个股票,每次回调触发时,datas 中通常只包含当前发生变动的那只股票的数据(或者同一时刻变动的几只)。因此,必须在回调内部遍历 datas.items() 来处理。
  3. 运行模式

    • 此功能仅在实盘运行(或全推行情的模拟盘)模式下有效。在回测模式下,subscribe_quote 不会触发实时推送回调。

Q&A

Q: subscribe_quote 订阅的数量有限制吗?
A: QMT 客户端本身对订阅数量没有硬性限制,但订阅过多的 Tick 数据(例如几千只股票)会导致回调函数频繁触发,可能造成 Python 线程阻塞或界面卡顿。建议根据硬件性能合理控制订阅数量。

Q: 回调函数中可以直接下单吗?
A: 可以。在 on_quote_callback 中根据行情逻辑判断后,可以直接调用 passorderalgo_passorder 进行交易。这是实现高频或盘口策略的常用方式。

Q: 如何取消订阅?
A: ContextInfo.subscribe_quote 会返回一个订阅 ID。你可以将这些 ID 保存在一个列表中,需要取消时调用 ContextInfo.unsubscribe_quote(sub_id)。另外,策略停止运行时,系统通常会自动清理订阅。

Q: 为什么回调函数里的 DataFrame 字段和文档不一样?
A: DataFrame 的列(Columns)取决于订阅的 period

  • period='tick': 包含 lastPrice, volume, amount, bid1...bid5, ask1...ask5 等详细盘口数据。
  • period='1d' / '1m': 包含 open, high, low, close, volume, amount 等标准 OHLCV 数据。