🚀 AI 一键生成 qmt 策略代码
立即体验
👉 AI 生成代码 👈

QMT 平台 VBA 策略中 strategyName 失效导致误撤单怎么办?

qmt | 发布时间: 2026/5/29
以下内容由 EasyQuant 生成。

问题描述

【BUG反馈】VBA下strategyName失效

vba 的下单撤单

PASSORDER(OPTYPE, ORDERTYPE, ACCOUNTID, ORDERCODE, PRTYPE, PRICE, VOLUME, QUICKTRADE, 'strategyName1')
AA:=ORDERINGS(ACCOUNTID,'strategyName2');
FOR ORD IN AA DO CANCEL(ORD.ORDERSYSID,ACCOUNTID,'STOCK');

PASSORDER 指定 strategyName1 策略下单后,查询 strategyName2 策略的委托信息进行撤单,为什么会把 strategyName1 的委托单(实际上是所有的委托单)撤销呢

指定撤单是交易最基本的环节,vba 使用的人虽然不多(基本都是通达信用户),也是迅投的一大特色(其他平台没有 vba,通达信竟然用的是 py,没用最有优势的 vba),但知识库很久没更新了,论坛上的 vba 问题回复讨论的也很少,希望迅投这块可以做好吧,有工作人员可以处理这 bug

解决方案

问题现象分析

在 QMT 平台中使用 VBA 编写策略时,开发者通常希望通过 strategyName(策略名称)来隔离不同策略的委托单,避免互相干扰。您遇到的问题是:

PASSORDER(OPTYPE, ORDERTYPE, ACCOUNTID, ORDERCODE, PRTYPE, PRICE, VOLUME, QUICKTRADE, 'strategyName1')
AA:=ORDERINGS(ACCOUNTID,'strategyName2');
FOR ORD IN AA DO CANCEL(ORD.ORDERSYSID,ACCOUNTID,'STOCK');

预期 AA 只包含 strategyName2 的委托,但实际上 ORDERINGS 返回了该账号下的所有委托单(包括 strategyName1 的单子),导致执行了无差别的全局撤单。这确实是 VBA 接口在特定版本中存在的一个已知过滤失效问题(或底层参数传递未严格匹配)。

为什么会出现这种情况?

  1. 本地标识局限性:在 QMT 底层,strategyName 是一个纯本地客户端的标识(不会发送到柜台),主要用于本地界面的区分和 API 的二次过滤。
  2. VBA 接口封装遗漏:VBA 的 ORDERINGS 函数在底层调用 C++ 接口时,可能未能正确将第二个参数(策略名)作为严格的过滤条件,导致退化为查询该账号下的所有未报/待撤委托。

解决方案与建议

方案一:VBA 下的临时替代方案(手动过滤)

既然 ORDERINGS 无法自动过滤,我们可以在 FOR 循环中手动增加一层判断,检查订单的备注或策略标识(通常映射在订单对象的特定属性中,如 REMARK 或自定义字段),只有匹配时才执行撤单:

// 假设订单对象中有 REMARK 或 STRATEGYNAME 属性(具体视 QMT VBA 对象字典而定)
AA := ORDERINGS(ACCOUNTID, ''); // 直接获取所有
FOR ORD IN AA DO 
BEGIN
    // 手动判断策略名是否匹配
    IF ORD.REMARK = 'strategyName2' THEN 
        CANCEL(ORD.ORDERSYSID, ACCOUNTID, 'STOCK');
END;

(注:具体属性名称请参考 QMT VBA 的内置对象说明,若 VBA 无法读取该属性,则此方法受限。)

方案二:迁移至 Python API(官方主推,完美支持)

正如您所说,QMT 目前的核心优势和官方维护重心都在 Python API 上。Python 接口对 strategyName 的支持非常完善,且文档更新及时。如果您希望实现精细化的订单管理,强烈建议使用 Python。

在 Python 中,实现您上述逻辑的代码如下,绝对不会出现误撤单

#encoding:gbk
def init(ContextInfo):
    ContextInfo.set_account('您的资金账号')

def handlebar(ContextInfo):
    account = '您的资金账号'
    
    # 1. 使用 strategyName1 下单
    # passorder(opType, orderType, accountid, orderCode, prType, price, volume, strategyName, quickTrade, userOrderId, ContextInfo)
    passorder(23, 1101, account, '000001.SZ', 5, -1, 100, 'strategyName1', 1, 'order_1', ContextInfo)
    
    # 2. 精确获取 strategyName2 的委托单并撤单
    # get_trade_detail_data(accountID, strAccountType, strDatatype, strategyName)
    orders_strategy2 = get_trade_detail_data(account, 'stock', 'order', 'strategyName2')
    
    for ord_obj in orders_strategy2:
        # 仅对 strategyName2 的未成委托进行撤单
        if ord_obj.m_nOrderStatus in [48, 49, 50, 55]: # 未报、待报、已报、部成等状态
            cancel(ord_obj.m_strOrderSysID, account, 'stock', ContextInfo)
            print(f"成功撤销 strategyName2 的委托: {ord_obj.m_strOrderSysID}")

总结

QMT 的 VBA 确实是通达信用户的福音,但在复杂交易逻辑(如多策略并发、精细化订单管理)上,VBA 的底层维护频率已不如 Python。建议您:

  1. 向迅投官方客服或客户经理提交该 VBA ORDERINGS 函数的 BUG 反馈,附上复现代码。
  2. 逐步将核心的自动化交易逻辑向 Python 迁移,Python 的 get_trade_detail_data 配合 strategyName 参数可以完美解决您的痛点。