问题描述
如图,6.24日取6.23日的K值,为什么与6.23日取的K值不同?
解决方案
在JoinQuant(聚宽)平台上,今天获取昨天的K线数据(如开盘价、收盘价等)与昨天当天获取的数据不同,最核心的原因是股票发生了除权除息事件,导致前复权价格发生了变化。
以下是详细的原因分析及解决方案:
1. 核心原因:前复权机制 (Pre-adjustment)
JoinQuant 平台的数据获取 API(如 get_price、history、attribute_history 等)默认返回的是**前复权(fq='pre')**数据。
- 什么是前复权? 前复权是以当前日期(你调用 API 的那一天)为基准,保持当前价格不变,将历史价格向下调整,以消除分红、送股、配股等除权除息事件造成的K线断层。
- 为什么数据会变? 假设 6月23日 股票收盘价为 10元。6月23日晚间(或6月24日早盘前)该股票进行了分红(例如每股分红1元)。那么在 6月24日,系统的复权因子会发生改变。为了保持K线连续,系统会将 6月23日及以前的历史价格进行前复权处理。此时,你在 6月24日 去获取 6月23日 的前复权收盘价,拿到的可能就是 9元,而不是昨天你看到的 10元。
官方文档特别提醒:
“你在不同日期调用 history/attribute_history/get_price 等 API 返回的价格可能是不一样的, 因为我们在不同日期看到的前复权价格是不一样的。所以不要跨日期缓存这些 API 返回的结果。”
2. 解决方案
如果你希望获取到的历史价格是固定不变的,或者需要真实的交易价格,可以采用以下几种方法:
方法一:获取不复权(真实)数据
在调用数据 API 时,显式地将复权参数 fq 设置为 None,这样获取到的就是当时真实的交易价格,不会随时间变化。
# 获取不复权数据,价格不会随除权除息改变
df = get_price('000001.XSHE', start_date='2023-06-23', end_date='2023-06-23', fq=None)
print(df['close'])
方法二:开启动态复权(真实价格)模式(强烈建议)
在策略的 initialize 函数中开启真实价格模式。开启后,回测和模拟交易将使用真实的未复权价格进行撮合,这能有效避免未来函数,并反映真实的账户资金变动。
def initialize(context):
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
注意:即使开启了 use_real_price,为了方便计算指标,history 等 API 默认返回的依然是基于当天的前复权价格。如果需要真实价格,仍需结合 fq=None 或利用复权因子还原。
方法三:利用复权因子还原真实价格
如果你同时需要复权数据计算均线,又需要真实价格,可以同时获取 factor(复权因子)字段,通过计算还原真实价格:
# 获取前复权收盘价和复权因子
df = attribute_history('000001.XSHE', 1, '1d', fields=['close', 'factor'])
# 还原昨天的真实收盘价
real_close = df['close'][-1] / df['factor'][-1]
总结
出现数据不一致是量化平台处理复权数据的正常现象。在编写策略时,切忌将某一天获取的前复权历史数据缓存下来留到第二天使用。每次需要历史数据时,都应该在当前时间点重新调用 API 获取最新的前复权数据,或者直接使用不复权数据(fq=None)进行逻辑判断。