4. 数据清洗与预处理流水线搭建

板块轮动周报与月报的结论是否可信,很大程度上取决于进入计算环节的数据是否干净、口径是否一致。板块轮动数据有三个鲜明特点:一是多源异构,行情来自交易接口、成分股来自指数公司、估值来自财务库,字段命名与时间戳格式各不相同;二是存在停牌、涨跌停、新股纳入、成分调整等结构性断点;三是复权口径不统一会让区间收益完全失真。因此,本节要搭建的不是零散的清洗脚本,而是一条可复用、可配置、可追溯的预处理流水线。

流水线的整体结构

建议把流水线拆成五个串行阶段,每个阶段只做一件事,并统一输出“宽表 + 质量日志”两份产物。宽表以“交易日期 × 板块代码”为索引,列为各板块的收盘价、复权因子、成交额、估值等字段;质量日志记录每个阶段处理的记录数、被修正或被剔除的样本及原因。这样后续周报、月报只依赖宽表,排障时只需查日志。

板块轮动数据预处理流水线 原始数据源 行情接口(日线) 指数成分与权重 估值/财务指标 交易日历 ① 时间序列对齐 统一交易日历 时区/日期格式归一 缺失交易日补位 去重与排序 ② 复权调整 前复权/后复权选择 除权除息因子 板块指数拼接 收益序列重算 ③ 缺失值处理 停牌识别 前向填充/插值 长缺口标记剔除 新股纳入处理 ④ 异常检测 涨跌幅阈值 MAD/分位法 成交额突变 人工复核标记 输出:标准化宽表 日期 × 板块代码|复权收盘价|成交额|估值 输出:质量日志 处理记录数|修正样本|剔除原因|告警 配置驱动 阈值/口径参数化 每个阶段独立可测,宽表与日志共同构成下游周报/月报的唯一数据入口

时间序列对齐:先统一“尺子”

对齐的第一步是确定基准日历。以 A 股为例,应以交易所发布的交易日历为准,而不是自然日。具体做法是:把各数据源的日期列统一转换为 YYYY-MM-DD 字符串或日期类型,剔除周末与节假日记录,再以基准日历为左表做外连接。对于板块指数在某个交易日无记录的情况,先区分是“非交易日”还是“停牌/数据缺失”,前者直接丢弃,后者保留占位并标记。

对齐时还要注意两点:一是估值、财务类数据往往是低频的(季度或月度),需要按“报告期 + 公告日”映射到交易日,避免未来函数;二是不同板块的上市起始日不同,早期数据天然缺失,不能简单用 0 填充,应保留 NaN 并在计算区间收益时按有效样本处理。

复权调整:让区间收益可比

板块指数本身通常已做修正,但若用成分股合成或使用 ETF 价格,就必须处理分红送转。原则是:计算历史区间收益用后复权,展示当前价格用前复权。实现上,读取每个板块的复权因子序列,用“原始价 × 复权因子”得到后复权价,再计算日收益率 r_t = P_t / P_{t-1} - 1。若某板块在区间内发生成分调整,应在调整日重置拼接基准,避免新旧成分价格直接相除产生虚假跳变。

缺失值处理:区分“没交易”和“没数据”

缺失值不能一刀切。停牌导致的缺失,价格应前向填充(保持停牌前收盘价),成交额填 0,并在日志中记录停牌天数;数据源漏采导致的缺失,若缺口不超过 2 个交易日可用线性插值,超过则标记为无效区间,不参与该周期的轮动打分。新股纳入板块时,纳入日之前的数据应视为不存在,而不是补 0,否则会把“从无到有”误判为暴涨。

异常值检测:规则 + 统计双保险

建议先用业务规则兜底:单日涨跌幅超过板块涨跌停限制(如 ±10%,ST 板块 ±5%)的记录直接标记;成交额为负或为 0 但价格发生变化的记录标记为可疑。再用统计方法补充:对日收益率序列计算中位数与 MAD(绝对中位差),把 |r - median| > 5 × 1.4826 × MAD 的点视为异常。被标记的样本不直接删除,而是置为缺失并进入人工复核队列,避免误杀真实的极端行情。

# 示例:基于 MAD 的异常标记(参数为教学假设值)
import numpy as np
import pandas as pd

def flag_outliers(ret: pd.Series, k: float = 5.0) -> pd.Series:
    med = ret.median()
    mad = (ret - med).abs().median()
    scale = 1.4826 * mad
    if scale == 0:
        return pd.Series(False, index=ret.index)
    return (ret - med).abs() > k * scale

# 对每个板块分别标记,保留原始值供复核
ret = wide["close_adj"].pct_change()
mask = ret.groupby(level="sector").transform(flag_outliers)
wide["ret_flag"] = mask

把流水线做成可复用组件

可复用的关键在于“配置与逻辑分离”。把交易日历路径、复权方式、插值上限、MAD 倍数、涨跌停阈值等写入一份 YAML 配置,流水线函数只读取配置执行。每次运行输出带时间戳的宽表与日志文件,并在日志头部记录配置快照,这样周报与月报使用同一份清洗结果,口径可追溯、结果可复现。下表给出建议的配置字段示例(数值为教学假设)。

配置项示例值作用
calendar_sourceexchange_calendar.csv基准交易日历
adjust_methodbackward区间收益采用后复权
max_interp_gap2允许插值的最大连续缺口(交易日)
mad_k5.0异常判定倍数
price_limit0.10常规板块单日涨跌幅阈值
suspend_fillffill停牌价格填充方式
验收流水线是否合格,可以看三个信号:宽表索引无重复、无乱序;每个板块的复权收益在除权日附近不出现异常跳变;质量日志中缺失率与异常率处于合理区间(例如单板块缺失率低于 5%)。若某项指标明显偏离,应回到对应阶段排查,而不是在下游报表里打补丁。

完成上述搭建后,后续的板块动量计算、轮动打分与周报月报生成都只需读取标准化宽表,数据口径问题被收敛在流水线内部,这正是可复用预处理的价值所在。