第四章 多因子模型入门:因子投资思想、常见因子分类与单因子测试框架

各位同学,欢迎来到多因子模型的第一课。

说实话,因子投资这个概念,刚入行的时候我也觉得挺玄乎的。什么「因子」啊、「暴露」啊,听着像物理课。但干久了你会发现,它其实就是一套系统化的选股逻辑——把那些能赚钱的规律,用数学语言描述出来。

4.1 因子投资的核心思想

因子投资的本质,说白了就是「找规律,做组合」。

我们不去猜哪只股票明天会涨,而是去找那些长期来看能带来超额收益的「共性特征」。比如:便宜的股票是不是比贵的股票表现好?过去涨得好的股票,接下来是不是还能涨?

这些「共性特征」,就是因子。

核心公式:

预期收益 = 无风险收益 + Σ(因子暴露 × 因子收益)

你想想看,这个公式其实跟做菜很像——因子就是调料,因子暴露就是放多少,因子收益就是调料带来的味道提升。

我个人习惯把因子投资拆成三步:

  1. 找因子——发现能赚钱的规律
  2. 测因子——验证这个规律是不是真的有效
  3. 用因子——把多个因子组合起来做选股

嗯,这里要注意:不是所有看起来有效的规律都能用。我在项目中遇到过很多「回测漂亮、实盘拉胯」的因子,原因后面会讲。

4.2 常见因子分类

因子的分类方式很多,我按最经典的三大类来讲:价值、动量、质量。

4.2.1 价值因子

价值因子是最古老的因子之一。它的逻辑很简单:买便宜的股票。

常用的指标有:

  • 市盈率(PE)——越低越便宜
  • 市净率(PB)——破净股往往被低估
  • 股息率——高分红说明公司现金流好

避坑指南:我曾经用PE选股,结果选了一堆银行股。银行PE确实低,但增长也慢。后来我加了「PE分位数」这个条件,只选那些处于历史低位的股票,效果好了不少。

4.2.2 动量因子

动量因子的逻辑是「强者恒强,弱者恒弱」。

常用的有:

  • 过去N个月收益率——比如过去12个月涨得好的股票
  • 均线乖离率——股价偏离均线的程度
  • RSI指标——超买超卖信号

但动量因子有个坑:它容易在震荡市里反复打脸。我记得2018年那会儿,动量因子回撤了将近30%,很多同行都扛不住砍掉了。

4.2.3 质量因子

质量因子关注的是公司本身的「质地」。

指标 含义 计算方式
ROE 净资产收益率 净利润 / 净资产
毛利率 产品竞争力 (收入-成本) / 收入
资产负债率 财务风险 总负债 / 总资产

质量因子有个好处:它跟其他因子的相关性低。你想想看,便宜的股票不一定质量好,质量好的股票不一定便宜。所以把质量因子跟价值因子搭配,往往能起到分散风险的作用。

4.3 因子数据处理

拿到原始因子数据后,不能直接用。为什么?因为数据里有噪音、有极端值、还有各种「脏东西」。

4.3.1 去极值

去极值就是处理那些离谱的数据点。比如某只股票PE突然变成1000倍,这明显是异常。

常用的方法有两种:

  • MAD法:用中位数和绝对偏差来识别异常值
  • 百分位法:直接砍掉上下1%或5%的数据
def winsorize_series(s, limits=[0.01, 0.01]):
    """
    去极值:用百分位法
    """
    lower = s.quantile(limits[0])
    upper = s.quantile(1 - limits[1])
    return s.clip(lower, upper)

# 举个例子
import pandas as pd
pe_series = pd.Series([10, 12, 15, 1000, 11, 13])
cleaned = winsorize_series(pe_series)
print(cleaned)
# 输出:10, 12, 15, 15, 11, 13
# 那个1000被砍成了15

注意:去极值不是删除数据,而是把极端值拉到边界上。我曾经见过有人直接删掉异常值,结果导致样本量不均匀,回测结果严重失真。

4.3.2 标准化

标准化是为了让不同量纲的因子可以比较。比如PE的数值范围是0-100,而ROE是0-1,不标准化没法直接对比。

def standardize(s):
    """
    Z-score标准化
    """
    return (s - s.mean()) / s.std()

# 标准化后,所有因子的均值都是0,标准差都是1

4.3.3 中性化

中性化是消除因子中的「杂质」。比如市值大的公司PE普遍偏低,如果你直接用PE选股,选出来的可能都是大盘股,而不是真正的「便宜股」。

中性化的做法:把因子对市值、行业等变量做回归,取残差作为「纯净」的因子值。

import statsmodels.api as sm

def neutralize(factor, market_cap, industry_dummies):
    """
    对市值和行业做中性化
    """
    X = pd.concat([market_cap, industry_dummies], axis=1)
    X = sm.add_constant(X)
    model = sm.OLS(factor, X).fit()
    return model.resid  # 残差就是中性化后的因子

个人经验:中性化这一步,很多人会忽略。但我建议你一定要做。我2019年做过一个测试:同样的因子,中性化前后的IC值差了将近0.05,效果天差地别。

4.4 单因子测试框架

单因子测试,就是验证一个因子到底有没有用。我常用的框架分四步:

  1. 分层回测:把股票按因子值分成10组,看每组的表现
  2. IC分析:计算因子值与未来收益的相关性
  3. 多空组合:做多因子值最高的组,做空最低的组
  4. 稳定性检验:看因子在不同市场环境下的表现

下面是一个简单的分层回测代码:

def factor_backtest(factor, returns, n_groups=10):
    """
    单因子分层回测
    factor: 因子值
    returns: 未来一期收益
    """
    # 按因子值分组
    groups = pd.qcut(factor, n_groups, labels=False)
    
    # 计算每组平均收益
    group_returns = returns.groupby(groups).mean()
    
    # 计算多空收益
    long_short = group_returns.iloc[-1] - group_returns.iloc[0]
    
    return group_returns, long_short

# 假设我们有因子数据和收益数据
# group_ret, ls_ret = factor_backtest(pe_factor, next_month_returns)
# print(f"多空收益: {ls_ret:.4f}")

嗯,这里有个关键点:单因子测试的样本量要足够大。我一般要求至少3年的数据,覆盖完整的牛熊周期。否则你测出来的结果,可能只是运气好。

4.5 本章知识体系

为了让你更直观地理解本章的内容,我画了一张流程图:

多因子模型入门 - 知识体系 因子投资思想 常见因子分类 因子数据处理 单因子测试框架 价值因子 动量因子 质量因子 去极值 标准化 中性化 分层回测 IC分析 多空组合 核心目标:找到稳定有效的选股因子

这张图把本章的核心内容串起来了。你想想看,从因子思想出发,我们知道了要「找规律」;然后通过因子分类,我们知道了「找什么规律」;接着通过数据处理,我们学会了「怎么把数据洗干净」;最后用测试框架,我们验证「这个规律到底行不行」。

好了,这一章的内容就到这里。因子投资的门算是打开了,后面我们会一步步深入,把每个环节都吃透。


公众号:蓝海资料掘金营,微信deep3321