Files
qmt_bridge/docs/研究/官方接口核实报告.md
T

11 KiB

QMT 官方接口核实报告(迅投知识库 dict.thinktrader.net)

核实日期:2026-08-19 资料来源:迅投官方知识库 http://dict.thinktrader.net(所有页面已存为 docs_ref/*.txt 供查阅)


一、结论速览

# 方案假设 官方文档核实结果 影响
1 adjust() 是 QMT 定时回调 不存在。官方定时回调是 ContextInfo.run_time(funcName, period, startTime)(支持 500nMilliSecond)或新版 ContextInfo.schedule_run 骨架代码要改
2 HTTP 线程(daemon)+ 队列桥接 官方明确:内置 Python 无法使用多线程和多进程,所有策略在同一线程执行 方案核心架构要重新设计
3 xtdata.get_market_data_ex 任意线程直调 ⚠️ xtdata 模块主动获取接口是 get_market_data,不是 get_market_data_ex(后者是 ContextInfo 方法)。且 xtdata 文档写明"本质是和 MiniQmt 建立连接" 函数名要改;能否连大 QMT 需实测
4 passorder 下单 → 结果回写 确认 passorder(opType, orderType, accountid, orderCode, prType, price, volume, strategyName, quickTrade, userOrderId, ContextInfo),返回无,真实状态靠 order_callback/deal_callback 主推(仅实盘模式生效,需先 set_account) 你的判断正确,补充细节
5 下单须在策略线程执行 正确,必须。所有交易函数依赖 ContextInfo 和策略上下文 成立
6 Python 3.6.8 官方确认:"内置了 3.6 版本的 python 运行环境" 成立
7 # coding:gbk 官方明确要求 成立
8 cancel(orderId, accountId, ContextInfo) ⚠️ 实际签名是 cancel(orderId, accountId, accountType, ContextInfo),有 accountType 参数 修正

二、逐项核实详情

2.1 内置 Python 运行环境(快速开始页)

"QMT 极速策略交易系统...内置了 3.6 版本的 python 运行环境,提供行情数据与交易下单两大核心功能。"

  • 确认方案 4.3 的"Python 3.6.8"判断正确(官方口径 3.6)。
  • 三种运行机制(官方明确):
    1. 逐 K 线驱动 handlebar
    2. 事件驱动 subscribe(订阅推送)
    3. 定时任务 run_time(固定间隔触发)

2.2 ⚠️ 关于线程(使用须知页)—— 最关键发现

"QMT中,python 无法使用多线程和多进程,而且所有策略都在同一线程中执行,所以策略中应该尽量避免阻塞类的写法,否则会影响其他策略的执行。"

这是对整个方案的颠覆性约束:

  • 方案假设的"init() 里启动 HTTP 服务线程(daemon)"很可能直接失败——多线程不可用
  • 队列桥接(HTTP线程入队 → adjust 出队)的双线程前提不成立
  • 需要找到"单线程事件循环"形态的替代架构(见下文第三节)

2.3 系统函数(系统函数页)—— 没有 adjust

  • 官方系统函数列表:ContextInfo对象、initafter_inithandlebarContextInfo.schedule_runContextInfo.cancel_schedule_runContextInfo.run_timestopContextInfo.is_last_barContextInfo.is_new_bar 等。
  • 全文没有 adjust 函数
  • 替代:定时回调用
    # 500ms 定时器
    ContextInfo.run_time("f", "500nMilliSecond", "2019-10-14 13:20:00")
    # 或新版
    ContextInfo.schedule_run(func, time_point, repeat_times, interval, name)
    

2.4 交易下单函数(交易函数页)

passorder 完整签名:

passorder(opType, orderType, accountid, orderCode, prType, price, volume,
          strategyName, quickTrade, userOrderId, ContextInfo)
  • 返回:无(不是布尔/错误码!下单是否成功只能靠回调或查询委托)
  • opType:23=股票买入, 24=股票卖出(期货另有开平仓)
  • orderType:1101=按股数(深沪通用), 1102=沪市按股, 1202=按金额(对账号组)
  • prType:5=最新价, 11=限价, 14=模型价(跟价), 12=市价
  • quickTrade:0=逐K线生效(默认), 1=最后一根K线立即, 2=调用即下单(不判bar状态)
  • userOrderId:用户自设委托ID,会进入 order/deal 对象的 m_strRemark 字段
  • 编译器界面执行的下单函数不会产生实际委托(必须策略交易界面运行)
  • 下单真实结果靠 get_trade_detail_data 查询或回调主推

cancel 实际签名:

cancel(orderId, accountId, accountType, ContextInfo)
  • accountType: 'FUTURE'/'STOCK'/'CREDIT'/'HUGANGTONG'/'SHENGANGTONG'/'STOCK_OPTION'
  • 返回 bool(是否发出撤单信号)
  • 注意:撤单参数是 orderId(委托号, m_strOrderSysID),不是 userOrderId

其他下单:algo_passorder(拆单)、smart_algo_passorder(VWAP等,需权限)、cancel_task/pause_task/resume_task(任务级)、get_basket/set_basket(篮子)。

2.5 交易查询函数(交易函数页)

get_trade_detail_data(accountID, strAccountType, strDatatype[, strategyName])
  • strDatatype: 'ACCOUNT'/'POSITION'/'POSITION_STATISTICS'/'ORDER'/'DEAL'/'TASK'
  • 返回 list 对象,字段以 m_ 开头,如:
    • 账号: m_dBalance(总资产) m_dAssureAsset(净资产) m_dAvailable(可用) m_dInstrumentValue(市值) m_dPositionProfit(盈亏)
    • 持仓: m_strInstrumentID m_nVolume(持仓量) m_nCanUseVolume(可用) m_dOpenPrice(成本) m_dInstrumentValue m_dPositionProfit
    • 委托: m_strOrderSysID(委托号) m_nOrderStatus(状态) m_strRemark(userOrderId) m_nVolumeTraded
    • 成交: m_strOrderSysID m_dPrice m_nVolume m_dTradeAmount

get_value_by_order_id(orderId, accountID, accountType) 按委托号取委托/成交信息。 get_last_order_id(accountID, accountType, 'order'/'deal') 取最新委托号。

2.6 成交回报主推回调(回调函数页)

回调 签名 说明
account_callback (ContextInfo, accountInfo) 资金账号状态变化
task_callback (ContextInfo, taskInfo) 任务状态变化
order_callback (ContextInfo, orderInfo) 委托状态变化主推
deal_callback (ContextInfo, dealInfo) 成交状态变化主推
position_callback (ContextInfo, positionInfo) 持仓状态变化
orderError_callback (ContextInfo, orderArgs, errMsg) 异常下单

重要提示(官方):

  • 回调仅在实盘运行模式下生效
  • 需要先在 init 里调用 ContextInfo.set_account(account)
  • order 对象的 m_strRemark = userOrderId, m_strOrderSysID = 委托号

2.7 行情数据(行情函数页 + XtQuant 文档)

内置 Python(策略内):

ContextInfo.get_market_data_ex(fields=[], stock_code=[], period='1d',
    start_time='', end_time='', count=-1, dividend_type='follow',
    fill_data=True, subscribe=True)
  • 返回 {stock_code: pd.DataFrame},index 为 time,columns 为 fields(open/high/low/close/volume/amount...)
  • 注意:该函数不建议在 init 中运行(init 中只能取本地数据)
  • 周期: 'tick' '1m' '5m' '15m' '30m' '1h' '1d' '1w' '1mon' '1q' '1hy' '1y'
  • 其他: ContextInfo.get_full_tick(全推) ContextInfo.subscribe_quote(订阅) ContextInfo.get_history_data(不推荐) ContextInfo.get_local_data(不推荐)

XtQuant 原生(外部 Python):

xtdata.get_market_data(field_list=[], stock_list=[], period='1d',
    start_time='', end_time='', count=-1, dividend_type='none', fill_data=True)
  • 注意:xtdata 的主动获取接口是 get_market_data(不是 get_market_data_ex!) get_market_data_ex 是内置 Python 的 ContextInfo 方法
  • xtdata 返回:period 为 K 线时 {field: pd.DataFrame}(index 为 stock_list, columns 为 time_list)——与内置 Python 的返回结构不同(内置是 {stock: df},xtdata 是 {field: df})!
  • 运行逻辑(官方原文): "xtdata提供和MiniQmt的交互接口,本质是和MiniQmt建立连接,由MiniQmt处理行情数据请求"

2.8 XtQuant 交易模块(xttrader 文档)

  • 外部 Python 可用 XtQuantTrader(path, session_id) 连接,文档明确绑定 MiniQMT(userdata_mini 路径)
  • 完整 API:order_stock(同步)/order_stock_async(异步)、cancel_order_stock、query_stock_asset/orders/trades/positions、回调 on_stock_order/on_stock_trade/on_order_error 等
  • 这印证了方案判断:外部 xtquant 依赖 miniQMT,大 QMT 不适用,必须走桥策略

2.9 ContextInfo 使用注意(使用须知页)

"由于底层机制的限制,ContextInfo 中存储的变量值将会回滚...请避免在其中存储任何变量。"

  • 官方推荐用 class G(): pass; g = G() 全局对象存状态
  • 桥策略的队列/结果字典等必须用模块级全局变量,不能挂 ContextInfo

三、对方案的修正建议(基于官方文档)

3.1 核心架构问题:单线程约束

官方明确"python 无法使用多线程"。这意味着方案的核心机制(HTTP 线程收请求 + 队列 + adjust 线程执行)需要重新设计。可选方向:

方向 A:单线程异步 HTTP(推荐验证)

  • asyncore/selectors 实现非阻塞 HTTP,或
  • BaseHTTPRequestHandler不开线程——利用 run_time 定时器轮询处理 socket
  • 但 HTTP 长连接/慢客户端会阻塞整个策略,风险仍在

方向 B:桥只做"指令中继",HTTP 放外部(推荐)

  • 把 HTTP 服务放在外部独立进程(Linux 侧或 Windows 侧 Python 3.14),不占用 QMT 策略线程
  • QMT 策略内只保留一个轻量"指令执行器":run_time 定时轮询一个本地指令源(文件/命名管道/端口)
  • 外部 HTTP 桥收到 /order → 写指令文件/管道 → QMT 定时器取指令 → passorder → 回写结果文件
  • 这样 QMT 内零线程、零阻塞,完全符合官方约束;HTTP 的并发/超时/安全都在外部处理

方向 C:验证"线程是否真的不可用"

  • 官方文档说不可用,但社区有说法"能起线程但会阻塞主线程/不稳定"
  • 建议在国金 GJQMT 上做个 10 分钟实测:init 里 threading.Thread(target=...).start() 看是否报错、是否影响 handlebar
  • 如果实测线程能跑,原方案(方向A变体)可保留,但必须加超时保护,避免慢请求卡死策略

3.2 函数修正清单

  1. adjust()ContextInfo.run_time("on_bridge_timer", "500nMilliSecond", "...")
  2. xtdata.get_market_data_ex → 内置 Python 用 ContextInfo.get_market_data_ex;若用 xtdata 模块则 xtdata.get_market_data
  3. cancel(orderId, accountId, ContextInfo)cancel(orderId, accountId, 'STOCK', ContextInfo)
  4. 下单状态:passorder 无返回 → 必须 order_callback + deal_callback(实盘模式 + set_account)或轮询 get_trade_detail_data
  5. 状态存储:不能挂 ContextInfo → 用模块级全局 class 实例

3.3 必须实测的三个点(写码前)

  1. 线程可用性:init 里起 daemon 线程是否真的失败(决定方向A还是B)
  2. set_account:实盘模式回调是否需要、如何配置账号
  3. xtdata 在大 QMT 内能否 import 并取数:若大 QMT 无 miniQMT 的 userdata_mini 连接,xtdata 可能连不上——则行情一律走 ContextInfo.get_market_data_ex

3.4 仍成立的设计

  • 队列桥接思路(若线程可用)、复权/周期参数、GBK 编码、8610 端口复用、脚本零改动目标
  • passorder 必须在策略上下文执行(官方:下单函数需要 ContextInfo,且编译器环境不下单)
  • 实盘模式登录才能收完整回报(官方:回调仅实盘生效)