问题描述
使用get_history获取K线数据后,发现数据中包含停牌日的数据,应该如何处理?
解决方案
在 ptrade 量化平台中,使用 get_history 接口获取历史行情数据时,系统默认不会跳过停牌的日期。为了保持时间轴与二级市场交易日日历一致,停牌日的数据会使用停牌前最后一个交易日的数据进行填充,并且当天的成交量(volume)和成交额(money)会被设置为 0。
因此,过滤停牌日数据的最有效方法就是剔除成交量(volume)为 0 的数据行。
过滤停牌日数据的代码示例
以下是如何在策略中通过 Pandas 的数据筛选功能来过滤停牌日数据的具体示例:
1. 单只股票的停牌日过滤
当获取单只股票的数据时,返回的是一个以时间为索引的 DataFrame。我们可以直接通过 volume > 0 来筛选。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def handle_data(context, data):
# 获取过去 10 天的历史数据,包含收盘价和成交量
df = get_history(10, '1d', ['close', 'volume'], security_list=g.security)
if df is not None and not df.empty:
# 过滤停牌日:只保留成交量大于 0 的数据
valid_df = df[df['volume'] > 0]
log.info("原始数据长度: %s, 过滤后数据长度: %s" % (len(df), len(valid_df)))
log.info("过滤后的有效数据:\n%s" % valid_df)
2. 多只股票的停牌日过滤
当获取多只股票的数据时(在 Python 3.11 环境下),返回的 DataFrame 会包含 code 列。我们同样可以使用 volume > 0 进行全局过滤,或者针对特定股票过滤。
def initialize(context):
g.security = ['600570.SS', '000001.SZ']
set_universe(g.security)
def handle_data(context, data):
# 获取多只股票的历史数据
df = get_history(10, '1d', ['close', 'volume'], security_list=g.security)
if df is not None and not df.empty:
# 全局过滤:剔除所有股票中成交量为 0 的记录
valid_df = df[df['volume'] > 0]
# 如果需要单独获取某只股票的有效数据
stock_a_df = valid_df.query('code == "600570.SS"')
log.info("600570.SS 的有效交易日数据:\n%s" % stock_a_df)
注意事项
- 日 K 线适用性:这种通过
volume == 0过滤的方法主要适用于日线级别(1d)的数据。对于分钟级别的数据,由于正常交易时间内也可能存在某分钟无成交的情况,直接过滤volume == 0可能会误删正常交易时间段内的数据。 - 数据填充逻辑:了解 ptrade 的填充逻辑(停牌日价格等于停牌前价格)有助于在计算移动平均线(MA)等技术指标时做出正确的处理选择。如果直接使用包含停牌日的数据计算 MA,停牌期间的平段价格会拉低或拉高均线的波动;如果过滤后再计算,则反映的是实际交易日的均线走势。通常建议过滤停牌日后再计算技术指标。