🚀 AI 一键生成 qmt 策略代码

QMT API 进阶:如何利用 position_callback 实现策略持仓的实时监控与风控?

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

问题描述

有没有办法让策略在持仓发生变化时立刻得到通知并执行相应的操作?

解决方案

在 QMT 中,要实现持仓发生变化时立刻得到通知并执行操作,最直接且高效的方法是使用 交易回报实时主推函数 中的 position_callback

这是一种事件驱动的机制。与在 handlebar 中轮询查询持仓不同,position_callback 会在交易柜台推送持仓变动信息(如成交导致持仓变化、出入金导致资产变化等)时,由系统自动触发调用。

实现步骤

  1. 绑定账号:在 init 函数中必须调用 ContextInfo.set_account(account_id),否则无法接收到该账号的主推消息。
  2. 定义回调函数:在策略代码中定义 def position_callback(ContextInfo, positionInfo):
  3. 编写逻辑:在回调函数内部,通过 positionInfo 对象获取具体的持仓信息,并编写相应的下单或风控逻辑。

策略代码示例

以下是一个完整的示例代码。当持仓发生变化时,它会打印变动的股票代码和当前持仓量。你可以在注释的位置添加具体的交易逻辑(如止盈止损、对冲下单等)。

# -*- coding: gbk -*-

def init(ContextInfo):
    # 1. 设置资金账号 (必须步骤)
    # 请将 'YOUR_ACCOUNT_ID' 替换为您实际的资金账号
    # 如果是股票账号通常是数字,如果是期货等其他账号请参考QMT显示的ID
    account_id = '6000000000' 
    ContextInfo.set_account(account_id)
    
    print(f"策略初始化完成,已绑定账号: {account_id},等待持仓变动推送...")

def handlebar(ContextInfo):
    # 必须存在该函数,保持策略运行,但此处不需要写轮询逻辑
    pass

def position_callback(ContextInfo, positionInfo):
    """
    持仓变动回调函数
    当持仓状态发生变化时(如成交、数据刷新),系统会自动调用此函数
    :param ContextInfo: 全局上下文对象
    :param positionInfo: 持仓对象,包含具体的持仓信息
    """
    
    # 2. 获取持仓关键信息
    # 证券代码 (如 '600000.SH')
    stock_code = positionInfo.m_strInstrumentID 
    # 证券名称
    stock_name = positionInfo.m_strInstrumentName
    # 当前总持仓量
    volume = positionInfo.m_nVolume
    # 可用持仓量
    can_use_volume = positionInfo.m_nCanUseVolume
    # 持仓成本
    open_price = positionInfo.m_dOpenPrice
    # 持仓盈亏
    profit = positionInfo.m_dPositionProfit
    # 账号ID
    acc_id = positionInfo.m_strAccountID

    # 3. 打印日志或执行逻辑
    print(f"【持仓变动通知】 账号:{acc_id} | 标的:{stock_name}({stock_code})")
    print(f"    -> 当前持仓: {volume}, 可用: {can_use_volume}, 盈亏: {profit}")

    # 4. 在此处编写您的业务逻辑
    # 例如:如果持仓量变为0(已清仓),则执行某些清理操作
    if volume == 0:
        print(f"    -> 检测到 {stock_code} 已清仓,执行后续逻辑...")
        # do_something()
    
    # 例如:如果持仓盈亏超过一定比例,触发止盈单
    # if profit > 10000:
    #     passorder(...) 

关键点说明

  1. positionInfo 对象属性
    回调函数传入的 positionInfo 是一个对象,包含了该只股票的详细持仓状态。常用的属性包括:

    • m_strInstrumentID: 证券代码
    • m_nVolume: 当前持仓数量
    • m_nCanUseVolume: 可用股份数量
    • m_dPositionProfit: 持仓盈亏
    • m_dOpenPrice: 持仓成本
    • m_dMarketValue: 最新市值
    • (更多属性请参考 QMT API 文档附录 6.4.4 position 持仓对象)
  2. 运行模式
    此功能仅在 “实盘”“模拟交易” 模式下有效。在回测模式中,由于没有真实的柜台推送机制,通常不会触发此回调(回测主要依赖 handlebar 的逐 K 线撮合)。

  3. 触发频率
    position_callback 可能会被频繁触发。例如,一笔委托分多次成交,或者行情刷新导致持仓市值变化,都可能触发推送。因此,在编写交易逻辑(如 passorder)时,建议加上状态判断或锁机制,防止针对同一变动重复下单。


Q&A

Q: position_callbackhandlebar 有什么区别?
A: handlebar 是由行情驱动的,每来一个 Tick 或每根 K 线结束时运行一次,适合做基于行情的策略计算。position_callback 是由交易柜台驱动的,只有当账号的持仓数据发生变化(如成交、资金变动)时才会触发,适合做交易风控、止盈止损监控或多策略协同。

Q: 如果我有多个账号,这个函数能区分吗?
A: 可以。positionInfo.m_strAccountID 属性存储了发生变动的账号 ID。你可以在函数内部通过 if positionInfo.m_strAccountID == '账号A': 来区分处理。

Q: 为什么我设置了代码但没有收到推送?
A: 请检查以下几点:

  1. 确保在 init 中正确调用了 ContextInfo.set_account()
  2. 确保策略处于“实盘”或“模拟”运行状态,且账号已登录成功。
  3. 确保确实发生了持仓变动(如果没有交易或数据刷新,不会无故触发)。