10 KiB
10 KiB
MiniQMT 无损替换兼容层
更新时间:2026-07-01
目标
把原来依赖 MiniQMT 的调用:
from xtquant.xttrader import XtQuantTrader
from xtquant.xttype import StockAccount
from xtquant import xtdata, xtconstant
替换为“大 QMT 策略进程 + Redis RPC”的远程调用,同时尽量保持业务代码继续使用:
xt_trader.query_stock_positions(acc)
xt_trader.query_stock_asset(acc)
xt_trader.query_stock_orders(acc)
xt_trader.query_stock_trades(acc)
xt_trader.order_stock(...)
xt_trader.order_stock_async(...)
xt_trader.cancel_order_stock_sysid(...)
xtdata.get_full_tick(...)
接入方式一:显式导入新包
适合先灰度,不影响机器上的真实 xtquant 包。
from bigqmt_signal_trader.xtquant_compat import (
StockAccount,
configure,
xt_trader,
xtdata,
)
from bigqmt_signal_trader import xtquant_compat as xtconstant
configure()
acc = StockAccount(xt_trader.client.account_id, "STOCK")
positions = xt_trader.query_stock_positions(acc)
ticks = xtdata.get_full_tick(["600000.SH"])
这类写法的优点是替换范围小,适合先在 core/trader.py 或独立测试脚本里验证查询链路。configure() 会原地更新已导入的 xt_trader / xtdata 对象,所以可以先 from ... import xt_trader,再调用 configure()。
接入方式二:用 xtquant shim 替换老 import
适合最终切换。把本仓库的 src 放到 PYTHONPATH 最前面后,老代码里的:
from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
from xtquant.xttype import StockAccount
from xtquant import xtdata, xtconstant
会命中本仓库提供的 src/xtquant/ shim。这样主业务代码基本不用改,只需要在本地私有配置文件里设置 Redis 和账号:
# D:\gjzqqmt\xtquant_big_convert\src\bigqmt_signal_trader_client_config.py
BIGQMT_ACCOUNT_ID = "YOUR_ACCOUNT_ID"
BIGQMT_RPC_TIMEOUT_SECONDS = 6.0
BIGQMT_REDIS_CONFIG = {
"host": "YOUR_REDIS_HOST",
"port": 6379,
"db": 5,
"username": "",
"password": "******",
}
BIGQMT_FULL_TICK_CACHE_CONFIG = {
"enabled": False,
"demand_ttl_seconds": 10,
"cache_ttl_seconds": 10,
"wait_seconds": 3.5,
}
然后启动前只需要确认本仓库的 src 在 PYTHONPATH 最前面:
$env:PYTHONPATH = "D:\gjzqqmt\xtquant_big_convert\src;$env:PYTHONPATH"
如果同一台机器仍然安装了真实 MiniQMT 的 xtquant 包,要确认 D:\gjzqqmt\xtquant_big_convert\src 位于 PYTHONPATH 最前面,否则 Python 会先加载真实 xtquant。
推荐落地步骤
- 大 QMT 侧先运行
BIGQMT_REDIS_DRYRUN/bigqmt_signal_trader_redis_rpc_runtime.py,保持rpc_allow_order_methods=False。 - 原策略侧用显式导入方式跑查询自检:资产、持仓、单票五档行情、
["SH","SZ"]全市场行情。 - 查询链路稳定后,把原项目中
core/trader.py的初始化切到兼容层,但仍保持远程下单关闭。 - 对比 MiniQMT 与大 QMT 返回的资产、持仓、委托、成交字段,确认业务字段都能读到。
- 只在确认风控、账号、委托价型都正确后,在大 QMT 私有配置里打开
rpc_allow_order_methods=True。 - 最终切换时再使用
xtquantshim,让旧 import 保持不变。
当前已兼容的方法
| MiniQMT 调用 | 兼容状态 | 说明 |
|---|---|---|
XtQuantTrader(path, session_id) |
已兼容 | 构造本地 RPC 客户端,不连接 MiniQMT |
register_callback() |
已兼容 | 保存 callback;RPC 暂不推送回调 |
start() / connect() / subscribe() |
已兼容 | 返回 0,subscribe() 会补账号 |
query_stock_asset(acc) |
已兼容 | 返回对象含 cash、available_cash、total_asset、market_value |
query_stock_positions(acc) |
已兼容 | 返回对象列表,含 stock_code、volume、can_use_volume、avg_price、price |
query_stock_position(acc, code) |
已兼容 | 返回单只持仓对象或 None |
query_stock_orders(acc, cancelable_only=False) |
已兼容 | 返回对象列表,含 order_type、order_status、order_volume、traded_volume、order_sysid |
query_stock_trades(acc) |
已兼容 | 返回对象列表,含 order_type、traded_volume、traded_price |
order_stock() / order_stock_async() |
已兼容 | 需要大 QMT 本地配置打开 rpc_allow_order_methods=True |
cancel_order_stock_sysid() |
已兼容 | 需要大 QMT 本地配置打开 rpc_allow_order_methods=True |
xtdata.get_full_tick(codes) |
已兼容 | 默认直接 RPC 调用;支持单票、ETF、["SH", "SZ"] 全市场;可选打开 Redis 快照缓存 |
xtdata.get_instrument_detail(code) |
已兼容 | 映射到大 QMT get_instrumentdetail() |
xtdata.get_instrument_type(code) |
已接入 | 优先调大 QMT;不支持时按代码前缀做基础判断 |
xtdata.subscribe_quote(...) / subscribe_whole_quote(...) |
Redis 订阅兼容 | 写入 bigqmt:quote_subscriptions:{account_id},并向 bigqmt:quote_events:{account_id} 发事件;callback 会收到一次当前快照/历史数据 |
xtdata.unsubscribe_quote(seq) |
Redis 事件兼容 | 不强依赖大 QMT 反订阅 API,直接删除 Redis 订阅表并推送 unsubscribe_quote 事件 |
xtdata.get_market_data(...) |
已接入 RPC | 透传到大 QMT ContextInfo.get_market_data,返回 DataFrame/字典结构会自动 JSON 化再还原 |
xtdata.get_market_data_ex(...) |
已接入 RPC | 大 QMT 不支持 get_market_data_ex 时回退到 get_market_data |
xtdata.get_local_data(...) |
已接入 RPC | 大 QMT 不支持 get_local_data 时回退到 get_market_data |
xtdata.get_stock_list_in_sector(...) |
已接入 RPC | 优先调大 QMT;失败时对 "沪深A股" 用 get_full_tick(["SH","SZ"]) 过滤 |
xtdata.get_sector_list() / get_sector_info() |
已接入 RPC | 依赖大 QMT ContextInfo 是否支持 |
xtdata.get_divid_factors(...) |
已接入 RPC | 依赖大 QMT ContextInfo 是否支持 |
xtdata.download_history_data(...) / download_history_data2(...) |
已接入 RPC | 依赖大 QMT ContextInfo 是否支持 |
xtdata.get_trading_dates(...) / get_holidays() / download_holiday_data() |
已接入 RPC | 依赖大 QMT ContextInfo 是否支持 |
xtdata.get_ipo_info(...) |
已接入 RPC | 行情侧新股资料;交易侧 query_ipo_data() 仍是占位 |
xtdata.get_etf_info() / download_etf_info() |
已接入 RPC | 依赖大 QMT ContextInfo 是否支持 |
xtdata.get_option_list(...) / 历史期权列表 |
已接入 RPC | 依赖大 QMT ContextInfo 是否支持 |
xtdata.get_financial_data(...) / download_financial_data(...) |
已接入 RPC | 支持 DataFrame 返回值序列化 |
xtdata.call_formula(...) / subscribe_formula(...) / unsubscribe_formula(...) / get_formula_result(...) |
已接入 RPC | 对应截图里的模型调用/订阅能力,依赖大 QMT ContextInfo 是否支持 |
xtdata.gen_factor_index(...) |
已接入 RPC | 对应生成因子数据,依赖大 QMT ContextInfo 是否支持 |
query_ipo_data() / query_new_purchase_limit() |
占位兼容 | 当前返回空结果,打新需要后续补大 QMT 等价能力 |
下单开关
大 QMT 本地配置默认关闭远程下单。要真正替换 MiniQMT 下单,需要在 QMT 本地私有配置中显式开启:
BIGQMT_REDIS_CONFIG = {
"host": "YOUR_REDIS_HOST",
"port": 6379,
"db": 5,
"username": "",
"password": "******",
"rpc_allow_order_methods": True,
}
开启后,price_type 会从客户端透传到大 QMT passorder(),不会再固定成默认限价。
最小自检脚本
这个脚本只读,不会下单:
from bigqmt_signal_trader.xtquant_compat import StockAccount, configure, xt_trader, xtdata
configure()
acc = StockAccount(xt_trader.client.account_id, "STOCK")
asset = xt_trader.query_stock_asset(acc)
positions = xt_trader.query_stock_positions(acc)
tick = xtdata.get_full_tick(["600000.SH"])
all_a = xtdata.get_stock_list_in_sector("沪深A股")
print("cash:", asset.cash)
print("total_asset:", asset.total_asset)
print("positions:", len(positions), positions[:3])
print("bid5:", tick["600000.SH"]["bidPrice"])
print("ask5:", tick["600000.SH"]["askPrice"])
print("hs_a_count:", len(all_a))
如果想验证最终 shim 方式:
from xtquant.xttrader import XtQuantTrader
from xtquant.xttype import StockAccount
from xtquant import xtdata, xtconstant
trader = XtQuantTrader("", 12345)
acc = StockAccount(trader.client.account_id, "STOCK")
assert trader.connect() == 0
assert trader.subscribe(acc) == 0
print(xtconstant.STOCK_BUY)
print(trader.query_stock_asset(acc))
print(xtdata.get_full_tick(["600000.SH"]))
验证命令
cd D:\gjzqqmt\xtquant_big_convert
python -B -m unittest discover -s tests\bigqmt_signal_trader
实盘前建议先只跑查询链路:
from bigqmt_signal_trader.xtquant_compat import StockAccount, configure, xt_trader, xtdata
configure()
acc = StockAccount(xt_trader.client.account_id)
print(xt_trader.query_stock_asset(acc))
print(xt_trader.query_stock_positions(acc)[:3])
print(xtdata.get_full_tick(["600000.SH"]))
注意事项
subscribe_quote()/subscribe_whole_quote()当前通过 Redis 记录订阅意图,并给 callback 推一次当前数据;持续行情推送需要独立的 Redis 行情生产者消费bigqmt:quote_subscriptions:{account_id}。get_full_tick()默认直接 RPC 现拉;如果全市场 payload 过大,再在客户端和 QMT 本地配置里打开 Redis 快照缓存。unsubscribe_quote(seq)当前按你的要求直接写 Redis:删除订阅表并推送unsubscribe_quote事件,不等待大 QMT 确认。get_stock_list_in_sector("沪深A股")的本地兜底会通过get_full_tick(["SH", "SZ"])过滤 A 股,速度取决于大 QMT 全市场快照返回耗时。- 历史行情、财务、ETF、期权、模型/因子等接口已经接到 RPC,但实际是否可用取决于大 QMT 策略环境里的
ContextInfo是否暴露同名方法。 query_ipo_data()/query_new_purchase_limit()当前返回空结果,打新逻辑不能直接视为无损替换。- RPC 下单默认关闭;打开前必须确认大 QMT 页面正在运行正确账号的 RPC 策略。