Skip to main content

xtquant_big_convert

大 QMT 运行环境里的 RPC 桥接包:把大 QMT 内置 Python(行情查询、交易、持仓)封装成可远程调用的服务,并兼容一组 MiniQMT 方法名,让外部程序无需 XtQuantServer 权限就能驱动大 QMT。

支持 Redis / ZMQ / MySQL / 共享内存 四种可插拔传输,切换只需改一个配置字段。

另附 qmt-trader skill:让 Claude Code / ZCode / Cursor 等 AI 助手通过统一 CLI(46 个子命令)直接查行情、查持仓、下单撤单,详见下文「AI 助手 Skill:qmt-trader」。


功能一览

RPC 接口(远程可调用)

通过 RPC 可调用的大 QMT 能力(白名单 117 个只读方法 + 2 个下单方法 + 12 个 MiniQMT 风格别名,覆盖官方文档全部交易/查询函数):

类别 方法
系统 ping
行情快照 get_ticks / get_full_tick(五档盘口)
K线/历史 get_market_data / get_market_data_ex / get_local_data / get_close_price / get_index_weight
L2 行情 get_l2_quote / get_l2_order / get_l2_transaction / subscribe_l2thousand(需 L2 权限)
板块 get_stock_list_in_sector / get_sector_list* / get_sector_info / create_sector / add_sector / remove_sector
交易日历/时段 get_trading_dates / get_holidays* / get_markets* / get_market_last_trade_date* / get_date_location / get_trading_calendar / get_trade_times
数据下载 download_history_data / download_history_data2 / download_holiday_data / download_etf_info / download_cb_data / download_history_contracts / download_index_weight / download_sector_data
财务/因子 get_financial_data / download_financial_data / download_financial_data2 / get_raw_financial_data / get_factor_data
ETF/期权/期货 get_etf_info / get_ipo_info / get_option_list / get_his_option_list / get_his_option_list_batch / get_option_detail_data / get_option_undl_data / get_option_undl / get_ETF_list / get_main_contract / get_his_contract_list
期权定价 bsm_price / bsm_iv / get_option_iv
龙虎榜/股东 get_longhubang / get_top10_share_holder / get_holder_num / get_turnover_rate(区间换手率)/ get_industry / get_his_st_data / get_his_index_data
资金流 get_north_finance_change(北向)/ get_hkt_statistics(港股通)/ get_hkt_details / get_hkt_exchange_rate
因子/模型 call_formula / subscribe_formula / unsubscribe_formula / get_formula_result / gen_factor_index
时间转换 datetime_to_timetag / timetag_to_datetime / timetagToDateTime(纯本地计算)
账户查询 get_asset(资金)/ get_positions(持仓)/ query_stock_position(单股持仓)/ query_orders(委托)/ query_trades(成交)/ get_history_trade_detail_data(历史成交)/ get_value_by_order_id / get_last_order_id
新股/打新 get_ipo_data / get_new_purchase_limit
融资融券 get_assure_contract(担保品)/ get_enable_short_contract(融券标的)/ get_unclosed_compacts(未平仓)/ get_closed_compacts(已平仓)/ get_debt_contract(负债)—— 需两融权限,普通账户降级为空
期权持仓 get_option_subject_position(标的持仓)/ get_comb_option(组合期权)
持仓同步 sync_positions(写回 Redis 供客户端缓存)
下单/撤单 submit_order / cancel_order(默认关闭,需显式开启)

客户端兼容层 BigQmtXtData 对常用方法有显式封装(xtdata.get_longhubang(...)xtdata.bsm_price(...) 等),其余通过万能入口 xtdata.call_method("get_float_caps", stockcode="000001.SZ") 调用。

* 标记的方法在大 QMT(完整交易端)环境下用 fallback 实现(非原生数据):get_sector_list 返回常用板块名清单,get_holidays 从交易日历反推,get_markets 返回固定市场集合,get_market_last_trade_date 从日历派生。详见 docs/RPC_API_REFERENCE.md 第 8 节「大 QMT 环境的能力边界」。

客户端兼容层

  • bigqmt_signal_trader.xtquant_compat:把旧代码的 xt_trader / xtdata 调用转成 RPC,无需改业务代码。
  • 兼容 MiniQMT 方法名:query_stock_asset / query_stock_positions / query_stock_orders / get_full_tick / order_stock 等。
  • 完整 xtconstant 枚举(91 个常量,对齐原生 MiniQMT):账号类型、委托类型(股票/期货/信用/期权)、报价类型、委托状态、账号状态、ORDER_TYPE_SET
# 旧代码零改动(自动命中 shim)
from xtquant.xtconstant import STOCK_BUY, FIX_PRICE, ORDER_SUCCEEDED

# 或直接从 compat 导入
from bigqmt_signal_trader.xtquant_compat import (
    SECURITY_ACCOUNT, STOCK_BUY, FIX_PRICE, CREDIT_FIN_BUY,
    FUTURE_OPEN, ACCOUNT_STATUS_OK, ORDER_SUCCEEDED,
)

异步回报回调(MiniQMT 风格,实盘验证)

客户端注册 XtQuantTraderCallback 子类,connect()/subscribe() 后实时接收委托/成交/错误回报(通过 Redis pubsub 推送):

from bigqmt_signal_trader.xtquant_compat import (
    StockAccount, XtQuantTraderCallback, configure, xt_trader,
)

class MyCallback(XtQuantTraderCallback):
    def on_stock_order(self, order):
        print("委托回报:", order.stock_code, order.order_status, order.order_sysid)

    def on_stock_trade(self, trade):
        print("成交回报:", trade.stock_code, trade.order_id, trade.traded_volume, trade.traded_price)

    def on_order_error(self, order_error):
        print("委托失败:", order_error.order_id, order_error.error_id, order_error.error_msg)

    def on_cancel_error(self, cancel_error):
        print("撤单失败:", cancel_error.order_id, cancel_error.error_id, cancel_error.error_msg)

    def on_order_stock_async_response(self, response):
        print("异步下单回报:", response.account_id, response.order_id, response.seq)

    def on_account_status(self, status):
        print("账户状态:", status.account_id, status.account_type, status.status)

configure()
xt_trader.register_callback(MyCallback())
acc = StockAccount(xt_trader.client.account_id, "STOCK")
xt_trader.connect()
xt_trader.subscribe(acc)

# 异步下单(返回 seq,回报走回调)
seq = xt_trader.order_stock_async(acc, "600654.SH", 23, 100, 11, 2.95, "rpc_test", "备注")

完整的回调链(对齐 MiniQMT 原生语义,实盘验证):

回调 触发时机 已验证
on_account_status connect()/subscribe()
on_order_stock_async_response(seq, resp) 异步下单提交成功 ✅(实盘)
on_stock_order(order) 委托状态变化(已报 50 / 已成 56 / 废单 57) ✅(实盘)
on_stock_trade(trade) 成交回报
on_order_error(err) 废单/拒单(服务端检测 status=57 推送) ✅(实盘)
on_cancel_error(err) 撤单失败
on_cancel_order_stock_async_response 异步撤单回报

*_async 查询方法(对齐 MiniQMT 签名,callback 可选):

# 方式 1:callback 接收结果(MiniQMT 原生语义,返回 None)
xt_trader.query_stock_asset_async(acc, lambda asset: print(asset.cash, asset.total_asset))
xt_trader.query_stock_positions_async(acc, lambda positions: print(len(positions)))

# 方式 2:不传 callback,返回 seq(我们的扩展)
seq = xt_trader.query_stock_orders_async(acc)

注意:QMT 必须运行在实盘模式(非模拟/模型交易)才能收到完整回报。模拟模式下委托进 QMT 界面但不在真实委托队列,query_orders 查不到、order_stock 返回 -1(触发 on_order_error)。

全推行情订阅(subscribe_whole_quote 真推送)

subscribe_whole_quote服务端真推送——对齐 MiniQMT 全推行情订阅。服务端引用计数管理 ContextInfo.subscribe_whole_quote 回调,通过独立 PUB/SUB 通道向客户端增量推送行情(不是一次性快照):

架构(三通道)

  1. 控制面 RPC——subscribe_whole_quote / unsubscribe_whole_quote / quote_keepalive 方法(复用现有 transport)
  2. 数据面推送——QuotePushChannel 单向 PUB/SUB(redis pub/sub 或 zmq PUB/SUB,按部署 transport 选择;msgpack 编码 + json 兜底)
  3. Big-QMT 行情源——QuoteSubscriptionManager 按组合键归一化共享(大写/去空格/排序),多客户端共享一个底层订阅

关键设计

  • 组合键去重:不同客户端订阅相同标的组合,只占一个 big-QMT 订阅
  • 引用计数:按 (client_id, sub_id) 计数,全部退订或 30s keepalive 超时才销毁
  • 客户端心跳:周期 quote_keepalive;检测推送静默(默认 10 轮心跳)自动重放订阅,服务端重启后自动恢复
  • 初始快照:客户端用 get_full_tick 预拉快照(big-QMT 回调是增量的)

用法

from bigqmt_signal_trader.xtquant_compat import configure, xtdata

configure()

# 订阅全推行情(callback 收到增量推送)
def on_quote(data):
    for code, tick in data.items():
        print(code, tick.get("lastPrice"))

seq = xtdata.subscribe_whole_quote(["600000.SH", "000001.SZ"], callback=on_quote)

# 退订
xtdata.unsubscribe_quote(seq)

验证:实盘交易日验证 1/20/50/100 只标的,3s 推送节奏稳定,零丢失零乱序;多客户端共享/退订隔离/同客户端多 sub_id 全过;服务端重启恢复(42s 中断后验证两次)。详见 docs/SUBSCRIBE_WHOLE_QUOTE_PUSH.mddocs/SUBSCRIBE_WHOLE_QUOTE_LIVE_VERIFICATION.md

可插拔传输层

传输 同机 p50 跨机 适用场景
redis(默认) ~13ms 生产默认,稳定
zmq ~0.7ms* 同机低延迟
mysql ~105ms 兼容兜底
shm 接口预留(未实现)

*zmq fast-path;约 30% 请求会撞 QMT 的 GIL 调度尖峰(~500ms)。

FormulaServer 直连快速路径(只读行情,默认开启)

大 QMT 的 58600 端口是 FormulaServer——QMT 内置的 C++ 行情/参考数据服务(端口取自 config/formulaserver/formulaserver.ini[server_formula] address)。QMT 自带 Python 的 qmt_api 包就是它的客户端。

客户端对这些方法会绕开整条 RPC 链路(不经过 QMT 的 python 策略线程,也不抢 GIL), 实测 p50 0.07ms,穿过完整客户端栈是 0.145ms/次

对比 p50
redis RPC ~13ms
zmq RPC ~0.7ms(30% 撞 500ms GIL 尖峰)
FormulaServer 直连 0.07ms(无 GIL 竞争)

直连覆盖 10 个方法:get_instrument / get_instrument_detail / get_instrumentdetail / get_last_volume / get_total_share / get_contract_multiplier / get_main_contract / get_weight_in_index / get_stock_list_in_sector / get_market_data_ex

能力边界(重要):FormulaServer 只有行情/参考数据。所有账户、持仓、委托、成交、下单 方法一律返回 ErrorID 200005 未找到该服务getFullTick/getQuote 也不存在。所以它是 只读快速路径,不是 RPC 桥的替代品——交易、账户查询、五档盘口仍然走 RPC。

以下方法刻意不走直连,因为参数语义与我们的调用方不一致,宁慢勿错:

  • get_trading_dates —— FormulaServer 要股票代码000001.SZ),传市场代码(SH)静默返回 [],而我们的调用方传的是市场。
  • get_divid_factors / get_risk_free_rate —— 参数语义不同(区间 vs 单日、index vs timetag)。
  • 复权 K 线 —— 实测 dividendTypenonefront 返回完全相同,复权未生效。因此只有 dividend_type="none" 才走直连,其余回退 RPC,避免静默返回未复权价格。 (复权数据还需先在服务端下载原始数据,见下文「复权数据下载陷阱」。)

配置(客户端侧,默认就是开启,通常不用写):

BIGQMT_REDIS_CONFIG = {
    "formula_server": {
        "enabled": True,              # 或环境变量 BIGQMT_FORMULA_ENABLED=0 关闭
        # "host": "127.0.0.1",        # 默认本机;FormulaServer 绑 0.0.0.0,跨机需放行防火墙
        # "port": 58600,              # 不写则从 qmt_root 的 ini 读,再退回 58600
        # "qmt_root": r"D:\国金证券QMT交易端",
        # "timeout_seconds": 3.0,
        # "methods": ["get_instrument"],       # 只路由白名单里的方法
        # "failure_cooldown_seconds": 30.0,    # 连不上后停用多久再重试
    },
}

失败一律自动回退 RPC:方法未映射、参数translate 不了、服务没起、连接断——都退回原路径, 所以连不上 58600 的客户端行为与改动前完全一致。BSON 编解码内置了无依赖实现(可选用 pymongo 的 bson,两者输出实测逐字节一致),客户端不需要额外装包。

独立 ZMQ 回测桥接

bigqmt_backtest 与实盘 RPC 桥接完全分离,提供两个明确隔离的后端:

  • QMT_NATIVEBIGQMT_ZMQ_BACKTEST.py 运行在 QMT 回测进程内。QMT 负责历史 行情推进、资金持仓、passorder/cancel 和原生撮合;ZMQ 只桥接 Bar、订单意图及 QMT 委托/成交结果。
  • LOCAL_SIM:端口 16661 的独立 CSV 工具,仅用于脱离 QMT 验证协议和策略逻辑, 使用本地撮合并输出本地结果文件。

QMT 原生入口使用独立端口 16662、独立 run_id/client_id,强制验证 ContextInfo.do_back_test=true,固定 live_ready=false,不会导入或修改 bigqmt_signal_trader

启动 CSV 独立测试服务:

python -m pip install -e .
python -m bigqmt_backtest.server `
  --data examples/backtest_bars.example.csv `
  --config examples/backtest_config.example.json `
  --run-id demo-001 `
  --bind tcp://127.0.0.1:16661

另开一个终端运行外部策略:

python examples/zmq_backtest_strategy.py `
  --endpoint tcp://127.0.0.1:16661 `
  --run-id demo-001 `
  --symbol 600000.SH `
  --fast 2 `
  --slow 3

QMT 原生安装、逐 Bar 同步协议、CSV 备用模式和安全边界见 docs/ZMQ_BACKTEST_BRIDGE.md

无 redis 版本(QMT 沙箱拒绝 import redis 时用)

如果你的 QMT 环境拒绝 import redis(券商白名单拦截),用 bigqmt_no_redis/ 目录下的无 redis 版本:

  • bigqmt_no_redis/zmq_transport.py — 自包含的 ZMQ transport,内联所有编码函数,完全不 import redis_common/redis_rpc,去掉 redis 服务发现(用静态派生端口)
  • bigqmt_no_redis/DRYRUN_no_redis.py — 无 redis 的 DRYRUN 入口,强制 transport=zmq + background_threads=True,只加载 zmq transport

用法:QMT 策略编辑器加载 BIGQMT_DRYRUN_NO_REDIS.py(同步到 QMT 目录时用这个文件名),RPC 走纯 ZMQ,零 redis 依赖。其余功能(行情/交易/持仓查询)与标准版一致。

委托/成交查询的 strategy_name 陷阱(重要)

get_trade_detail_datastrategy_name 过滤委托/成交——下单时用的 strategy_name 必须和查询时一致,否则查不到。

  • 下单时传 strategy_name="rpc_test" → 委托记在 rpc_test
  • 查询时传 strategy_name="bigqmt_signal_trader" → 返回空(不匹配)

修复query_orders / query_trades 默认传空字符串 "",返回该账户的全部委托/成交(不按 strategy_name 过滤)。如需过滤,显式传 strategy_name

实测验证(get_trade_detail_data 探测):

  • st="" → ORDER=9, DEAL=9(全部)
  • st="rpc_test" → ORDER=3, DEAL=1(只有 rpc_test 的)
  • st="bigqmt_signal_trader" → ORDER=0, DEAL=0(空)

复权数据下载陷阱(重要)

前/后复权 K 线必须先在服务端下载原始数据,否则返回全 0

Big QMT 的复权(dividend_type='front'/'back')是服务端现场计算的——需要原始 K 线 + 除权因子已经在服务端存在。直接请求 front 而服务端没下载过原始数据时,返回的 close 全是 0.0(只有最后一根有价)。

实测复现(600654.SH / 600227.SH):

  • 直接 get_market_data_ex(dividend_type='front') → 634 行全 0
  • download_history_data 后再请求 → 真实复权价(front ≠ none,复权生效)

已修复xtdata.download_history_data2(codes, period, dividend_type='front') 现在会自动先触发服务端原始数据下载(拉原始 K 线 + 除权因子),再拉复权数据到本地缓存。用法不变:

# 前复权下载(自动先服务端下载原始数据 + 除权因子)
xtdata.download_history_data2(["600654.SH"], period="1d",
                               start_time="20240101", dividend_type="front")

# 之后本地读取(零 RPC)
xtdata.get_local_data(["close"], ["600654.SH"], period="1d",
                      start_time="20240101", dividend_type="front")

读取类 API 也自愈get_market_data_ex / get_market_data 带复权参数时,若检测到返回全 0(服务端缺原始数据),会自动触发服务端下载、等待落盘、重试一次,拿到真实复权价。get_local_data 的 fallback 拉取同样受益。无需手动等待。

注意:QMT 服务端下载是异步落盘的,自愈路径内置了等待 + 一次重试;极端大区间若一次重试仍全 0,可稍后重读或先显式 download_history_data2

实盘卖出方向误判修复(exec_events)

实盘发现:QMT 回调里 m_nDirection 恒为 48(即使是卖出),导致卖出被误判为买入。

修复(exec_events._extract_direction)改为仲裁链:

  1. m_nOffsetFlag(最可靠,匹配 query_orders
  2. m_nDirection(传统 EEntrustBS,但实盘可能恒为 48)
  3. 当 direction≠offset(期货:卖+开仓=49+48),用 m_nOpType(23=买/24=卖)仲裁
  4. m_nOpType/order_type(兜底)

对股票现货,direction=offset(48=买/49=卖);对期货,direction≠offset,仲裁保正确。

多账号使用(股票+期货 / 普通+信用)

当前架构是单账号单实例——一个 QMT 策略进程绑定一个账号,RPC channel 按 account_id 隔离(bigqmt:rpc:req:{account_id})。多账号场景(如股票+期货、普通+信用账户同时交易)的推荐方案是在 QMT 里跑多个策略实例,每个实例绑一个账号。

方案:多策略实例(推荐,不改代码)

服务端(QMT 内):为每个账号创建一个独立的配置文件和 DRYRUN 入口。

# bigqmt_signal_trader_local_config_stock.py  — 股票账号
BIGQMT_ACCOUNT_ID = "你的股票账号"
BIGQMT_REDIS_CONFIG = {
    "host": "...", "port": 6379, "db": 5, "password": "...",
    "transport": "redis",          # 或 "zmq"
    "account_type": "STOCK",       # 股票
    # ...
}

# bigqmt_signal_trader_local_config_credit.py  — 信用账号
BIGQMT_ACCOUNT_ID = "你的信用账号"
BIGQMT_REDIS_CONFIG = {
    "host": "...", "port": 6379, "db": 5, "password": "...",
    "transport": "redis",
    "account_type": "CREDIT",      # 信用(两融)
    # ...
}

然后在 QMT 策略编辑器里加载两个 DRYRUN 文件(每个指向不同的配置),分别运行。两个实例的 RPC channel 自动隔离(按 account_id)。

zmq 模式注意:每个实例的 zmq 端口从 account_id 派生(15560 + account_id mod 100),不同账号自动不冲突。

客户端(外部程序):为每个账号创建独立的 client/trader 对象。

from bigqmt_signal_trader.xtquant_compat import BigQmtRpcClient, BigQmtXtTrader, StockAccount

# 股票账号
stock_client = BigQmtRpcClient(account_id="股票账号", redis_config={...})
stock_trader = BigQmtXtTrader(account_id="股票账号", redis_client=stock_client.redis_client)
stock_acc = StockAccount("股票账号", "STOCK")

# 信用账号
credit_client = BigQmtRpcClient(account_id="信用账号", redis_config={...})
credit_trader = BigQmtXtTrader(account_id="信用账号", redis_client=credit_client.redis_client)
credit_acc = StockAccount("信用账号", "CREDIT")

# 分别查询/下单
stock_asset = stock_trader.query_stock_asset(stock_acc)
credit_positions = credit_trader.query_stock_positions(credit_acc)

跨账号隔离:每个账号的 RPC channel、持仓查询、委托回报完全隔离(按 account_id 路由),互不影响。


环境要求与依赖安装

本系统分两部分,各自需要自己的 Python 环境和依赖:

部分 运行位置 Python 装什么
客户端(外部程序) 你的开发机 3.8+(推荐) pip install xtquant-big-convert
服务端(QMT 内) QMT 的 bin.x64/python.exe 3.6(QMT 自带) 按传输装 1 个包

A. 客户端(外部程序,推荐 pip 安装)

客户端就是写策略/调接口的那台电脑(也叫「开发机」)。直接 pip 安装:

# 基础安装(含 pyzmq,zmq 传输必需)
pip install xtquant-big-convert

# 含 redis 支持(redis 传输)
pip install xtquant-big-convert[redis]

# 含 mysql 支持(mysql 传输)
pip install xtquant-big-convert[mysql]

# 开发环境(含测试工具)
pip install xtquant-big-convert[dev]

# 从源码安装(开发模式)
git clone https://github.com/litaolemo/xtquant_big_convert.git
cd xtquant_big_convert
pip install -e .

安装后可直接 import:

from bigqmt_signal_trader.xtquant_compat import configure, xt_trader, xtdata
from bigqmt_signal_trader.transports.factory import build_transport

configure()
print(xtdata.get_full_tick(["000001.SZ"]))

B. 服务端(QMT 内 Python 3.6)

QMT 自带 Python 3.6(bin.x64/python.exe),只需按你选的传输装对应依赖

传输 服务端需要的包 客户端需要的包
redis(默认) redis(QMT 通常已内置) redis
zmq pyzmq pyzmq(基础安装已含)
mysql pymysql + DBUtils pymysql + DBUtils

⚠️ 用 redis 传输就不需要装 pyzmq / pymysql / DBUtils——下面的安装说明是按需的,你用什么传输装什么。

安装到 QMT 的 Python(以 zmq / mysql 为例):

QMT 的 Python 3.6 用旧 OpenSSL,pip 直连 HTTPS 镜像会报 SSL 错误。有两种方法:

# 方法 A:从开发机拷贝纯 Python 包(推荐,绕过 SSL 问题)
# pymysql / DBUtils 是纯 Python,可直接拷贝;在开发机(已装这些包)执行:
$QMT_SITE = "D:\国金证券QMT交易端\bin.x64\Lib\site-packages"
Copy-Item -Recurse "C:\Users\<你>\anaconda3\Lib\site-packages\pymysql" "$QMT_SITE\pymysql"
Copy-Item -Recurse "C:\Users\<你>\anaconda3\Lib\site-packages\dbutils" "$QMT_SITE\dbutils"

# 方法 B:用 QMT python pip 装(可能因 SSL 失败,需配置信任)
cd D:\国金证券QMT交易端
.\bin.x64\python.exe -m pip install --trusted-host mirrors.aliyun.com pymysql DBUtils

验证安装:

.\bin.x64\python.exe -c "import pymysql; from dbutils.pooled_db import PooledDB; print('OK')"

pyzmq 特殊说明:包含 C 扩展,不能直接拷贝。Python 3.6 需装 pyzmq==19.0.2(最后一个支持 3.6 的版本)。如果 SSL 装不上,可下载对应 wheel 手动 pip install xxx.whl


快速开始

前置:客户端已按上面「A. 客户端」装好包;服务端按「B. 服务端」装好所选传输的依赖。下面是从零跑通整套流程的步骤。

第 1 步:同步代码到 QMT 的 python 目录

把以下内容复制到大 QMT 的 python 目录(如 D:\国金证券QMT交易端\python\):

src/bigqmt_signal_trader/          (整个核心包,含 transports/)
src/bigqmt_signal_trader_strategy.py
src/bigqmt_signal_trader_redis_rpc_runtime.py
src/BIGQMT_REDIS_DRYRUN.py         (★ QMT 编辑器入口,GBK 编码,在 QMT 里加载这个)

在 QMT 策略编辑器里只加载 BIGQMT_REDIS_DRYRUN.py 一个文件。它会自动 import 上面其余文件。其余 .pybigqmt_signal_trader_*)是它依赖的模块,不是直接运行的入口。

第 2 步:创建 QMT 端私有配置

在 QMT 的 python 目录创建 bigqmt_signal_trader_local_config.py不要提交此文件):

# coding: utf-8
BIGQMT_ACCOUNT_ID = "你的资金账号"        # 如 "1234567890"

BIGQMT_REDIS_CONFIG = {
    "host": "你的Redis地址",              # 如 "192.168.1.100"
    "port": 6379,
    "db": 5,
    "password": "你的Redis密码",

    # === 传输选择(默认 redis,生产推荐)===
    # "transport": "redis",              # 不写就是 redis
    # 切 zmq(同机低延迟,实测 p50~0.3ms):装了 pyzmq 后只需这一行。
    #   非 redis 传输会自动开 background_threads;端口按账号派生 127.0.0.1:1556x。
    # "transport": "zmq",
    # 切 mysql(兼容兜底):需装 pymysql+DBUtils,同样自动开 background_threads。
    # "transport": "mysql",
    # "mysql": {"driver":"pymysql","host":"...","port":3306,"user":"root",
    #           "password":"...","database":"bigqmt_rpc","charset":"utf8mb4"},

    "rpc_allow_order_methods": False,    # 下单默认关闭
    "rpc_process_in_listener": True,     # 只读请求在收包线程直接处理(低延迟)
    "rpc_listener_methods": ("*",),      # * = 所有只读方法
    "rpc_background_threads": False,     # redis 用 QMT adjust 线程 drain
    "schedule_adjust": True,
    "schedule_adjust_interval": "500nMilliSecond",
}

重要:切到 zmq 或 mysql 时,必须同时设 "rpc_background_threads": True(这两种传输用自己的后台线程,不走 QMT 回调 drain)。

第 3 步:在 QMT 里运行策略(BIGQMT_REDIS_DRYRUN.py)

入口文件是 src/BIGQMT_REDIS_DRYRUN.py(GBK 编码,QMT 友好)。在 QMT 策略编辑器加载并运行它。

这个文件做什么

它是 QMT 编辑器入口的"外壳"(shell),按顺序做 5 件事:

  1. 定位 python 目录:把 QMT 的 python 目录加到 sys.path,让 bigqmt_signal_trader 包能 import。
  2. reload 模块importlib.reload 刷新 redis_common / redis_rpc / strategy / runtime —— QMT 在编辑器里重跑策略时,进程不退出,reload 确保新代码立即生效。
  3. 注入 Redis 配置:读 bigqmt_signal_trader_local_config.py 里的 BIGQMT_REDIS_CONFIG,调 configure_runtime_redis()
  4. 注入账号:读 BIGQMT_ACCOUNT_ID,调 configure_runtime_account()。如果配置没给,fallback 用 QMT 全局变量 account
  5. 绑定 QMT 原生 API:把 QMT 内置的 passorder / cancel / get_trade_detail_data 函数绑进 runtime(用 try/except NameError 包住,因为这些名字只在大 QMT 进程内存在)。
  6. 导出 QMT 回调init = _runtime.init / handlebar = _runtime.handlebar / adjust = _runtime.adjust 等,让 QMT 能回调到我们的策略逻辑。

⚠️ 硬编码路径(重要)

BIGQMT_REDIS_DRYRUN.py 里有一处写死的 QMT python 目录路径,作为 __file__ 找不到时的 fallback:

def _known_qmt_python_dir():
    root = "".join(chr(value) for value in (0x56fd, 0x91d1, 0x8bc1, 0x5238))   # 国金证券
    suffix = "".join(chr(value) for value in (0x4ea4, 0x6613, 0x7aef))          # 交易端
    return "D:\\" + root + "QMT" + suffix + "\\python"
    # 解码后 = D:\国金证券QMT交易端\python
  • chr() 编码是为了规避 QMT 用 GBK 保存策略文件时中文乱码(用 Unicode 码点拼出"国金证券交易端")。
  • 路径优先级:先用 __file__ 所在目录(脚本实际位置),找不到才用这个硬编码 fallback。
  • 如果你的 QMT 装在别的路径(比如 D:\华泰QMT\python):通常不用改,因为 __file__ 优先。但如果你用 exec 方式加载(__file__ 未定义),需要把 _known_qmt_python_dir() 改成你的路径,或直接硬编码:
    def _known_qmt_python_dir():
        return r"D:\你的券商QMT\python"
    

启动成功标志(QMT 输出面板)

[bigqmt_shell] reload entry paths=['D:\\国金证券QMT交易端\\python']
[bigqmt_shell] local redis config loaded keys=['host', 'port', 'db', ...]
[bigqmt_shell] local account config loaded=True
[bigqmt_rpc] transport=redis mode process_in_listener=True listener_methods=('*',) ...
[bigqmt_rpc] started channel=bigqmt:rpc:req:你的账号
[bigqmt_signal_trader] init ok

为什么是 GBK 编码? QMT 的策略编辑器用本地代码页(中文 Windows 是 GBK)保存文件。文件头 #coding:gbk 声明编码,避免 QMT 保存时破坏 UTF-8 内容。源码本身是 ASCII(中文用 chr() 拼),所以实际不会乱码。

为什么不直接用 bigqmt_signal_trader_redis_rpc_runtime.py 那个文件是纯逻辑入口,不包含 reload 和 QMT API 绑定。BIGQMT_REDIS_DRYRUN.py 是给 QMT 编辑器专用的外壳,处理了 QMT 进程不退出导致模块缓存、API 绑定等坑。在 QMT 里只加载 BIGQMT_REDIS_DRYRUN.py

第 4 步:客户端调用

方式 A:用兼容层(推荐,旧代码零改动)

客户端创建配置文件 bigqmt_signal_trader_client_config.py(与上面类似但用客户端视角),然后:

from bigqmt_signal_trader.xtquant_compat import StockAccount, configure, xt_trader, xtdata

configure()

acc = StockAccount(xt_trader.client.account_id, "STOCK")

# 行情
ticks = xtdata.get_full_tick(["000001.SZ"])
print(ticks["000001.SZ"]["lastPrice"])

# 持仓 / 资金
positions = xt_trader.query_stock_positions(acc)
asset = xt_trader.query_stock_asset(acc)
print(asset.cash, asset.total_asset)

# K线(自动还原成 pandas DataFrame)
klines = xtdata.get_market_data_ex(
    field_list=["close"], stock_list=["000001.SZ"], period="1d", count=5
)

方式 B:直接 RPC 调用

from bigqmt_signal_trader.redis_rpc import call_redis_rpc
import redis

r = redis.Redis(host="192.168.1.100", port=6379, db=5, password="...")
resp = call_redis_rpc(r, "你的账号", "get_full_tick", {"codes": ["000001.SZ"]})
print(resp["data"]["000001.SZ"]["lastPrice"])

方式 C:无缝替换旧 xtquant(最终切换)

把仓库 src 放到 PYTHONPATH 最前面,旧代码的 from xtquant import xtdata 自动命中本仓库 shim:

$env:PYTHONPATH = "D:\gjzqqmt\xtquant_big_convert\src;$env:PYTHONPATH"
# 旧代码完全不改
from xtquant import xtdata
ticks = xtdata.get_full_tick(["600000.SH"])  # 走 RPC 到大 QMT

切换传输层

只需改一个字段

服务端 + 客户端的配置文件里,transport 字段保持一致即可:

BIGQMT_REDIS_CONFIG = {
    "transport": "zmq",                  # redis / zmq / mysql / shm
    "zmq": {"host": "127.0.0.1"},        # 各传输子配置
    # redis 配置保留(zmq 服务发现、mysql 不需要时的 fallback 都用它)
}

各传输配置示例

Redis(默认)

{"transport": "redis"}  # 或省略 transport 字段

ZMQ(同机低延迟,需 pyzmq):

{
    "transport": "zmq",
    "rpc_background_threads": True,        # 必须!
    "zmq": {
        "host": "127.0.0.1",              # 默认端口从 account_id 派生
        # "port": 5560,                   # 可显式指定
        # 端口冲突时自动找空闲端口 + 通过 Redis 服务发现告知客户端
    },
}

MySQL(兼容兜底,需 pymysql + DBUtils):

{
    "transport": "mysql",
    "rpc_background_threads": True,        # 必须!
    "mysql": {
        "driver": "pymysql",
        "host": "192.168.1.100", "port": 3306,
        "user": "root", "password": "...",
        "database": "bigqmt_rpc", "charset": "utf8mb4",
        "poll_interval_seconds": 0.01,
        "pool_config": {"mincached": 1, "maxcached": 3, "maxshared": 0, "maxconnections": 4},
    },
}

ZMQ 端口与服务发现

  • 默认端口从 account_id 派生:15560 + (账号数字 mod 100),不同账号自动不冲突。
  • 端口被占时,server 自动往上扫描找空闲端口,把真实地址写到 Redis key bigqmt:zmq:addr:{account_id}(TTL 300s)。
  • 客户端连接时按优先级解析地址:显式 connect_address > Redis 服务发现 > 默认派生端口。
  • server 退出时自动清理 discovery key。
  • 服务发现是可选的(没配 Redis client 时退化为静态派生端口)。

完整传输层文档见 docs/RPC_TRANSPORTS.md


实测延迟对比(真实直连 QMT)

三种传输全部实测,端到端连接真实 QMT 进程,n=15/方法:

传输 ping p50 get_full_tick p50 成功率 尖峰来源
Redis 13ms 15ms 100% 偶发 245ms(网络抖动)
ZMQ 0.7ms* 0.7ms* 100% 30% 撞 500ms(QMT adjust GIL)
MySQL 104ms 110ms 100% 轮询开销

*ZMQ fast-path(避开 GIL 尖峰的请求);overall p90 ~498ms。

生产推荐 Redis:稳定、跨机、无 GIL 问题、QMT 端零额外依赖。ZMQ 理论最快但受 QMT 主线程 GIL 调度影响。MySQL 仅作兜底。

复现基准:

python bench_latency.py        # Redis 单传输延迟
python bench_transports.py -n 100  # Redis vs ZMQ 对比

目录结构

src/bigqmt_signal_trader/
├── transports/                    可插拔传输层
│   ├── base.py                    RpcTransport 抽象接口
│   ├── redis_transport.py         Redis(默认,rpush/blpop/brpop)
│   ├── zmq_transport.py           ZMQ(ROUTER/DEALER + 服务发现)
│   ├── mysql_transport.py         MySQL(轮询 + DBUtils 连接池)
│   ├── shm_transport.py           共享内存(stub)
│   └── factory.py                 build_transport 工厂
├── adapters/                      QMT API 适配器
│   ├── market_bigqmt.py           行情(ContextInfo 封装)
│   ├── order_bigqmt.py            下单(passorder)
│   ├── position_bigqmt.py         持仓(get_trade_detail_data)
│   └── redis_common.py            Redis 连接/编解码
├── redis_rpc.py                   RPC 服务(handlers + service + transport 集成)
├── xtquant_compat.py              客户端兼容层(xt_trader / xtdata + 异步回调)
├── exec_events.py                 委托/成交/错误事件推送(Redis pubsub)
├── quote_push_channel.py          全推行情推送通道(redis/zmq PUB/SUB)
├── quote_subscription_manager.py  服务端全推订阅管理(引用计数 + 组合键去重)
├── whole_quote_session.py         客户端全推订阅会话(心跳 + 重启恢复)
├── full_tick_cache.py             全市场行情快照缓存(可选降载)
├── strategy.py 之类               策略骨架、风控、价格引擎等
bigqmt_no_redis/                   无 redis 版本(QMT 沙箱拒绝 import redis 时用)
│   ├── zmq_transport.py           自包含 ZMQ transport(内联编码,零 redis 依赖)
│   └── DRYRUN_no_redis.py         无 redis DRYRUN 入口
src/xtquant/                       可选 xtquant import shim
src/bigqmt_signal_trader_strategy.py        策略入口(init/handlebar/adjust + 启动诊断)
src/bigqmt_signal_trader_redis_rpc_runtime.py  Redis RPC runtime 入口
src/BIGQMT_REDIS_DRYRUN.py                  QMT 编辑器加载入口(GBK)
src/BIGQMT_ZMQ_BACKTEST.py                  独立 QMT 回测 ZMQ 入口(GBK)
src/bigqmt_backtest/                        独立历史驱动、模拟撮合、ZMQ 协议与客户端
tests/bigqmt_signal_trader/        单元测试(无 QMT 环境可跑)
tests/bigqmt_backtest/             回测、确定性、隔离和 ZMQ 往返测试
qmt-trader/                        AI 助手 Skill(大模型直接操作 QMT,见下文专节)
│   ├── SKILL.md                   skill 说明书(命令速查 + 工作流 + 安全须知)
│   ├── scripts/qmt.py             统一 CLI(46 子命令 + rpc 兜底)
│   └── references/api_reference.md  完整 API 参考
docs/                              详细文档
test_all_apis.py                   端到端 API 测试(发现生产问题)
bench_latency.py / bench_transports.py  延迟基准脚本

本地测试

python -m pytest tests/bigqmt_signal_trader/ -q

当前覆盖 199 个用例(含传输层往返、Redis RPC、客户端兼容、持仓/行情/下单 handlers、异步回调、执行事件)。

端到端 API 测试(发现生产问题)

test_all_apis.py端到端验证测试——不只测「调用成功」,还测「结果正确」,能发现这些生产问题:

验证项 检测什么 为什么重要
客户端/服务端一致性 ping 超时 → transport 不匹配 Issue #24 根因:客户端 redis / 服务端 zmq 连不上
持仓查询 get_positions 返回空但账户有持仓 容错设计把「失败返回空」当成「正常」
委托查询 query_orders 返回空 strategy_name 不匹配(默认应为 "" 返回全部)
买入/卖出 submit_order 成功但委托没进系统 静默失败(passorder 被 QMT 拒绝但没报错)
server_error 显示 QMT 端拒绝原因 委托被 QMT 静默拒绝时返回具体原因

用法

# 方式 A:用环境变量
$env:BIGQMT_ACCOUNT_ID="你的账号"
$env:BIGQMT_REDIS_HOST="你的Redis地址"
$env:BIGQMT_REDIS_PORT="6379"
$env:BIGQMT_REDIS_DB="5"
$env:BIGQMT_REDIS_PASSWORD="你的密码"
python test_all_apis.py

# 方式 B:用 QMT 端配置(需 bigqmt_signal_trader_local_config.py 在 PYTHONPATH)
$env:PYTHONPATH="D:\国金证券QMT交易端\python;$env:PYTHONPATH"
python test_all_apis.py

示例输出(发现问题时):

--- 端到端验证: 客户端/服务端一致性 ---
客户端配置 transport: redis
❌ ping 失败: redis rpc timeout: ping
   可能原因: 客户端 transport 和服务端不匹配
   - 客户端配置 transport=redis
   - 如果服务端是 zmq, 客户端也要设 transport=zmq

--- 端到端验证: 持仓查询 ---
⚠️  get_positions 返回空 — 账户可能真的没持仓, 或查询失败 (检查 QMT 上下文)

--- 端到端验证: 买入/卖出 ---
✅ submit_order OK
❌ 委托没进系统 — submit_order 成功但 query_orders 找不到
   这是静默失败 (passorder 被 QMT 拒绝但没报错)
   检查: 1) 价格是否超出范围 2) 账户权限 3) QMT 风控

日志与排错(出错去哪看)

系统自带文件日志——所有报错/异常同时写 QMT 输出面板和本地日志文件,重启/崩溃后也能回溯。

日志位置

环境 日志文件
QMT 内(服务端) <QMT python 目录>\logs\bigqmt.log(如 D:\国金证券QMT交易端_lemo\python\logs\bigqmt.log
外部客户端 ~\.cache\bigqmt\logs\bigqmt.log(用户目录下)
  • 按天轮转(午夜),默认保留最近 7 天
  • 每行带时间戳 + 级别 + 模块标签:2026-08-14 21:45:59 [ERROR] [bigqmt.quote_push] publisher start failed: ...

查看方式

# 实时跟踪日志
Get-Content "D:\国金证券QMT交易端\lempython\logs\bigqmt.log" -Wait -Tail 50

# 只看错误
Get-Content "D:\...\python\logs\bigqmt.log" | Select-String "ERROR|WARN"

配置

环境变量 默认 说明
BIGQMT_LOG_ENABLED 1 0 关闭文件日志
BIGQMT_LOG_TO_STDOUT 1 0 不输出到 QMT 面板
BIGQMT_LOG_RETENTION_DAYS 7 日志保留天数

排错首选看日志文件:QMT 面板内容重启/清空后丢失,日志文件保留 7 天,包含启动诊断([bigqmt_diag])、崩溃原因、端口冲突等。


安全默认值

  • rpc_allow_order_methods 默认 False:远程 order_stock / cancel_order 被拒绝。确认接入方、账号、风控后再显式开启。
  • 回测桥接永久 live_ready=false,协议中没有真实账户和实盘下单方法。
  • 配置文件含资金账号和密码,bigqmt_signal_trader_local_config.py / bigqmt_signal_trader_client_config.py 已在 .gitignore不要提交
  • 请求负载经过 base64 + 数字混淆编码(encode_rpc_request_payload),避免 QMT 的 Redis 客户端拦截含股票代码的明文。

AI 助手 Skill:qmt-trader(大模型直接操作 QMT)

仓库内置一个 Agent Skill——qmt-trader/,让支持 SKILL.md 约定的 AI 编程助手(Claude Code / ZCode / Cursor / Codex 等)直接用命令行驱动 QMT 的全部交易与行情能力,无需每次现场写 Python 调用代码。人也可以脱离 AI 手动执行其中的 CLI 脚本。

目录结构

qmt-trader/
├── SKILL.md                        skill 说明书(触发条件 + 命令速查 + 典型工作流 + 安全须知)
├── scripts/qmt.py                  统一 CLI 入口(46 个子命令 + 通用 rpc 兜底,约 1000 行)
└── references/api_reference.md     完整 API 参考(参数/返回值/常量/已知陷阱)

工作原理

  • AI 助手匹配到 SKILL.md 里的 description("查行情 / 查持仓 / 下单 / 龙虎榜 / 北向资金…时触发")后自动加载本 skill;
  • 之后助手调用 python qmt-trader/scripts/qmt.py <子命令> 执行确定性命令,不再临时生成 RPC 调用代码,避免参数写错;
  • 所有命令默认输出 JSON(ok / data / ts 三字段,便于模型解析),加 --table 切换人类可读表格;出错时返回 ok: false + error / detail / code,退出码 1;
  • qmt.py 自动把仓库 src/ 加入 sys.path(开发模式免 pip install),并自动发现 QMT 的 python 目录读取客户端配置。

启用方式

方式 A:安装到 AI 助手的 skills 目录(推荐,全局生效):

# Claude Code
cp -r qmt-trader ~/.claude/skills/qmt-trader
# ZCode / 其他遵循 agents skills 约定的助手
cp -r qmt-trader ~/.agents/skills/qmt-trader

安装后正常提需求即可,例如"帮我看下工商银行最近的走势""我账户现在什么持仓",助手会自动触发。

方式 B:不安装,对话里显式指定

阅读 qmt-trader/SKILL.md,之后用里面的 qmt.py 命令帮我查行情 / 持仓 / 下单。

方式 C:纯手动(不经过 AI,人直接当 CLI 用):

python qmt-trader/scripts/qmt.py ping
python qmt-trader/scripts/qmt.py snapshot --table

前置条件

与「快速开始」的客户端一致:

  1. QMT 端 RPC 服务已启动(BIGQMT_REDIS_DRYRUN.py 运行中,输出面板/日志看到启动诊断 OK);
  2. 客户端配置就绪——环境变量(BIGQMT_ACCOUNT_ID / BIGQMT_REDIS_HOST / BIGQMT_REDIS_PORT / BIGQMT_REDIS_DB / BIGQMT_REDIS_PASSWORD)或配置文件;
  3. ping 确认连通:redis 约 13ms / zmq 约 0.7ms 为正常,超时说明 transport 或配置不匹配。

一分钟上手

# 0. 连通性检测(含延迟测量)
python qmt-trader/scripts/qmt.py ping

# 1. 账户全景:资产 + 持仓 + 委托 + 成交(一次往返)
python qmt-trader/scripts/qmt.py snapshot

# 2. 实时五档盘口(含涨跌幅)
python qmt-trader/scripts/qmt.py tick 600000.SH

# 3. 前复权日 K 60 根(含 MA5/20/60 统计)
python qmt-trader/scripts/qmt.py kline 600000.SH --period 1d --count 60 --dividend front

# 4. 干跑下单(只打印不提交,确认参数)
python qmt-trader/scripts/qmt.py buy 600000.SH 100 --price 7.50 --dry-run

命令概览

分类 命令
连通/全景 ping / snapshot
账户 account(资产)/ positions(持仓含浮动盈亏)/ orders(委托含语义化状态)/ trades(成交)
行情 tick / kline / instrument / sector / trading-dates / north(北向)/ longhubang(龙虎榜)/ financial(财务)/ download(历史数据下载)/ quote-subscribe(全推订阅)
扩展查询(25 个快捷命令) holiday / stock-name / instrument-type / divid-factors / market-times / trading-calendar / option-list / bsm-price / bsm-iv / hkt-stats / hkt-details / hkt-rate / top10-holder / holder-num / ipo / ipo-limit / credit-assure / credit-short / credit-debt / his-st / index-weight / industry / sector-info / local-data / timetag2dt / dt2timetag
交易 buy / sell / cancel(均支持 --dry-run,buy/sell 支持 --latest / --strategy / --remark
通用兜底 rpc <method> [json] — 调用白名单内任意方法(如 rpc get_l2_quote '{"stock_code":"600000.SH"}'),未列出的方法都能这样调

安全设计

  • 下单三命令(buy / sell / cancel)受服务端白名单控制,rpc_allow_order_methods 默认 False,未显式开启时返回 ORDER_DISABLED
  • 下单前先用 tick 看价 + --dry-run 确认参数;
  • ORDER_TIMEOUT不要直接重试,先 orders 查询确认委托是否已进系统,避免重复下单;
  • 下单的 --strategy 与查询的 --strategy 需一致;查全部委托用 orders --strategy ""(空 = 不过滤)。

完整命令表、四个典型工作流(行情分析 / 持仓监控 / 下单交易 / 批量分析)和 API 参数细节见 qmt-trader/SKILL.mdqmt-trader/references/api_reference.md


相关文档


为什么不直接连大 QMT

官方 xtquant.xttrader.XtQuantTrader 依赖客户端侧 XtQuantServer 通道。当前国金大 QMT 环境中直接连 connect() 返回 -1交易能力因此必须放在大 QMT 内部策略进程里,外部通过 RPC 驱动。

但只读行情不必走 RPC。 58600 是 FormulaServer,它同时就是行情/参考数据服务——QMT 自带 Python 里的 qmt_api 包(bin.x64/Lib/site-packages/qmt_api)正是它的客户端。本仓库已接入这条直连快速路径,见上文「FormulaServer 直连快速路径」。

如果后续券商开通 XtQuantServer 权限且 connect()==0,可再加交易直连模式。

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xtquant_big_convert-0.2.0.tar.gz (209.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xtquant_big_convert-0.2.0-py3-none-any.whl (196.4 kB view details)

Uploaded Python 3

File details

Details for the file xtquant_big_convert-0.2.0.tar.gz.

File metadata

  • Download URL: xtquant_big_convert-0.2.0.tar.gz
  • Upload date:
  • Size: 209.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for xtquant_big_convert-0.2.0.tar.gz
Algorithm Hash digest
SHA256 e2800cef16fdc6aefb2190c9d5c887b45590440aa83b9aa4be376168366c858a
MD5 4bf7dea46379df4e0277149114abe55e
BLAKE2b-256 635096b70f1954a88599a4d7f9852eabb4193449701b232b41c80bfbc0fe1d1e

See more details on using hashes here.

File details

Details for the file xtquant_big_convert-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for xtquant_big_convert-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 df18a4a60702b6df236402a5e15f4cdc474ccedb809f2c34e7cd0c14e99bdd10
MD5 bb749a9ff4131f68e79b6a338ac50fff
BLAKE2b-256 4d5fcc800d578a7601aeee3be4df7452fa594c68b774bb92fdcd6632e6e88045

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page