基线阈值怎么定?数据清洗里藏着多少您不知道的坑
第13页 · 预计12页
上一章结束时,我已经将五维度框架抛给对方,并给出了基线筛选结果(钢铁、有色、银行等传统周期股)。对方看后没有立即接受,而是提出了一个看似微小却关键的要求:“老师,就按您说的标准,再加上‘超跌排名靠前’。”
这句话包含两个隐含信息:第一,对方接受了我提出的五个维度作为基础框架,没有质疑维度本身的合理性;第二,对方想要追加一个额外的排序条件——“超跌排名靠前”,意味着在满足基础条件的前提下,按照年内回撤幅度从大到小排序,选取回撤最大的10只。
这个要求并不复杂,但暴露出一个常见问题:“按您说的标准”中的“标准”其实并未被量化。我需要做出一个专业判断——是用行业惯例填补阈值空白,还是返回去追问具体数字?
很多量化从业者遇到这种情况,会习惯性地追问“您想要回撤多少?”“ROE要多少合适?”,但这样反而会让本来就没有明确标准的用户更加困惑。我的经验是,先给出一个经过市场验证的基线,让用户在基线的基础上调整,远比从零开始讨论效率高得多。
我选择了前者。理由如下:在缺乏明确偏好的情况下,给出一份可讨论的参照系,其信息价值高于不给出任何结果。行业通用的“优质股”阈值(ROE>15%、PE<20倍)已经被大量学术研究和实践验证为区分“平庸”与“优秀”的有效分界线。阈值本质上是一种可迭代的参数,而非教条。后续可以根据对方反馈迅速调整。
具体设定的每个阈值,背后都有扎实的量化依据,不是随手写的数字:
| 维度 | 条件 | 说明 |
|---|---|---|
| 净资产收益率(ROE) | >15% | 高于A股平均水平,筛选盈利能力稳定的公司 |
| 净利润三年复合增长率 | >0% | 排除持续下滑企业,但不要求高增长(避免过滤掉稳健型) |
| 滚动市盈率(PE TTM) | <20倍 | 低于市场均值,避免高估值泡沫 |
| 总市值 | >100亿元 | 剔除流动性差的小市值股票(日均成交额常低于300万元) |
| 年内高点回撤 | >30%(用于排序) | 技术性超跌的常见阈值,与“熊市底部区域”经验值吻合 |
| 风险标记 | 非ST/*ST | 过滤退市风险、财务造假等极端案例 |
净资产收益率ROE大于15%:A股全市场长期ROE中位数大约在8%到10%之间,15%以上的公司大致处于全部上市公司的前30%分位,能够稳定维持这个水平的公司,通常具备稳定的盈利能力和一定的竞争壁垒,不会轻易陷入行业价格战。这个阈值也是国内机构选股时常用的盈利底线,具备广泛的市场共识基础。
净利润三年复合增长率大于0:这个条件相对宽松,目的只是排除连续三年净利润下滑的衰退型企业,不对增长速度做过高要求。这样可以把那些盈利稳定但增速不高的稳健型公司保留下来,避免筛选结果过度偏向高波动的成长股。
滚动市盈率PE小于20倍:万得全A指数的长期PE中枢大约在17到18倍之间,20倍作为上界,略高于市场均值,既不会因为太严格而选出太少标的,也不会因为太宽松而纳入估值泡沫严重的股票。对于价值型选股来说,20倍PE是公认的合理估值上沿。
总市值大于100亿元:设置这个门槛主要是为了排除流动性过差的小市值股票。通常总市值低于100亿的个股,日均成交额经常低于3000万元,买卖滑点大,大一点的资金进出就会影响股价,不适合作为策略标的。100亿以上的公司流动性基本有保障,也大多已经度过了最脆弱的初创期,爆雷风险相对更低。
年内高点回撤大于30%:这是技术性超跌的常见阈值,与“熊市底部区域”的经验值吻合。一般来说,个股从高点回撤30%,通常已经消化了大部分利空情绪,进入了价值区间,反弹的概率和空间都会明显提升。这个阈值也是很多逆向投资者的通用抄底线。
风险标记为非ST、非*ST:过滤退市风险、财务造假等极端案例。这是所有选股策略的前置条件,不用多解释。
如果想要测试不同阈值下的选股效果,或者查看全市场各个因子的分位分布,可以登录a-sig.com壹信因子查询平台,所有阈值都可以自由调整,实时返回筛选结果和历史回测表现。
在调用数据接口时,会遇到三类常见问题,需要预处理。这些细节在最终输出的表格中完全不可见,但任何一个环节出错,都会导致结果偏差。量化工作中,80%的时间花在数据准备上,只有20%用于建模和筛选。很多新手以为量化就是写公式选股票,最后才发现数据质量才是决定策略成败的基础。
季报披露时间不统一:部分公司在4月底才披露一季报,而另一部分可能已披露中报。为确保可比性,需要统一使用最新报告期数据,并标注报告期截止日。这里最容易犯的错误就是“未来函数”——比如用4月30日的全部财报数据,去回测4月20日的选股,相当于在当时使用了还没披露的信息,回测收益会严重虚高,实盘根本无法复现。
ROE计算口径也有差异:有摊薄ROE和加权ROE,有单季度的也有滚动12个月的。我统一使用TTM(滚动12个月)ROE,以平滑季节性波动,避免单季度业绩波动导致的指标失真。
PE为负的公司(亏损)应当剔除,因为负PE没有比较意义。PE大于100倍的公司,除非有明确的高增长逻辑,否则在基线筛选中一并排除。这些极端值往往是微利公司(每股收益趋近于零)或泡沫股,会导致PE失真,拉低整体筛选结果的可靠性。
我见过很多新手第一次选股,选出来的PE第一名是几千倍,就是因为没有剔除微利股,这样的筛选结果完全没有参考价值。
“年内高点”需要明确:是指自然年度(1月1日至今)的最高收盘价,还是过去252个交易日的最高价?我选择后者(过去一年),更符合技术分析习惯,且避免年初效应。如果用自然年度,每年1月1日所有股票的回撤都归零,会导致年初的筛选结果完全失真。
如果个股在年内有过除权除息,需要复权处理。使用前复权价格计算回撤,否则回撤幅度会被严重高估。举个最常见的例子:某只股票执行10送10的分红方案,股价从20元跌到10元,如果不复权直接算回撤,会得出-50%的结论,看似深度超跌,但实际复权后的回撤可能只有-10%。误把除权当成超跌,是新手最常见的错误之一,我见过不下十个人栽在这个细节上。
不同接口返回的市值单位可能不同(万元、亿元、元),需要统一转换为亿元。回撤幅度可能是小数(0.3)也可能是百分数(30),需要标准化。
不要小看这些单位问题,我曾经遇到过因为两个数据源一个用万元一个用亿元,导致算出来的市值差了一万倍,筛选结果完全错误的情况。细节决定成败,量化工作尤其如此。
这些数据清洗的细节处理,在intoquant.com提供的代写源码服务中都会默认内置,包括数据对齐、极值处理、复权校准等全套逻辑,不用自己逐个踩坑调试。
执行筛选后,得到上一章末尾的10只股票表格。为了让对方更直观地理解这批股票的特征,我同时提供了两个统计摘要:行业分布统计和关键指标的分布区间。
我没有直接丢给对方10行股票代码就完事,而是先给整体画像,原因很简单:人对信息的接收是先整体后局部的。如果先看个股,很容易陷入对某只股票的主观好恶,忽略整体特征。先看行业分布和指标区间,就能快速建立对这批股票的整体认知——这是一批估值低廉、盈利稳健、但近期跌幅较大的传统周期性公司。
| 行业 | 股票数量 | 平均回撤 | 平均ROE | 平均PE |
|---|---|---|---|---|
| 钢铁 | 3 | -35.4% | 17.2% | 9.7 |
| 有色金属 | 2 | -32.2% | 19.6% | 13.4 |
| 银行 | 1 | -30.8% | 15.3% | 5.1 |
| 房地产 | 1 | -41.2% | 15.9% | 7.4 |
| 建筑 | 1 | -32.4% | 16.2% | 5.8 |
| 建材 | 1 | -38.9% | 17.8% | 9.6 |
从行业分布能很清楚地看到,钢铁、有色、建材这些周期行业占了绝大多数,没有科技股,没有成长股,完全是价值风格的标的。
关键指标的分布区间也有明确的特征:
回撤幅度集中在30%到41%之间,标准差约3.8%,波动较小,说明这批股票的超跌程度比较均匀,没有某只股票回撤特别深或者特别浅的情况。
ROE全部高于15%门槛,最高为紫金矿业的22.3%,最低的宝钢股份也有15.1%,整体盈利质量很高。
PE从5.1倍到15.6倍不等,最低的是成都银行,最高的是山金国际,全部低于20倍的阈值,估值水平整体偏低。
这些统计不是为了炫技,而是让对方快速把握这批股票的整体画像,不用一个个去算去查。
如果需要批量生成不同市场、不同策略的筛选统计报告,也可以通过intoquant.com定制自动化报表脚本,每日自动输出完整的筛选结果与统计分析,节省大量手工整理时间。
从量化条件看,这份名单无懈可击。但从交易者的直觉看,它可能“不够性感”。
这里存在一个核心矛盾:量化筛选追求规则的一致性和可复现性,而交易者的偏好往往包含审美判断——对行业、故事、想象空间的偏好。
例如,钢铁和水泥行业虽然ROE高、PE低,但市场给予它们的长期估值一直偏低,因为行业处于成熟期甚至衰退期,缺乏增长预期。而成长股投资者宁愿买80倍PE的AI芯片公司,也不愿买8倍PE的钢铁股。这不是谁对谁错的问题,而是投资框架的差异——价值投资者赚业绩修复的钱,成长投资者赚产业扩张的钱。
我选择不主动“优化”这份名单,而是将它作为一个锚点。原因在于:如果对方不满意,他的反馈将是最有价值的修正信号——他会告诉我,他更在意成长性、产业趋势还是其他什么维度。而如果他满意,说明他的策略偏好就是深度价值+逆向投资。
这就像机器学习中的主动学习:先用初始模型给出预测,然后根据用户对预测结果的反馈,不断调整模型权重。迭代的成本远低于一次性构建完美模型的成本。
做量化这么多年我最深的感受是:好的策略从来不是设计出来的,而是迭代出来的。
对方看到这份名单后的第一句话,将成为整个策略迭代的转折点。但那是第三章的内容。
在本章结束时,我需要做的是:准备好接收反馈,并预判可能的调整方向。
根据我的经验,对方最可能的反应有四种:
第一种是接受,那么策略方向就定格在深度价值+超跌反转,后续可以做更长期的回测,优化参数细节。
第二种是认为“太传统”,需要增加成长因子、产业趋势标签,把选股方向转向新兴行业。
第三种是认为“还不够超跌”,提高回撤阈值至40%以上,或加入超跌动量指标,追求更深的安全边际。
第四种是询问资金面,需要接入主力资金流向数据,验证股票是否有机构资金关注。
而根据A股个人投资者的普遍偏好,以及对方一开始就强调“超跌排名靠前”的逆向风格,我预判他大概率会偏向第二种,也就是不满意传统行业,想要更有想象空间的标的。当然,也有可能他会追加资金面的要求,毕竟“有没有资金买”是所有交易者都关心的问题。
不复权的价格会导致回撤计算严重失真。例如,某股10送10后价格减半,不复权回撤显示-50%,但实际复权回撤可能只有-10%。误把除权当成超跌,是新手最常见的错误之一。
这里补充一下前复权和后复权的区别:前复权是以当前价格为基准,把历史价格按除权比例调整,适合计算历史回撤和收益率;后复权是以发行价为基准,适合计算累计收益。选股和回测场景下,统一使用前复权价格是行业标准。
def safe_retrace(price_series, current_price):
"""计算年内回撤,处理空值和除权"""
if price_series.empty:
return None
# 使用前复权价格(已在数据获取时处理)
high_252 = price_series.rolling(252).max()
if high_252.iloc[-1] == 0:
return None
retrace = (current_price - high_252.iloc[-1]) / high_252.iloc[-1]
return retrace
写代码的时候一定要做异常处理,比如价格序列为空、最高价为0这些边界情况,否则程序很容易因为某只股票数据缺失就崩溃。量化系统的稳定性,90%取决于异常处理做得够不够。
上市不足252个交易日的次新股:不要硬套252日高点,用实际交易日数计算高点,或者直接剔除上市不满一年的次新股,因为次新股没有足够的历史数据,超跌逻辑不适用。
近期有重大资产重组的股票:建议人工复核,因为价格连续性被破坏,之前的高点没有参考意义。
ST摘帽的股票:摘帽前后的估值逻辑完全不同,不能直接用过去一年的价格算回撤。
这些边界情况的处理逻辑,在a-sig.com的因子计算引擎中都已经内置,所有指标都会自动处理除权、次新股、重组等特殊情况,输出的结果直接可用,不用自己做数据清洗。
下一章将揭示,对方的真实反馈是第二种——“老师,我觉得太传统了”。这个反馈将引导我们进入A股的未来产业赛道:AI算力、半导体、新能源。
本章内容节选自原创量化书籍《因子会说谎》,更多数据清洗与因子计算的实操细节,可登录intoquant.com查阅完整内容。
⚠️ 风险提示:本书内容仅为量化研究与知识分享,不构成任何投资建议。套利交易存在基差、费率、流动性、平台与极端行情等风险,历史表现不代表未来收益。投资有风险,入市需谨慎,请自主决策、量力而行。
💡 键盘 ←/→ 翻章 · T 键切换目录