Files
qmt_bridge/docs/研究/xtquant_big_convert调研.md
T

6.9 KiB

xtquant_big_convert 实现原理调研(基于协议线索 + 官方API还原)

调研日期:2026-08-19 仓库:https://github.com/litaolemo/xtquant_big_convert ⚠️ 注意:本机出网受限(GitHub/镜像/Bing/Baidu 全部不通),无法抓取真实源码。 本文基于方案文档中的协议线索 + 迅投官方API文档(已核实)还原实现原理。 协议线索:请求 RPUSH bigqmt:rpc:queue:{账号} / 响应 BLPOP bigqmt:rpc:respq:{账号}:{reqId}


一、它解决什么问题

目标:让外部 Python 程序(没有 MiniQMT/XtQuantServer 权限)直接调用"大QMT"的交易和行情能力。

背景约束(官方文档核实):

  • xtquant 外部库的 XtQuantTrader / xtdata 本质是和 MiniQMT 建立连接(官方原文)
  • 大QMT(完整交易端)不提供 MiniQMT 的 userdata_mini 连接通道 → 外部 xtquant 直连大QMT 失败
  • 但大QMT 的策略编辑器(内置 Python 3.6)能跑策略,能调 passorder / get_trade_detail_data

解法:把"桥"跑在大QMT 进程内(策略里),外部程序通过 Redis 发 RPC 请求,桥在 QMT 策略线程里执行并回写结果。


二、核心架构

┌─ 外部Python进程(无QMT权限) ─┐        ┌─ Redis ─┐        ┌─ 大QMT进程内(策略) ─┐
│ 你的量化脚本 / sfgrid(TS)     │        │         │        │  qmt_big_convert.py  │
│                              │ ①RPUSH │         │ ②BLPOP │                      │
│  redis_client.rpush(        ├───────►│  queue  ├───────►│  bridge_loop():       │
│    'bigqmt:rpc:queue:{acct}',│        │  {acct}  │        │    解析请求           │
│    json.dumps(req))          │        │         │        │    passorder(...)    │
│                              │        │         │        │    get_trade_detail  │
│ ⑤BLPOP(respq) ←─────────────┼────────┤  respq  │◄───────┤ ④RPUSH 结果          │
│  reqId → 结果                │        │ {acct}: │        │                      │
└──────────────────────────────┘        │ {reqId} │        └──────────────────────┘
                                        └─────────┘

关键:Redis 是"队列桥接"的中枢,不是 HTTP server。这正好绕开官方"QMT 内置 Python 不能多线程"的约束——QMT 侧不需要开监听线程,用一个循环/定时器消费队列即可。


三、Redis 协议设计(从 key 命名还原)

3.1 请求通道

Key:   bigqmt:rpc:queue:{accountID}
Type:  LIST
操作:  外部进程 RPUSH,  QMT桥 BLPOP
Value: JSON 请求体

3.2 响应通道

Key:   bigqmt:rpc:respq:{accountID}:{reqId}
Type:  LIST
操作:  QMT桥 RPUSH,  外部进程 BLPOP(带超时)
Value: JSON 响应体

3.3 推断的请求/响应结构(基于常见 RPC 桥设计 + 协议命名)

// 请求(外部 → QMT)
{
  "reqId": "uuid或自增id",       // 用于关联响应队列
  "method": "order | cancel | query_position | query_asset | kline | ...",
  "params": {
    // order:  {"code":"000001.SZ","opType":23,"volume":100,"priceType":5,"price":-1,...}
    // kline:  {"code":"600000.SH","period":"1d","count":100}
  }
}

// 响应(QMT → 外部)
{
  "reqId": "同上",
  "code": 0,                       // 0成功, 非0错误
  "data": {...} | [...],           // 查询结果 / 下单结果
  "msg": "error message"
}

四、QMT 侧桥程序的关键实现

4.1 入口:策略生命周期

#coding:gbk
import json, redis   # 或自实现极简RESP客户端

def init(ContextInfo):
    ContextInfo.run_time("bridge", "200nMilliSecond", "2019-01-01 00:00:00")
    # 或:
    # 起一个 while 循环线程(若实测线程可用)

def bridge(ContextInfo):
    # 定时/循环:BLPOP 队列
    req = redis_client.blpop('bigqmt:rpc:queue:%s' % ACCOUNT, timeout=0.1)
    if req:
        result = dispatch(req)   # 在策略上下文执行
        redis_client.rpush('bigqmt:rpc:respq:%s:%s' % (ACCOUNT, req['reqId']),
                           json.dumps(result))

def dispatch(req):
    method = req['method']
    if method == 'order':
        return passorder(req['params'])   # 必须传 ContextInfo
    elif method == 'cancel':
        return cancel(...)
    elif method == 'query':
        return get_trade_detail_data(...)
    elif method == 'kline':
        return ContextInfo.get_market_data_ex(...)

4.2 必须处理的点(官方文档核实)

  1. passorder 无返回 → 下单结果要 order_callback/deal_callback 或轮询委托回写
  2. 回调仅实盘模式 + 需 set_account → init 里 ContextInfo.set_account(account)
  3. 状态不能挂 ContextInfo(会回滚) → 用模块级全局 class
  4. 行情函数:内置 Python 用 ContextInfo.get_market_data_ex(不能直接在 init 跑)
  5. 定时器用 run_time(官方无 adjust)

五、为什么它和你的 HTTP 桥方案是"同构"的

维度 xtquant_big_convert 你的 qmt_http_bridge 方案
桥的位置 大QMT 策略内 大QMT 策略内
外部入口 Redis LIST(RPUSH/BLPOP) HTTP server
队列桥接 Redis 队列 内存 ORDER_QUEUE
结果回写 Redis respq + reqId ORDER_RESULTS[rid]
QMT 侧执行 策略线程(定时消费) adjust() 定时消费
解决的问题 外部无 xtquant 权限 外部脚本零改动复用8610

本质相同:都是"大QMT 进程内桥 + 队列 + 策略线程执行 + 结果回写"。


六、Redis vs HTTP 的取舍(你的方案该参考什么)

xtquant_big_convert 用 Redis 的动机(推断)

  • 官方"不能多线程"→ 无法开 HTTP server 线程
  • Redis BLPOP 天然适配单线程轮询:一个 run_time 定时器就能消费
  • 外部 redis-py 客户端成熟,不碰 QMT

但它引入的问题

  1. 需要 Redis 服务 → 多一个运维组件(虽然轻量)
  2. QMT 内置 Python 3.6 是否有 redis 库? → 大概率没有,要自己实现极简 RESP 客户端(纯 socket,~100行)
  3. BLPOP 阻塞语义 → 若桥循环里阻塞,会卡住策略主线程,需要 timeout 参数

对你 HTTP 桥方案的启示

  • 如果实测 QMT 里线程可用 → HTTP 方案可行,但必须加请求超时保护(慢客户端卡死策略)
  • 如果线程不可用 → 你的 HTTP 方案需要改成"单线程事件循环",或者借鉴 Redis 思路:QMT 侧只做定时轮询,HTTP 监听放外部进程(方向B)

七、待验证项(拿到真实源码后核对)

  • 桥是否用 redis-py 还是自写 RESP 客户端
  • 请求/响应 JSON 的确切字段名
  • 下单结果如何回写(回调 or 轮询)
  • 是否处理了 order_callback / deal_callback
  • 定时器用的 run_time 还是线程
  • 是否支持行情(kline)还是只做交易
  • 是否内置了 token/鉴权