2. 数据预处理 DWD
数据治理的设计原则:修复已知语义的缺失、暴露未知原因的异常。预处理负责数据治理,对问题数据抛出告警。
作用:把原始 K 线加工成因子可直接消费的干净面板,写入 processed_kline_data。
输入与输出的契约
输入是通过入库校验的原始日 K 线(OHLCV + vwap,见 数据接入层)。输出是一张「日期 × 标的」的面板,在原始字段之上新增三个衍生字段:
| 字段 | 含义 | 说明 |
|---|---|---|
returns | 日收益率 | pct_change 计算,每只标的的首行天然缺失 |
vwap | 成交量加权均价 | 停牌日的 0 值会被修复(见下) |
cap | 市值代理 | 成交额(volume × close),并非真实市值 |
这一层对下游的承诺是:进入因子层的每个值,要么可用,要么被显式暴露(告警或停机)。不允许静默的坏值。围绕这个承诺,预处理做了三个关键决策。
决策一:极端值截断,而不是删行
逐日截面上,对 returns / volume / cap / vwap 做 mean±4σ 截断(Winsorization)。
为什么要处理:Alpha101 的核心运算是截面统计——排名、zscore、相关性。少数长尾异常点即可扰乱这些统计量,让整个截面的评分失真。
为什么截断而不是删行:删掉一行,当天截面就少了一只标的,其余所有标的的相对排名都会改变;而且缺席的原因(数据错误还是真实暴跌)被一并掩盖。截断保留这只标的的存在和它「极端」这个信息,只是不让极端的幅度污染统计量。
举个数字例子:某日截面 returns 均值 0.1%、标准差 2%,4σ 边界约为 ±8%。一只标的因数据源错误出现 +300% 的收益率,截断后变为 +8%——它仍排在截面最前列(排名信息保留),但不再把均值、标准差和相关性整体拉偏。
决策二:缺失值修复已知语义、暴露未知原因
面板里的 NaN 不做一刀切的填充,而是按「是否知道缺失的原因」分开处理:
- 唯一主动补的值是 returns 首行补 0:
pct_change首行天然是 NaN,语义明确,补 0 无歧义。 - 其余缺失按标的自身的时间序列前向 / 后向填充。填充不跨标的、不凭空造行——停牌日本来就没有行,就保持没有行(行缺失由后面的交易日断点检查暴露)。
- 填充后仍残留的 NaN 保留原样,按列统计并抛出告警。实践中能走到这一步的基本只有一种情况:某标的整列无有效值(典型如整列为 0 的 vwap 被替换成整列 NaN),属于病态数据,交给下一道质量检查停机、人工介入。
这个取舍的原则是:预处理层可以修复「已知语义」的缺失,但不应掩盖「未知原因」的缺失。后者是数据质量问题的信号,掩盖后难以追溯根因。
已知问题:后向填充引入前视偏差
后向填充用未来值填补历史起点段的缺失,属于 look-ahead。当前实现中 returns 的首行也受此影响(首行 NaN 先被次日收益率填掉,「补 0」实际未生效)。影响范围为每只标的的第一行,每日增量运行不受影响。修复方向:returns 不参与后向填充,首行留给补 0。
决策三:坏数据停机,而不是带病计算
预处理落库之后、因子计算之前,流水线设有一道数据质量检查(DQC),对整张面板做八项检查(空值、价格逻辑、异常收益率、覆盖度、零成交量等,明细见下方实现对照)。任一项不通过,整条流水线在因子计算前中止:当天不出信号、不下任何单,持仓维持不动。
为什么这么保守:一条脏数据进入因子层,污染的不是一个点,而是整个截面。以停牌日 vwap=0 为例,如果不处理:
vwap = 0 → 含 close/vwap 的因子在该标的上产生极端值
→ 截面排名被挤占 → 当日 Top 10 名单可能因此换人单个坏值是截面问题,不是单点问题。宁可当天不出信号,也不让被污染的截面进入因子层。
代价与调整:停牌日 volume=0 这类常态噪声也会触发停机,需要人工介入判断。若长期靠人工放行,检查会退化成告警,因此八项检查正在分级:空值 / 价格逻辑 / 异常收益率 / 覆盖度为 hard(直接停机);零成交量 / 零振幅 / 交易日断点为 soft(占比超过 1% 才停机,否则告警放行)。
与去极值的分工:Winsorization 处理「真实但极端」的值,是统计处理;DQC 抓「不该存在」的值,是告警停机。两者不重复。
常见错误
- 增量处理的窗口边界算错,回溯期 returns 失真,污染整张因子截面 → 事故档案 · 增量窗口污染
- 未做去极值时,少数长尾异常点扰乱截面排名 → 引入 Winsorization 的直接动因
当前状态
已上线:returns / vwap / cap 衍生 + 时序填充 + 去极值;DQC 作为流水线 Step 3 每日运行,任一检查项失败即中止后续因子计算。这套清洗逻辑回测与实盘共用(One Codebase),保证所见即所得。
主要缺口:tradable_mask 尚未落地,停牌、不可交易和数据源缺失目前混在一起;更严谨的版本应按字段区分填充规则(价格可有限前填,成交量和可交易状态不应被无差别补齐)。完整清单见下方实现对照。
实现对照
上一层:1. 数据接入 ODS · 下一层:3. 因子与信号 DWS