🚀 AI 一键生成 qmt 策略代码

QMT回测时 get_market_data_ex 获取分钟数据包含未来时间怎么办?

qmt | 发布时间: 2026/5/21
以下内容由 EasyQuant 生成。

问题描述

【求助】get_market_data_ex 获取分钟数据有未来时间

使用 get_market_data_ex 获取分钟数据,回测的时候总是会出现未来时间,从而导致获取的价格都是重复的值,从下面的日志可以看到当前的时间是“20260202090500”,但是取出来的收盘价序列除了最后一个值,之前都是未来日期,根据之前论坛前辈的建议 get_market_data_ex 的 end_time 也指定了当前时间,init 里面也下载了历史数据,但是这个问题始终存在,希望知道的可以解答下这个问题,谢谢

代码分割线============================================

#coding:gbk

import numpy as np

def init(ContextInfo):
ContextInfo.trade_pair=['rb00.SF']
ContextInfo.position_tag = {'long':False,'short':False} #初始化持仓状态
ContextInfo.set_universe(ContextInfo.trade_pair) # 设置标的期货合约对应股票池
ContextInfo.accid = 'test12345678'

添加周期类型和周期参数
ContextInfo.timeFrame = '5m' # 分钟线,可根据需要修改为 '1d'、'1m'、'5m'等

def after_init(ContextInfo):

不确定有没有本地数据的话,下一次本地数据
if 1:

print("正在下载rb00.SF数据")
download_history_data("rb00.SF", ContextInfo.timeFrame,"","",)
print("数据下载完成,程序继续")

def handlebar(ContextInfo):

backTestTime = timetag_to_datetime(ContextInfo.get_bar_timetag(ContextInfo.barpos),"%Y%m%d%H%M%S")
print('print backtesttime')
print(backTestTime)

# 使用get_market_data_ex获取收盘价时间序列
closes = ContextInfo.get_market_data_ex(
fields=['close'],
stock_code=ContextInfo.trade_pair,
period=ContextInfo.timeFrame,
count=20,
end_time = backTestTime
)
print('print cloese')
print(closes)

日志分割线==========================================

解决方案

这个问题在 QMT(迅投)平台的回测中比较常见。导致获取到“未来时间”或重复值的主要原因在于 get_market_data_ex 函数的默认订阅机制。

问题原因分析

ContextInfo.get_market_data_ex 函数中,有一个默认参数 subscribe=True(订阅数据开关)。在回测模式下,如果保持默认的 subscribe=True,系统可能会尝试去拉取最新的实时行情数据,或者在数据对齐时发生偏移,从而导致你获取到了相对于回测当前时间(barpos)而言的“未来数据”。

解决方法

方法一:关闭数据订阅(推荐)

在回测时,我们只需要读取本地已经下载好的历史数据,不需要订阅实时行情。因此,只需要在调用 get_market_data_ex 时,显式地将 subscribe 参数设置为 False 即可。

修改后的代码如下:

def handlebar(ContextInfo):
    backTestTime = timetag_to_datetime(ContextInfo.get_bar_timetag(ContextInfo.barpos), "%Y%m%d%H%M%S")
    print('print backtesttime:', backTestTime)

    # 增加 subscribe=False 参数,强制只读取本地历史数据
    closes = ContextInfo.get_market_data_ex(
        fields=['close'], 
        stock_code=ContextInfo.trade_pair, 
        period=ContextInfo.timeFrame, 
        count=20,
        end_time=backTestTime,
        subscribe=False  # 关键修改点
    )
    print('print closes:')
    print(closes)

方法二:使用 get_history_data(回测更稳定)

根据 QMT 官方 API 文档,get_market_data_ex 更适合用于复杂的行情获取和实盘/模拟盘中的数据订阅。如果在回测中仅仅是为了获取当前 K 线往前推 N 根 K 线的历史数据,使用 ContextInfo.get_history_data() 是最稳妥且效率最高的方式,它天然契合回测的 K 线推进机制,绝对不会取到未来数据。

替代代码示例:

def handlebar(ContextInfo):
    # 获取股票池中所有股票最近20根K线的收盘价
    # 返回的是一个 dict,key 为合约代码,value 为价格 list
    his_dict = ContextInfo.get_history_data(20, ContextInfo.timeFrame, 'close')
    
    for code in ContextInfo.trade_pair:
        if code in his_dict:
            closes = his_dict[code]
            print(f"{code} 的收盘价序列: {closes}")

总结建议

  1. 回测场景:优先使用 ContextInfo.get_history_data(),或者在使用 get_market_data_ex 时务必加上 subscribe=False
  2. 实盘/模拟场景:可以使用 get_market_data_ex 并保持 subscribe=True,以确保能获取到最新的推送数据。
  3. 数据准备:确保在回测前,已经在 QMT 终端的“数据管理”中完整下载了对应品种和周期的历史数据。