问题描述
解决方案
在 QMT 策略回测中,为了避免分红、送股等公司行为导致股价出现非市场因素的“跳空缺口”,从而影响策略信号的准确性,必须使用复权数据。
通常推荐使用前复权(Forward Adjustment),因为它以当前价格为基准,向下调整历史价格,保持了最新的价格与实际盘面一致,非常适合策略回测和实盘信号判断。
在 QMT 中,可以通过以下两种方式来实现:
方法一:在策略编辑器界面设置(全局生效)
这是最简单的方法。在 QMT 客户端的策略编辑器中,无需修改代码,直接更改设置即可:
- 打开【策略编辑器】。
- 在右侧或下方的【基本信息】面板中找到 “复权方式” 选项。
- 将其设置为 “前复权”(或者“等比前复权”)。
- 设置后,策略中所有默认跟随主图的数据获取函数(如
dividend_type='follow')都会自动使用前复权数据。
方法二:在代码中指定复权参数(API 控制)
如果你需要在代码中精确控制获取的数据类型,或者混合使用不同复权方式的数据,可以在调用数据获取接口时显式指定 dividend_type 参数。
推荐使用 ContextInfo.get_market_data_ex 接口,因为它更高效且功能更全。
关键参数说明
dividend_type:'none': 不复权(原始价格,会有缺口)'front': 前复权(推荐用于回测)'back': 后复权'follow': 跟随主图/界面设置
代码示例
以下代码展示了如何在策略中强制获取“前复权”的历史数据,以消除分红影响:
# -*- coding: gbk -*-
def init(ContextInfo):
# 设置股票池,例如平安银行
ContextInfo.set_universe(['000001.SZ'])
# 可以在init中打印提示
print("策略初始化完成,准备获取前复权数据...")
def handlebar(ContextInfo):
# 获取当前K线位置
index = ContextInfo.barpos
# 获取当前主图的股票代码
stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
# 仅在最后一根K线或特定条件下打印,避免日志过多
if ContextInfo.is_last_bar():
# 【核心代码】使用 get_market_data_ex 获取前复权数据
# dividend_type='front' 强制指定为前复权
# count=10 获取最近10根K线
data_map = ContextInfo.get_market_data_ex(
fields=['open', 'high', 'low', 'close'],
stock_code=[stock_code],
period='1d',
start_time='',
end_time='',
count=10,
dividend_type='front', # 这里指定 'front' 即可避免分红缺口
fill_data=True,
subscribe=True
)
if stock_code in data_map:
df = data_map[stock_code]
print(f"股票 {stock_code} 的最近10日前复权数据:")
print(df)
# 示例:计算简单的均线,因为是复权价格,不会受分红跳空影响
if len(df) >= 5:
ma5 = df['close'].rolling(window=5).mean().iloc[-1]
print(f"当前5日均线价格: {ma5}")
总结
- 界面设置:将策略属性中的“复权方式”改为“前复权”,这是最快捷的方式。
- 代码设置:在
get_market_data_ex或get_history_data中将dividend_type参数设置为'front'(或1对于旧版接口)。
通过以上设置,历史K线将变得平滑,技术指标(如均线、MACD)计算将基于调整后的价格,从而避免因分红造成的虚假交易信号。
Q&A
Q: 为什么回测通常推荐使用“前复权”而不是“后复权”?
A: 前复权是以当前最新价格为基准,调整过去的价格。这意味着图表上的最新价格与你实际看到的盘面价格一致,方便直观判断和实盘核对。后复权虽然也能消除缺口,但会导致当前价格变成一个很大的数字(如几千元),与实际交易价格不符,容易造成混淆。
Q: get_history_data 接口如何设置复权?
A: get_history_data 是较老的接口,它的 dividend_type 参数是数字类型。0 代表不复权,1 代表前复权,2 代表后复权。建议尽量使用 get_market_data_ex。
Q: 如果我在界面设置了“前复权”,代码里写 dividend_type='none',以哪个为准?
A: 以代码为准。代码中的显式参数优先级高于界面设置。如果代码中写 dividend_type='follow',则会使用界面的设置。