# QMT Bridge — 大 QMT 薄桥(HTTP + WebSocket) 将大 QMT(国金 GJQMT_BIG)内置 Python 的行情/交易能力,通过 HTTP RESTful + WebSocket 推送暴露为开放数据服务。接口规范由本地维护的 OpenAPI 文档驱动,可同步 Apifox 管理。 > ## ⚠️ 新会话启动 · 首要参考 > 1. **本文件(README.md)** — 项目概览、结构、接口、部署、约束速查 > 2. **`docs/项目规范.md`** — 详细规范(设计约束/部署/接口文档/迭代规范),项目的"宪法" > 3. **`docs/设计/整体设计方案_v3.md`** — 唯一设计依据(架构决策/环境调研/性能实测) > 4. **`docs/迭代记录/index.md`** — 迭代索引(每次迭代的记录) ## 架构一句话 **薄桥**:跑在 QMT 策略进程内(Python 3.6.8,纯标准库),HTTP 做请求,WS 做推送,所有业务逻辑由 QMT 统一处理,桥只做协议转换。 ``` 外部客户端 ── HTTP(8610): 查询/订阅 ──► 大QMT策略进程 ◄── WS(8610): 行情推送 ── bridge_main.py ``` - 端口: **8610**(HTTP + WS 共端口) - 账号: 单账号(桥绑定),从 `bridge_local_config.py` 读 ACCOUNT_ID ## 目录结构 ``` qmt_bridge/ ├── README.md ← 本文件(会话启动参考) ├── docs/ │ ├── 项目规范.md ← 项目规范(宪法,详细约束) │ ├── api_spec/openapi.yaml ← 接口规范(唯一事实来源,中文,主动维护) │ ├── 设计/整体设计方案_v3.md ← 主设计文档(唯一设计依据) │ ├── 研究/ ← 调研类文档(xtquant_big_convert调研、官方接口核实) │ ├── 迭代记录/index.md ← 迭代索引(每次迭代登记) │ ├── 桥接口清单与sfgrid满足度对照.md │ └── ... ├── src/ ← 桥源码(部署时复制到 QMT python 目录) │ ├── bridge_main.py ← QMT 生命周期入口 │ ├── bridge_http_server.py ← HTTP server + 路由(含 /mcp 路由) │ ├── bridge_ws_server.py ← WebSocket(心跳 + broadcast_all 推送) │ ├── bridge_data_adapter.py ← QMT API 透传适配层 │ ├── bridge_subscription.py ← 订阅管理(snowflake sub_id + QMT 回调→WS 推送) │ ├── bridge_mcp_server.py ← MCP 端点(JSON-RPC tools,POST /mcp) │ ├── bridge_util.py ← 共享状态 + 工具 │ └── qmt_strategy_entry.py ← QMT 策略入口(粘贴进 QMT 编辑器,含热重载) ├── tools/ │ ├── push_apifox.py ← 生成 openapi.json + Apifox 手动导入指引 │ ├── fetch_apifox_doc.ps1 ← 沙箱外抓取 Apifox 文档(UAC 提权) │ └── fetch_qmt_docs.ps1 ← 沙箱外抓取 QMT 官方文档(UAC 提权) ├── tests/ │ ├── test_trade.py ← 交易接口 mock 测试 │ ├── test_subscription.py ← 订阅/退订/tick mock 测试 │ ├── test_ws_push.py ← WS 推送链路 mock 测试 │ ├── test_ws_real.py ← 真实 QMT WS 推送验证 │ ├── test_sub_no_ws.py ← 无 WS 连接时订阅行为测试 │ └── test_mcp.py ← MCP 端点 mock 测试(纯标准库,无需 pandas) ├── reference/ ← 参考材料(xtquant_big_convert 等,只读) └── deploy_elevated.bat ← 部署脚本(自动提权) ``` ## 模块职责与依赖 ``` bridge_main.py ──import──► bridge_http_server.py, bridge_ws_server.py, bridge_data_adapter.py, bridge_subscription.py bridge_http_server.py ──import──► bridge_data_adapter.py, bridge_util.py, bridge_ws_server.py, bridge_subscription.py bridge_ws_server.py ──import──► bridge_util.py bridge_data_adapter.py ──import──► bridge_util.py bridge_subscription.py ──import──► bridge_util.py, bridge_ws_server.py ``` | 模块 | 职责 | |------|------| | bridge_main.py | QMT 生命周期,启动/停止服务器,绑定 QMT API,刷新交易缓存,清理订阅 | | bridge_http_server.py | HTTP 服务,路由(含订阅/退订/tick/MCP),WS Upgrade 分流,openapi 端点 | | bridge_ws_server.py | WS 握手/帧编解码/心跳,broadcast_all 推送 | | bridge_data_adapter.py | 调 QMT API(get_market_data_ex/get_full_tick/get_instrument_detail/get_trading_dates/get_trade_data) | | bridge_subscription.py | 订阅管理: snowflake sub_id、订阅表、QMT 订阅回调→WS 推送 | | bridge_mcp_server.py | MCP 端点: JSON-RPC 2.0(initialize/ping/tools/list/tools/call),9 个工具 | | bridge_util.py | 日志、工具、共享状态(CTX/QMT_API/交易缓存) | | qmt_strategy_entry.py | QMT 策略入口(热重载: 重跑时清模块缓存+释放端口) | ## 当前接口(12 个 HTTP + WS + MCP,详见 docs/api_spec/openapi.yaml) - GET `/health` — 健康检查 - GET `/data/kline` — K线(先下载后查询,fields 可筛选,默认完整 OHLCV) - GET `/data/quote` — 实时快照(单票 full tick,含五档) - GET `/data/tick` — 全推 tick 快照(批量,透传 get_full_tick)【订阅体系】 - GET `/data/instrument` — 合约详情(涨跌停价/名称) - GET `/data/calendar/trading_dates` — 交易日历 - POST `/data/subscribe` — 订阅数据(当前支持 whole 全量tick)【订阅体系】 - POST `/data/unsubscribe` — 退订数据【订阅体系】 - GET `/trade/positions` — 持仓(全部持仓,语义化字段 + m_* 超集 + summary) - GET `/trade/asset` — 资金资产 - GET `/trade/orders` — 委托(code/status/strategy_name 过滤) - GET `/trade/trades` — 成交 - WS `/ws` — 单通道推送(接收 `{"type":"whole","data":{code:tick_dict}}` 增量) - POST `/mcp` — **MCP 端点**(JSON-RPC 2.0,9 个工具与 HTTP 接口 1:1),详见下文「MCP 服务」章节 **待实现**: `/trade/order`(下单)、`/trade/cancel`(撤单)、`/trade/order/status`、WS 账号交易通知(trade_result 等)、MCP `qmt_order`/`qmt_cancel`/SSE 流式。 ## 部署到 QMT 1. 双击 `deploy_elevated.bat`(自动提权,复制 src 下 7 个 .py 到 `C:\Programs\GJQMT_BIG\python\`) 2. QMT 策略编辑器新建策略,粘贴 `qmt_strategy_entry.py` 内容(含热重载) 3. 配置 `C:\Programs\GJQMT_BIG\python\bridge_local_config.py` 的 `ACCOUNT_ID` 4. 运行 → 日志 `[qmt_bridge] HTTP+WS server started on 0.0.0.0:8610` **热重载**: 改代码后 QMT 里 停止→运行 即可(入口自动清模块缓存+释放端口)。 > ⚠️ 若端口被残留占用(监听但不响应),需**重启 QMT 进程**彻底释放。 **验证**: `http://127.0.0.1:8610/health` 返回 ok 即正常。 ## 接口规范同步(Apifox) - 桥提供 `GET /openapi.yaml` / `GET /openapi.json`(从 QMT 目录读取,Apifox URL 同步用) - 手动导入: Apifox → 导入数据 → OpenAPI/Swagger → 文件导入 `docs/api_spec/openapi.yaml` - 辅助: `python tools/push_apifox.py`(生成 json + 打印步骤) - 开放 API 自动推送未打通(沙箱代理伪造 201 / PowerShell 422) ## MCP 服务(AI 助手接入) 桥在 8610 端口提供 **MCP(Model Context Protocol)端点**,AI 助手(Claude Desktop / Cursor / 支持 MCP 的客户端)可通过 `tools/call` 直接调用桥的行情/交易能力,无需自己解析 HTTP。 ### 端点与接入 ``` URL: http://127.0.0.1:8610/mcp (Streamable HTTP,非流式) 鉴权: X-Token header 或 ?token=(与桥 TOKEN 一致;未设 TOKEN 时无需) 方法: initialize → notifications/initialized → ping → tools/list → tools/call ``` Claude Desktop 配置示例(`claude_desktop_config.json`): ```json { "mcpServers": { "qmt_bridge": { "type": "http", "url": "http://127.0.0.1:8610/mcp", "headers": { "X-Token": "<桥 TOKEN,如有>" } } } } ``` ### 工具清单(9 个,与 HTTP 接口 1:1) | 工具 | 对应 HTTP | 说明 | |------|-----------|------| | `qmt_kline` | GET /data/kline | K线(先下载后查询,fields 可筛选) | | `qmt_quote` | GET /data/quote | 实时快照(单票 full tick,含五档) | | `qmt_tick` | GET /data/tick | 批量 tick 快照(codes 逗号分隔) | | `qmt_instrument` | GET /data/instrument | 合约详情(涨跌停价/名称) | | `qmt_trading_dates` | GET /data/calendar/trading_dates | 交易日历 | | `qmt_positions` | GET /trade/positions | 全部持仓(语义化字段 + summary) | | `qmt_asset` | GET /trade/asset | 资金资产 | | `qmt_orders` | GET /trade/orders | 委托(code/status/strategy_name 过滤) | | `qmt_trades` | GET /trade/trades | 成交 | ### 实现要点 - **为什么桥内嵌**: QMT 内置 Python 3.6.8 纯标准库,官方 mcp SDK 要求 Python ≥ 3.10;桥手写 JSON-RPC 2.0(仅 json/socket/threading),零依赖 - **线程约束一致**: 全部工具复用 `bridge_data_adapter` → 与 HTTP 接口同模式(行情 worker 直调,交易读缓存),不违反 QMT 线程约束 - **错误语义**: JSON-RPC 错误走 HTTP 200(parse -32700 / invalid request -32600 / method not found -32601 / invalid params -32602 / internal -32603);非法 body 走 400 - **CORS**: 响应带 `Access-Control-Allow-Origin: *`,`OPTIONS /mcp` 预检 204 - **不做订阅/长连接**: MCP 仅查询(请求-响应);实时数据走 HTTP 订阅 + WS `/ws` 推送 - 详细设计见 `docs/迭代记录/MCP服务.md` ## 本地测试 ```bash python tests/test_trade.py # 交易接口 mock 测试 python tests/test_subscription.py # 订阅/退订/tick mock 测试 python tests/test_ws_push.py # WS 推送链路 mock 测试 python tests/test_mcp.py # MCP 端点 mock 测试(纯标准库,无需 pandas) ``` ## 关键约束(硬性,详见 docs/项目规范.md) 1. **源码编码**: 文件头 `# coding:gbk`,内容必须**纯 ASCII**(UTF-8 中文会 SyntaxError) 2. **QMT 函数线程约束**: `get_trade_detail_data`/`passorder`/`cancel` 只能在**策略线程**调(缓存/队列方案); `get_full_tick`/`subscribe_whole_quote`/`download_history_data` 可在 HTTP 线程调(实测) 3. **单账号**: 桥天然单账号(QMT 一个策略=一个账号),HTTP 接口无 account 参数 4. **字段差异**: 大 QMT 订单行无 `m_strStrategyName`;`m_strInstrumentID` 不带后缀 5. **K线**: 查询前必须先下载;fields 传完整列表;DataFrame 用 iat 取值 6. **错误格式**: `{"detail":"..."}` + 4xx/5xx ## 迭代规范 每次迭代在 `docs/迭代记录/` 定义设计文档,在 `index.md` 登记索引,记录完成情况。详见 `docs/项目规范.md` 第九节。 ## 文档导航 | 文档 | 用途 | |------|------| | `docs/项目规范.md` | 项目宪法: 结构/约束/部署/接口文档/迭代规范 | | `docs/设计/整体设计方案_v3.md` | 唯一设计依据(架构/环境调研/性能实测/变更记录) | | `docs/api_spec/openapi.yaml` | 接口规范唯一事实来源 | | `docs/桥接口清单与sfgrid满足度对照.md` | sfgrid 需求 vs 桥能力 | | `docs/迭代记录/index.md` | 迭代索引 | | `docs/研究/` | 调研文档 |