第三章 经典风格因子(上):价值、规模与盈利

各位同学,今天我们来聊聊因子投资里最经典的三个风格因子。说实话,这三个因子就像武术里的马步冲拳——看着简单,但真正练好了,能解决大部分问题。

我刚开始做量化那会儿,也迷恋过各种花哨的复杂模型。后来发现,真正稳定赚钱的策略,底层往往就是这几个老家伙在起作用。嗯,咱们一个一个来看。

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普遍高,科技股普遍低。如果你不做行业中性化处理,选出来的全是银行股。

所以,我建议的做法是:

  1. 计算每只股票的BM值
  2. 按行业分组,在每个行业内做z-score标准化
  3. 用标准化后的值作为因子暴露

代码实现也很简单:

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股的大盘股涨得飞起,小盘股反而跌成狗。很多做小市值策略的朋友那几年亏得很惨。

为什么会这样?我个人认为有两个原因:

  • 因子拥挤:太多人知道小盘股有效,都来买,把超额收益买没了
  • 市场结构变化:机构投资者占比提升,他们更偏好流动性好的大盘股

那规模因子还能不能用?我的答案是:能用,但要换个思路。

我建议的做法是:

  1. 不要直接用市值排序,而是用市值对数的倒数
  2. 做市值分层处理,比如把股票分成10组,取最小市值组的平均收益
  3. 结合其他因子一起用,比如小市值+高盈利

代码示例:

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 三个因子的组合使用

好了,三个因子都讲完了。现在的问题是:怎么把它们组合起来?

我见过很多新手直接等权加权,然后跑回测。结果发现收益还不如单因子。为什么?因为因子之间有相关性,简单加权会放大重叠部分的信息。

我建议的做法是:

  1. 先对每个因子做行业中性化和市值中性化
  2. 计算因子之间的相关系数矩阵
  3. 用PCA或者回归方法做正交化处理
  4. 最后用等权或波动率倒数加权

下面这张图展示了三个因子的组合逻辑:

三因子组合框架 价值因子 BM, E/P 规模因子 对数市值 盈利因子 ROE, ROA 预处理:行业中性化 + 市值中性化 + 异常值处理 正交化处理:PCA / 回归残差 多因子组合:等权 / 波动率倒数加权

嗯,这张图把整个流程串起来了。你可能会问,正交化之后因子收益会不会变差?说实话,短期看可能会,但长期看,正交化后的因子组合更稳健,回撤更小。

最后说一句,这三个因子只是起点。真正的高手,会在这些经典因子的基础上,结合自己的理解做改进。比如我见过有人把价值因子拆成「账面价值」和「市场情绪」两部分,效果出奇的好。

好了,今天就到这里。记住,因子投资不是找圣杯,而是理解市场运行的规律。这三个因子,够你研究好一阵子了。