问题描述
解决方案
在PTrade中,get_history 和 get_price 接口在获取历史行情时,默认不会跳过停牌日期。对于停牌期间的数据,系统会使用停牌前一交易日的收盘价进行填充,并将成交量(volume)设为0。
因此,要过滤掉停牌数据,最直接有效的方法是对返回的 DataFrame 进行筛选,剔除 volume 为 0 的行。
以下是具体的代码实现示例:
代码实现
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def handle_data(context, data):
# 1. 获取历史行情数据(包含收盘价和成交量)
# 注意:必须获取 'volume' 字段用于判断
df = get_history(10, frequency='1d', field=['close', 'volume'], security_list=g.security)
# 打印原始数据(包含停牌填充数据)
log.info("原始数据:")
log.info(df)
# 2. 过滤停牌数据
# 逻辑:保留成交量大于0的数据
df_filtered = df[df['volume'] > 0]
# 打印过滤后的数据
log.info("过滤停牌后数据:")
log.info(df_filtered)
# 3. 进一步处理(示例:计算均线)
if len(df_filtered) > 0:
mean_price = df_filtered['close'].mean()
log.info("有效交易日的平均收盘价: %s" % mean_price)
核心逻辑说明
- 获取字段:调用
get_history或get_price时,field参数必须包含'volume',因为这是判断是否停牌的关键依据。 - Pandas筛选:利用 Pandas DataFrame 的布尔索引功能
df[df['volume'] > 0],直接筛选出成交量大于 0 的行。 - 多股处理:如果是同时获取多只股票的数据(返回 DataFrame 格式,包含
code列),上述代码同样适用,它会移除所有股票中成交量为 0 的记录。
Q&A
Q: 为什么PTrade返回的历史数据包含停牌日?
A: PTrade 为了保持时间序列的连续性(例如在绘制K线图或进行矩阵计算时保持索引对齐),默认会对停牌日进行填充。填充规则是:价格沿用前一交易日收盘价,成交量为0。
Q: 除了判断成交量,还有其他方法判断停牌吗?
A: 可以使用 get_stock_status(stocks, 'HALT') 接口查询股票当前的停牌状态,或者使用 get_history 时获取 paused 字段(如果接口支持返回该字段,但在PTrade标准文档中,利用 volume 判断是最通用的做法)。
Q: 如果股票全天跌停或涨停导致没有成交量,会被误判为停牌吗?
A: 理论上极少出现全天成交量严格为0的情况(通常会有少量撮合)。但在极端流动性枯竭的情况下,如果成交量确实为0,该逻辑会将其过滤。对于绝大多数A股策略,volume > 0 是区分停牌与否的有效标准。