问题描述
使用 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}")
总结建议
- 回测场景:优先使用
ContextInfo.get_history_data(),或者在使用get_market_data_ex时务必加上subscribe=False。 - 实盘/模拟场景:可以使用
get_market_data_ex并保持subscribe=True,以确保能获取到最新的推送数据。 - 数据准备:确保在回测前,已经在 QMT 终端的“数据管理”中完整下载了对应品种和周期的历史数据。