问题描述
get_history_data与get_market_data_ex计算出来的均线回测结果差距很大是什么原因?
解决方案
在 QMT 平台中,使用 get_history_data 和 get_market_data_ex 计算均线(MA)等技术指标时,如果发现回测结果差距很大,最核心的原因通常是:两个函数默认的复权方式(dividend_type)不同。
以下是详细的原因分析及解决方案:
1. 默认复权方式不同(核心原因)
股票在发生分红、送股等除权除息事件后,价格会出现跳空。如果不进行复权处理,直接计算均线会导致指标严重失真。
get_history_data的默认复权方式是不复权:
根据 QMT API 文档,get_history_data的dividend_type参数默认值为0(不复权)。get_market_data_ex的默认复权方式是跟随主图:
get_market_data_ex的dividend_type参数默认值为'follow'(跟随当前主图复权方式)。在进行策略回测时,我们通常会在策略基本信息中将主图设置为“前复权”。
结果差异:如果你在代码中没有显式指定复权参数,get_history_data 取到的是不复权数据,而 get_market_data_ex 取到的是前复权数据。用这两组不同的价格序列计算出来的均线自然会产生巨大的差异,进而导致买卖信号和回测收益完全不同。
2. 停牌数据的填充处理差异
get_history_data:参数skip_paused默认为True,即遇到停牌日会自动用停牌前最后一个交易日的价格进行填充。get_market_data_ex:参数fill_data默认为True,但文档中特别标注了“暂不可用”。这可能导致在某些特定停牌场景下,两者返回的 K 线序列长度或数据对齐方式存在细微差别。
3. 数据获取的基准点不同
get_history_data:是基于当前运行到的 K 线(ContextInfo.barpos)往前取len根 K 线的数据。它严格依赖于当前主图的进度。get_market_data_ex:可以通过start_time和end_time灵活指定时间段,或者通过count往前取值。如果时间参数设置不当,可能导致取到的数据区间与预期不符。
💡 解决方案:显式指定相同的复权方式
为了保证计算结果的一致性,强烈建议在调用这两个接口时,显式地传入相同的复权参数(推荐使用前复权)。
正确的使用示例:
def handlebar(ContextInfo):
# 假设我们要计算 000001.SZ 的 5 日均线
stock = '000001.SZ'
# 1. 使用 get_history_data,显式指定 dividend_type = 1 (前复权)
# 注意:get_history_data 只能获取 ContextInfo.set_universe() 中设置的股票数据
his_dict = ContextInfo.get_history_data(5, '1d', 'close', dividend_type=1)
if stock in his_dict and len(his_dict[stock]) == 5:
ma5_history = sum(his_dict[stock]) / 5.0
# 2. 使用 get_market_data_ex,显式指定 dividend_type = 'front' (前复权)
df_ex = ContextInfo.get_market_data_ex(
fields=['close'],
stock_code=[stock],
period='1d',
count=5,
dividend_type='front'
)
if stock in df_ex and not df_ex[stock].empty and len(df_ex[stock]) == 5:
ma5_ex = df_ex[stock]['close'].mean()
# 此时 ma5_history 和 ma5_ex 的计算结果应该是一致的
总结:在量化回测中,处理股票数据时务必时刻关注复权问题。统一使用前复权(dividend_type=1 或 'front')可以有效消除因接口默认值不同带来的回测误差。