问题描述
国金 qmt 交易端版本:2.0.8.300]
券商:国金证券
运行环境:实盘交易模式(非模拟)
周期:1 分钟周期 K 线驱动 handlebar
复现步骤: 在 handlebar 中调用:
kline = C.get_market_data_ex(['close'], [stock_code], period='1d', count=3)
9:15 时调用全市场批量查询(10000 只 × 1d × count=3)正常返回。但盘中 10:30 / 14:45 / 14:59 时调用单只持仓股(1-5 只 × 1d × count=3)时,约 10 秒后日志显示:
[WARN] PythonCacheData::gmdSubscribe timeout, stockCode:., period:86400000
然后 handlebar 被强制中断,后续代码不再执行(含异常都没抛出)。
环境排查:
网络:ping 国金行情服务器(139.224.114.71、81.69.152.51)全天 0 丢包
已尝试 WiFi 和 USB 有线网卡,问题相同
疑问:
get_market_data_ex 单股日线查询是否需要先 subscribe?
有什么替代方法可以在 handlebar 中查询单股近 3 日收盘价?
是否有相关参数或调用模式可以避免触发 gmdSubscribe?
谢谢!
解决方案
针对您在国金 QMT 实盘中遇到的 gmdSubscribe timeout 问题,以下是详细的原因分析及解决方案:
问题原因分析
在 QMT 的 Python API 中,get_market_data_ex 函数包含一个默认参数 subscribe=True。当您在盘中(如 10:30、14:45 等)调用该函数时,如果本地没有最新的数据,底层 C++ 引擎会向行情服务器发起实时订阅请求(即 gmdSubscribe)。
盘中特定时段(尤其是临近收盘的 14:45-15:00)行情服务器并发请求量极大,如果服务器响应稍慢,就会触发底层的 10 秒超时机制。由于这是底层 C++ 抛出的超时,Python 层无法捕获异常,从而导致 handlebar 被强制中断。
疑问解答与解决方案
1. 是否需要先 subscribe?
不需要。get_market_data_ex 默认自带订阅行为(subscribe=True)。正是这个默认的订阅行为在盘中引发了超时。
2. 如何避免触发 gmdSubscribe?(核心解决方案)
要避免触发 gmdSubscribe,您只需要在调用 get_market_data_ex 时,显式地将 subscribe 参数设置为 False。这样函数将只读取本地已有的数据,不会向服务器发起网络请求,从而彻底杜绝超时问题。
修改后的代码:
kline = ContextInfo.get_market_data_ex(
['close'],
[stock_code],
period='1d',
count=3,
subscribe=False # 关键参数:关闭实时订阅,仅读取本地数据
)
注:使用此方法的前提是,您在盘前(如 9:15)已经通过全市场查询或数据下载功能,将日线数据缓存到了本地。
3. 有什么替代方法可以查询单股近 3 日收盘价?
除了关闭 subscribe 参数外,您还可以使用以下两种更轻量级的替代方法:
替代方法一:使用 get_history_data(推荐用于简单指标计算)
如果您只需要获取股票池内股票的历史数据,可以在 init 中设置股票池,然后在 handlebar 中直接获取。此函数直接读取本地内存数据,速度极快且不会超时。
def init(ContextInfo):
# 假设 stock_code 是您要查询的股票
ContextInfo.set_universe([stock_code])
def handlebar(ContextInfo):
# 获取股票池中所有股票最近3日的收盘价
his_dict = ContextInfo.get_history_data(3, '1d', 'close')
if stock_code in his_dict and len(his_dict[stock_code]) >= 3:
close_prices = his_dict[stock_code]
print(f"近3日收盘价: {close_prices}")
替代方法二:使用 get_local_data
直接读取本地硬盘/内存中的行情数据,不涉及任何网络请求。
def handlebar(ContextInfo):
# 获取本地最新的3条日线数据
local_data = ContextInfo.get_local_data(
stock_code=stock_code,
period='1d',
count=3
)
# local_data 返回的是 dict 结构,需自行解析 close 字段
总结建议
对于实盘高频驱动的 handlebar(如 1 分钟或 tick 级别),强烈建议不要在其中发起任何带有网络请求的同步阻塞调用。请将 get_market_data_ex 的 subscribe 设为 False,或者改用 get_history_data,以确保策略运行的稳定性和流畅性。