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

168 lines
6.9 KiB
Markdown

# 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 桥设计 + 协议命名)
```jsonc
// 请求(外部 → 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 入口:策略生命周期
```python
#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/鉴权