4. 停复牌数据获取
停复牌数据的获取,是缺失行情修复链条的起点。若停复牌事件本身识别错误,后续的插值、对齐、因子计算都会建立在错误前提上。本节围绕“从哪里拿数据、怎么拿、拿到后怎么清洗、如何判定停复牌事件”四个环节展开,目标是让学员建立一条可复现、可审计的数据获取与事件识别流水线。
一、核心原理:三类数据源的互补关系
停复牌信息并非只存在于一个地方。交易所公告是权威事实来源,行情数据源是交易状态的直接体现,数据接口则是工程化获取的通道。三者关系可以概括为:公告定义“为什么停”,行情定义“是否真的没交易”,接口负责“稳定地把两者取回来”。
- 交易所公告:上交所、深交所、北交所官网及巨潮资讯网发布的停牌/复牌公告,包含停牌原因、停牌起始日、预计复牌日、复牌日等字段,权威性最高,但格式多样、更新有延迟。
- 行情数据源:日线、分钟线行情中,停牌日通常表现为无成交、无收盘价或收盘价沿用前值。通过成交量、成交额、最高最低价是否为空,可以反推交易状态。
- 数据接口:Wind、Choice、Tushare、AkShare、聚宽等提供的停复牌接口,以及交易所公开数据接口,负责批量、定时、结构化地拉取上述信息。
二、方法流程:从接口拉取到事件表生成
完整流程可分为五步:接口拉取、字段对齐、数据清洗、事件识别、事件表落库。下面以 Tushare 与 AkShare 为例给出典型调用方式。
# 示例:拉取停复牌信息(Tushare)
import tushare as ts
pro = ts.pro_api('YOUR_')
df = pro.suspend_d(suspend_type='S', start_date='20240101', end_date='20241231')
# 字段:ts_code, trade_date, suspend_timing, suspend_type
# 示例:AkShare 获取停复牌
import akshare as ak
suspend_df = ak.stock_tfp_em(date="20240101")
拉取后需进行字段对齐:统一股票代码格式(如 600000.SH 与 600000 的映射)、统一日期格式(YYYYMMDD 与 YYYY-MM-DD)、统一停牌类型编码(S 停牌、R 复牌)。随后进入清洗环节。
三、数据清洗:停复牌数据的常见脏数据类型
停复牌数据清洗的重点不是“去重”这么简单,而是要处理以下几类问题:
| 脏数据类型 | 典型表现 | 清洗策略 |
|---|---|---|
| 重复记录 | 同一股票同一日多条停牌公告 | 按股票+日期去重,保留最新公告时间 |
| 日期缺失 | 复牌日为空或为“待定” | 用行情首个有成交日回填复牌日 |
| 类型混淆 | 停牌与复牌记录混在同一字段 | 按 suspend_type 拆分,生成事件对 |
| 代码不一致 | 退市、更名导致代码变更 | 建立代码映射表,回溯历史代码 |
| 非交易日干扰 | 周末、节假日被误判为停牌 | 与交易日历对齐,剔除非交易日 |
四、停复牌事件识别:从记录到区间
清洗后的停复牌记录仍是离散的“点”,而修复缺失行情需要的是“区间”。事件识别的核心任务,就是把停牌记录与复牌记录配对,生成 [停牌起始日, 复牌日) 的停牌区间。
- 按股票代码分组,按日期升序排列。
- 遇到 suspend_type=S 记录,标记为区间起点。
- 向后寻找最近的 suspend_type=R 记录,作为区间终点。
- 若区间终点缺失,用行情中首个恢复成交的交易日作为终点。
- 校验区间内每个交易日是否确实无成交,剔除误判区间。
# 事件区间生成伪代码
for code, group in df.groupby('ts_code'):
group = group.sort_values('trade_date')
start = None
for _, row in group.iterrows():
if row['suspend_type'] == 'S':
start = row['trade_date']
elif row['suspend_type'] == 'R' and start:
events.append((code, start, row['trade_date']))
start = None
识别完成后,还需与行情数据做一次“一致性校验”:停牌区间内的交易日,成交量应为 0 或缺失;复牌日当天应恢复成交。若不一致,需回到公告或行情源排查。
五、案例与复盘:一次误判引发的修复偏差
某量化团队在修复某只股票 2023 年 5 月的缺失行情时,发现 5 月 8 日至 5 月 12 日无任何成交数据,便直接判定为停牌并做了前值填充。但后续核对公告发现,该股实际停牌日为 5 月 9 日至 5 月 11 日,5 月 8 日和 5 月 12 日均为正常交易日,只是当日成交量为 0(极端冷门股)。这一误判导致两天的“伪停牌”被错误填充,进而影响了波动率因子的计算。
复盘结论有三点:
- 不能仅凭行情缺失判定停牌,必须与公告交叉验证。
- 停牌区间边界要精确到日,起始日和复牌日的归属直接影响收益率计算。
- 清洗与识别要留痕,每一步的剔除、回填、修正都应记录日志,便于审计与复现。
source 字段,标记该事件来自公告、行情推断还是人工修正,并保留 update_time,这样在后续修复出现异常时,可以快速定位是数据源问题还是识别逻辑问题。至此,停复牌数据从获取、清洗到事件识别的完整链路已经建立。下一阶段将在此基础上,进入缺失行情的具体修复方法。