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)。
- 三种运行机制(官方明确):
- 逐 K 线驱动
handlebar - 事件驱动
subscribe(订阅推送) - 定时任务
run_time(固定间隔触发)
- 逐 K 线驱动
2.2 ⚠️ 关于线程(使用须知页)—— 最关键发现
"QMT中,python 无法使用多线程和多进程,而且所有策略都在同一线程中执行,所以策略中应该尽量避免阻塞类的写法,否则会影响其他策略的执行。"
这是对整个方案的颠覆性约束:
- 方案假设的"init() 里启动 HTTP 服务线程(daemon)"很可能直接失败——多线程不可用
- 队列桥接(HTTP线程入队 → adjust 出队)的双线程前提不成立
- 需要找到"单线程事件循环"形态的替代架构(见下文第三节)
2.3 系统函数(系统函数页)—— 没有 adjust
- 官方系统函数列表:
ContextInfo对象、init、after_init、handlebar、ContextInfo.schedule_run、ContextInfo.cancel_schedule_run、ContextInfo.run_time、stop、ContextInfo.is_last_bar、ContextInfo.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_strInstrumentIDm_nVolume(持仓量)m_nCanUseVolume(可用)m_dOpenPrice(成本)m_dInstrumentValuem_dPositionProfit - 委托:
m_strOrderSysID(委托号)m_nOrderStatus(状态)m_strRemark(userOrderId)m_nVolumeTraded - 成交:
m_strOrderSysIDm_dPricem_nVolumem_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 函数修正清单
adjust()→ContextInfo.run_time("on_bridge_timer", "500nMilliSecond", "...")xtdata.get_market_data_ex→ 内置 Python 用ContextInfo.get_market_data_ex;若用 xtdata 模块则xtdata.get_market_datacancel(orderId, accountId, ContextInfo)→cancel(orderId, accountId, 'STOCK', ContextInfo)- 下单状态:passorder 无返回 → 必须
order_callback+deal_callback(实盘模式 + set_account)或轮询get_trade_detail_data - 状态存储:不能挂 ContextInfo → 用模块级全局 class 实例
3.3 必须实测的三个点(写码前)
- 线程可用性:init 里起 daemon 线程是否真的失败(决定方向A还是B)
- set_account:实盘模式回调是否需要、如何配置账号
- xtdata 在大 QMT 内能否 import 并取数:若大 QMT 无 miniQMT 的 userdata_mini 连接,xtdata 可能连不上——则行情一律走
ContextInfo.get_market_data_ex
3.4 仍成立的设计
- 队列桥接思路(若线程可用)、复权/周期参数、GBK 编码、8610 端口复用、脚本零改动目标
- passorder 必须在策略上下文执行(官方:下单函数需要 ContextInfo,且编译器环境不下单)
- 实盘模式登录才能收完整回报(官方:回调仅实盘生效)