踩坑复盘
adv 语义错误
论文定义 adv{d} 为「平均成交金额」,早期实现误用「平均成交股数」。无异常抛出,但因子值系统性偏差。#33 事故档案。
层级 DWS · 因子计算 严重度 高(隐性) 关联 #33 · commit 2ebb979 · operators.py alpha_factors.py
现象
程序无异常,因子计算正常完成,回测结果看似合理。但将实现与论文逐项核对后发现,凡涉及 adv{d} 的因子,截面排序均与预期不符——属于无异常但结果系统性偏差的静默错误。
定位
WorldQuant 文档对 adv{d} 的定义是:
adv{d}= average daily dollar volume for the past d days(过去 d 天的平均成交金额)
而早期实现里,adv 直接对 volume(成交股数)取均值:
# 错误:成交股数的均值
adv20 = volume.rolling(20).mean()
# 正确:成交金额 = 价格 × 股数,再取均值
adv20 = (close * volume).rolling(20).mean()一只 $500 的股票和一只 $5 的股票,成交股数相近时成交金额差 100 倍——adv 一错,所有以它做分母 / 排序的因子全部失真。
根因
volume 和 dollar volume 在代码里都是一列浮点数,类型相同、维度相同,编译器和测试都不会报警。这类 bug 的本质是语义错位:数值合法、结构正确,只有「它代表什么」错了。
修复
按论文定义把 adv{d} 一律改为 (close * volume) 的滚动均值,并补单元测试锁定语义。借这次排查,把所有算子逐个对照 WorldQuant 原文做了一遍语义审计。
教训:量化系统中危害最大的 bug 不是抛出异常,而是静默的语义偏差——程序正常运行,但结果系统性失真。防范此类问题的关键手段是为每个算子编写语义级单元测试,明确验证其物理含义。
关联
- 手册:3. 因子与信号 DWS
- 基础:WorldQuant 算子词典——
adv{d}的权威定义在这里。 - 同期修复:随机扰动与不可复现