第三章 经典风格因子(上):价值、规模与盈利
各位同学,今天我们来聊聊因子投资里最经典的三个风格因子。说实话,这三个因子就像武术里的马步冲拳——看着简单,但真正练好了,能解决大部分问题。
我刚开始做量化那会儿,也迷恋过各种花哨的复杂模型。后来发现,真正稳定赚钱的策略,底层往往就是这几个老家伙在起作用。嗯,咱们一个一个来看。
3.1 价值因子(Value)
价值因子,说白了就是买便宜的股票。但这里有个坑——什么叫「便宜」?
我个人习惯用两个指标来衡量:
- 账面市值比(Book-to-Market, BM):账面价值 / 总市值
- 盈利收益率(Earnings Yield, E/P):每股收益 / 股价
你可能会问,为什么不用市盈率(P/E)?其实E/P就是市盈率的倒数。我更喜欢用E/P,因为它在统计上更接近正态分布,做截面回归时方便很多。
核心逻辑:高BM或高E/P的股票,未来预期收益更高。这是Fama-French三因子模型的核心发现之一。
我在项目中遇到过一个问题:直接用原始BM值做因子,效果并不好。为什么?因为不同行业的BM值差异太大了。银行股的BM普遍高,科技股普遍低。如果你不做行业中性化处理,选出来的全是银行股。
所以,我建议的做法是:
- 计算每只股票的BM值
- 按行业分组,在每个行业内做z-score标准化
- 用标准化后的值作为因子暴露
代码实现也很简单:
import pandas as pd
import numpy as np
def calc_value_factor(df):
"""
df: 包含 'bm', 'industry' 列的DataFrame
返回行业中性化后的价值因子
"""
df['value_raw'] = df['bm']
# 行业中性化
df['value_factor'] = df.groupby('industry')['value_raw'].transform(
lambda x: (x - x.mean()) / x.std()
)
return df
小技巧:如果你用的是A股数据,建议用过去12个月的滚动BM值,而不是最新一期。因为A股财报披露有滞后,用最新数据容易引入未来信息偏差。
3.2 规模因子(Size)
规模因子,就是小盘股效应。小市值股票长期跑赢大市值股票——这个现象在各国市场都被验证过。
但这里有个问题:规模因子的收益在近十年明显衰减了。我记得2017年到2020年,A股的大盘股涨得飞起,小盘股反而跌成狗。很多做小市值策略的朋友那几年亏得很惨。
为什么会这样?我个人认为有两个原因:
- 因子拥挤:太多人知道小盘股有效,都来买,把超额收益买没了
- 市场结构变化:机构投资者占比提升,他们更偏好流动性好的大盘股
那规模因子还能不能用?我的答案是:能用,但要换个思路。
我建议的做法是:
- 不要直接用市值排序,而是用市值对数的倒数
- 做市值分层处理,比如把股票分成10组,取最小市值组的平均收益
- 结合其他因子一起用,比如小市值+高盈利
代码示例:
def calc_size_factor(df):
"""
df: 包含 'market_cap' 列
返回对数市值(负向)作为规模因子
"""
df['size_factor'] = -np.log(df['market_cap'])
# 也可以做市值分层
df['size_quantile'] = pd.qcut(df['market_cap'], 10, labels=False)
return df
避坑指南:我曾经用全市场最小市值组做策略,结果回测曲线漂亮得不行。但实盘一跑,发现根本买不到——小盘股流动性太差,滑点直接把收益吃光了。所以,做小市值策略一定要考虑流动性约束,至少剔除市值最小的那5%的股票。
3.3 盈利因子(Profitability)
盈利因子,就是买赚钱的公司。这个逻辑很直观——能持续赚钱的公司,股价长期应该上涨。
衡量盈利能力的指标有很多,我常用的有:
| 指标 | 计算公式 | 特点 |
|---|---|---|
| ROE | 净利润 / 股东权益 | 最常用,但容易被杠杆放大 |
| ROA | 净利润 / 总资产 | 剔除了杠杆影响,更稳健 |
| 毛利率 | (营收-成本) / 营收 | 反映定价能力,行业差异大 |
| F-Score | 综合9个财务指标 | Piotroski提出的综合评分 |
我个人习惯用ROE,但会做两个处理:
- 剔除金融行业:金融公司的ROE结构特殊,和其他行业不可比
- 用过去3年平均值:单一年份的ROE可能被操纵,取均值更可靠
你想想看,如果一个公司连续3年ROE都在15%以上,那它的盈利能力大概率是真实的。如果只是某一年突然飙到30%,第二年又跌回5%,那很可能是财务洗澡。
代码实现:
def calc_profitability_factor(df):
"""
df: 包含 'roe', 'industry' 列
返回行业中性化后的盈利因子
"""
# 剔除金融行业
df = df[df['industry'] != '金融']
# 计算3年滚动平均ROE
df['roe_avg'] = df.groupby('stock_id')['roe'].rolling(3).mean().values
# 行业中性化
df['profit_factor'] = df.groupby('industry')['roe_avg'].transform(
lambda x: (x - x.mean()) / x.std()
)
return df
重要提醒:盈利因子和价值因子经常是负相关的。高盈利的公司往往估值也高(低BM),低盈利的公司反而可能估值低(高BM)。所以,如果你同时用这两个因子,一定要做正交化处理,否则会互相抵消。
3.4 三个因子的组合使用
好了,三个因子都讲完了。现在的问题是:怎么把它们组合起来?
我见过很多新手直接等权加权,然后跑回测。结果发现收益还不如单因子。为什么?因为因子之间有相关性,简单加权会放大重叠部分的信息。
我建议的做法是:
- 先对每个因子做行业中性化和市值中性化
- 计算因子之间的相关系数矩阵
- 用PCA或者回归方法做正交化处理
- 最后用等权或波动率倒数加权
下面这张图展示了三个因子的组合逻辑:
嗯,这张图把整个流程串起来了。你可能会问,正交化之后因子收益会不会变差?说实话,短期看可能会,但长期看,正交化后的因子组合更稳健,回撤更小。
最后说一句,这三个因子只是起点。真正的高手,会在这些经典因子的基础上,结合自己的理解做改进。比如我见过有人把价值因子拆成「账面价值」和「市场情绪」两部分,效果出奇的好。
好了,今天就到这里。记住,因子投资不是找圣杯,而是理解市场运行的规律。这三个因子,够你研究好一阵子了。