3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 QMT(Quant Trader)平台中,策略回测速度慢通常由平台参数设置不当或代码逻辑效率低下导致。QMT 的运行机制是逐 K 线(Bar-by-Bar)驱动 handlebar 函数,如果该函数内部包含大量重复计算或 I/O 操作,回测效率会显著下降。
以下是针对 QMT 平台的具体提速方案,分为设置优化和代码优化两部分。
在 QMT 策略编辑器的界面右侧或“基本信息”中,有几个关键参数直接影响速度:
开启“快速计算” (Quick Calculation)
100 或 200)。这样平台只会计算最后 N 根 K 线,极大缩短初始化时间。调整“刷新间隔”
减少回测对象和周期
ContextInfo.set_universe() 中的股票数量越多,循环次数越多,速度越慢。调试时建议只用几只代表性股票。QMT 的 handlebar(ContextInfo) 函数会在每一根 K 线(或 Tick)到来时被调用一次。如果在 handlebar 里写了低效代码,回测时间会呈指数级增长。
handlebar 中重复获取全量历史数据错误做法:在每一根 K 线通过 get_market_data 获取过去几年的所有数据。
优化做法:只获取计算指标所需的最小窗口数据。
# --- 低效代码 ---
def handlebar(ContextInfo):
# 每次都取了全量历史数据,极慢
data = ContextInfo.get_market_data(['close'], stock_code=['000001.SZ'], count=-1)
# --- 高效代码 ---
def handlebar(ContextInfo):
# 只取计算 MA60 所需的最近 60 根 K 线
data = ContextInfo.get_market_data_ex(['close'], ['000001.SZ'], period='1d', count=60)
print 输出 (I/O 瓶颈)原理:控制台输出(I/O 操作)是非常耗时的。如果在 handlebar 中每根 K 线都 print 数据,回测速度会降低 10 倍以上。
优化:
print。def handlebar(ContextInfo):
# print(ContextInfo.barpos) # <--- 务必注释掉这行
if condition_buy:
# 仅在交易时打印
print(f"Buy at {ContextInfo.barpos}")
passorder(...)
QMT 集成了 pandas 和 numpy。尽量使用这些库的整列计算功能,而不是用 for 循环遍历价格列表。
init原理:init(ContextInfo) 只在策略启动时运行一次。
优化:如果有些数据(如股票池的基本面数据、行业分类、固定的参数配置)在回测期间不会变,务必放在 init 中,不要放在 handlebar 里。
def init(ContextInfo):
# 在初始化中设定好股票池,不要在 handlebar 里反复 set
ContextInfo.set_universe(['000001.SZ', '600000.SH'])
# 预加载一些静态数据
ContextInfo.my_static_data = { ... }
def handlebar(ContextInfo):
# 直接使用
data = ContextInfo.my_static_data
get_market_data_ex 替代 get_market_data根据文档,get_market_data 已不建议使用,建议使用 get_market_data_ex。新接口在处理多股数据结构时通常更高效,且返回的是标准的 Pandas DataFrame/Dict 结构,便于直接进行向量化运算。
如果你的策略是日线级别,但运行在分钟周期上(例如为了更精细的撮合),可以使用 ContextInfo.run_time 定时器,让核心逻辑只在特定时间(如收盘前)运行,而不是每分钟都跑一遍逻辑。
def init(ContextInfo):
# 设定每天 14:55:00 运行一次 my_strategy_logic
ContextInfo.run_time("my_strategy_logic", "1nDay", "2019-10-14 14:55:00", "SH")
def my_strategy_logic(ContextInfo):
# 这里写核心交易逻辑
print("Running daily logic...")
def handlebar(ContextInfo):
# handlebar 留空或仅处理极简逻辑
pass
如果回测依然慢,请按以下顺序检查:
handlebar 里打印了大量日志?(最常见原因)handlebar 里使用了 count=-1 获取全量历史数据?for 循环遍历股票池和 K 线?paint 函数?(大量绘图也会占用资源)Q: 为什么我的策略在实盘运行很快,回测却很慢?
A: 实盘通常是“当前帧”触发,只处理最新的 Tick 或 K 线。而回测需要从历史开始,模拟成千上万次 handlebar 的调用。如果在 handlebar 中写了全量数据获取(如获取过去5年的数据),实盘只跑一次没感觉,回测跑几千次就会极慢。
Q: ContextInfo.get_market_data_ex 和 get_market_data 哪个更快?
A: 推荐使用 get_market_data_ex。它是新版接口,针对数据结构进行了优化,且更符合 Pandas 的使用习惯,能更好地配合向量化计算来提升速度。
Q: 如何在不降低回测精度的情况下减少计算量?
A: 使用“缓存”思想。例如计算 MA10,不需要每次取 10 个数计算。可以维护一个全局变量,新来一个价格,减去最早的一个,加上最新的一个(增量计算),或者利用 Pandas 的 rolling 函数在获取数据后一次性计算好,而不是在循环中计算。
Q: QMT 支持多进程或多线程回测吗?
A: QMT 的 Python 策略主要运行在单线程环境中。虽然 Python 支持多线程,但受限于 GIL 和 QMT 底层 C++ 的交互机制,直接在策略中开多线程可能会导致数据竞争或报错。建议通过优化算法复杂度来提速。