问题描述
原来请求一次在几十毫秒,现在需要 2 秒,大家有没有遇到过
解决方案
在 QMT(券商极速交易平台)中,遇到 get_stock_list_in_sector 接口突然变慢(从几十毫秒增加到 2 秒左右)是部分量化开发者会遇到的常见问题。这通常与数据同步、调用频率、或者本地缓存机制有关。
以下是导致该接口变慢的常见原因及相应的优化解决方案:
一、 为什么接口会突然变慢?
- 频繁在
handlebar中调用:handlebar是逐 K 线或逐 Tick 驱动的。如果在handlebar中每次都调用get_stock_list_in_sector,会导致极高的 I/O 或内存读取开销,尤其是在 Tick 级别下,会严重拖慢策略运行速度。 - 本地板块数据正在同步或损坏:QMT 的板块数据依赖于本地客户端的【数据管理】。如果后台正在更新板块数据,或者本地的板块文件过大/存在异常,读取速度会显著下降。
- 参数
realtime的影响:如果未传入realtime或传入了最新的时间戳,系统可能会尝试向服务器校验最新成分股,从而引发网络延迟(通常在 1-2 秒)。
二、 解决方案与代码优化
1. 核心优化:在 init 中缓存数据(强烈推荐)
板块成分股在盘中通常是不会频繁变动的。因此,绝对不要在 handlebar 中每次都去获取板块成分股。正确的做法是在 init 初始化函数中获取一次,并将其存入 ContextInfo 的全局变量中。
优化前(错误示范 - 导致极度卡顿):
def handlebar(ContextInfo):
# 每次 tick/bar 都去请求,极度消耗性能!
sector_stocks = ContextInfo.get_stock_list_in_sector('沪深300')
# ... 策略逻辑
优化后(正确示范 - 毫秒级响应):
def init(ContextInfo):
# 1. 在 init 中获取一次并缓存
ContextInfo.my_sector_stocks = ContextInfo.get_stock_list_in_sector('沪深300')
print(f"成功加载板块成分股,共 {len(ContextInfo.my_sector_stocks)} 只")
def handlebar(ContextInfo):
# 2. 在 handlebar 中直接使用缓存的列表,耗时几乎为 0
stocks = ContextInfo.my_sector_stocks
# ... 策略逻辑
2. 盘中定时更新(如果必须获取最新成分股)
如果你确实需要在盘中更新板块(例如自定义板块在盘中被外部程序修改了),可以使用 QMT 的定时器 run_time 功能,每隔一段时间(如 5 分钟)更新一次,而不是每个 Tick 都更新。
def init(ContextInfo):
# 初始化时获取一次
ContextInfo.my_sector_stocks = ContextInfo.get_stock_list_in_sector('我的自选')
# 设置定时器,每 5 分钟更新一次板块数据
ContextInfo.run_time("update_sector", "5nMinute", "2020-01-01 09:30:00", "SH")
def update_sector(ContextInfo):
# 定时回调函数中更新缓存
ContextInfo.my_sector_stocks = ContextInfo.get_stock_list_in_sector('我的自选')
print("板块数据已定时更新")
def handlebar(ContextInfo):
# 依然直接使用缓存
stocks = ContextInfo.my_sector_stocks
3. 检查客户端数据管理
如果即使在 init 中调用也需要 2 秒,建议进行以下排查:
- 打开 QMT 客户端,进入 【数据管理】 -> 【补充数据】,手动重新下载一次相关的板块数据和基础财务数据。
- 重启 QMT 客户端。有时候客户端长时间运行,内存碎片或后台线程卡死会导致 API 响应变慢,重启通常能解决 80% 的底层卡顿问题。
总结
量化策略编写的一个重要原则是:将静态数据或低频变动数据(如股票池、板块成分股、财务数据)放在 init 中预加载,handlebar 中只处理高频的行情(Tick/Bar)和交易逻辑。 按照上述缓存方法修改代码后,你的策略运行速度将恢复到正常的毫秒级别。