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 拆分,生成事件对
代码不一致 退市、更名导致代码变更 建立代码映射表,回溯历史代码
非交易日干扰 周末、节假日被误判为停牌 与交易日历对齐,剔除非交易日
清洗阶段最容易犯的错误是“把没有行情等同于停牌”。新股上市首日、退市整理期、长期无成交的冷门股,都可能出现无行情但并非停牌的情况,必须结合公告与交易日历交叉验证。

四、停复牌事件识别:从记录到区间

清洗后的停复牌记录仍是离散的“点”,而修复缺失行情需要的是“区间”。事件识别的核心任务,就是把停牌记录与复牌记录配对,生成 [停牌起始日, 复牌日) 的停牌区间。

  1. 按股票代码分组,按日期升序排列。
  2. 遇到 suspend_type=S 记录,标记为区间起点。
  3. 向后寻找最近的 suspend_type=R 记录,作为区间终点。
  4. 若区间终点缺失,用行情中首个恢复成交的交易日作为终点。
  5. 校验区间内每个交易日是否确实无成交,剔除误判区间。
# 事件区间生成伪代码
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 或缺失;复牌日当天应恢复成交。若不一致,需回到公告或行情源排查。

停复牌数据获取与事件识别流水线 交易所公告 权威事实来源 行情数据源 交易状态校验 数据接口 批量稳定拉取 数据清洗:去重 · 日期对齐 · 类型拆分 · 代码映射 · 交易日历校验 剔除重复公告、回填缺失复牌日、剔除非交易日误判 停复牌事件识别:S/R 配对 → 生成 [停牌起始日, 复牌日) 区间 与行情一致性校验:停牌区间无成交,复牌日恢复成交 停复牌事件表

五、案例与复盘:一次误判引发的修复偏差

某量化团队在修复某只股票 2023 年 5 月的缺失行情时,发现 5 月 8 日至 5 月 12 日无任何成交数据,便直接判定为停牌并做了前值填充。但后续核对公告发现,该股实际停牌日为 5 月 9 日至 5 月 11 日,5 月 8 日和 5 月 12 日均为正常交易日,只是当日成交量为 0(极端冷门股)。这一误判导致两天的“伪停牌”被错误填充,进而影响了波动率因子的计算。

复盘结论有三点:

  • 不能仅凭行情缺失判定停牌,必须与公告交叉验证。
  • 停牌区间边界要精确到日,起始日和复牌日的归属直接影响收益率计算。
  • 清洗与识别要留痕,每一步的剔除、回填、修正都应记录日志,便于审计与复现。
建议在事件表中增加 source 字段,标记该事件来自公告、行情推断还是人工修正,并保留 update_time,这样在后续修复出现异常时,可以快速定位是数据源问题还是识别逻辑问题。

至此,停复牌数据从获取、清洗到事件识别的完整链路已经建立。下一阶段将在此基础上,进入缺失行情的具体修复方法。