3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 QMT 平台中,使用 get_history_data 和 get_market_data_ex 计算均线(MA)等技术指标时,如果发现回测结果差距很大,最核心的原因通常是:两个函数默认的复权方式(dividend_type)不同。
以下是详细的原因分析及解决方案:
股票在发生分红、送股等除权除息事件后,价格会出现跳空。如果不进行复权处理,直接计算均线会导致指标严重失真。
get_history_data 的默认复权方式是不复权:get_history_data 的 dividend_type 参数默认值为 0(不复权)。get_market_data_ex 的默认复权方式是跟随主图:get_market_data_ex 的 dividend_type 参数默认值为 'follow'(跟随当前主图复权方式)。在进行策略回测时,我们通常会在策略基本信息中将主图设置为“前复权”。结果差异:如果你在代码中没有显式指定复权参数,get_history_data 取到的是不复权数据,而 get_market_data_ex 取到的是前复权数据。用这两组不同的价格序列计算出来的均线自然会产生巨大的差异,进而导致买卖信号和回测收益完全不同。
get_history_data:参数 skip_paused 默认为 True,即遇到停牌日会自动用停牌前最后一个交易日的价格进行填充。get_market_data_ex:参数 fill_data 默认为 True,但文档中特别标注了“暂不可用”。这可能导致在某些特定停牌场景下,两者返回的 K 线序列长度或数据对齐方式存在细微差别。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')可以有效消除因接口默认值不同带来的回测误差。