一、多因子选股模型:从理论到实战

多因子选股模型,说白了就是给股票打分。

你想想看,一只股票好不好,不能光看市盈率,也不能只看ROE。得综合多个维度来评估。这就是多因子的核心思想——把各种能预测收益的特征组合起来,形成一个打分系统。

我个人习惯把因子分成几大类:

  • 估值因子:PE、PB、PS、PCF 这些传统指标
  • 成长因子:营收增速、利润增速、ROE 变化趋势
  • 质量因子:毛利率、净利率、资产负债率、现金流质量
  • 动量因子:过去1个月、3个月、6个月的收益表现
  • 情绪因子:换手率、波动率、分析师预期调整

我在项目中遇到过一个问题:刚开始做多因子模型时,恨不得把所有能想到的因子都塞进去。结果呢?过拟合严重,实盘一跑就崩。后来我学乖了——因子不是越多越好,关键是有效且稳定。

核心原则:因子之间要低相关,每个因子要有明确的逻辑支撑,不能光靠数据挖掘。

二、因子构建与计算:把想法变成代码

因子构建,说白了就是把你的投资逻辑量化出来。

举个例子,你想捕捉「低估值」这个逻辑。那怎么量化?可以用市盈率的倒数(E/P),也可以用市净率的倒数(B/P)。但要注意,不同行业的估值中枢不一样。银行股PE 5倍算正常,科技股PE 50倍也算正常。所以我在构建因子时,通常会做行业中性化处理。

下面是我常用的因子计算框架:

import pandas as pd
import numpy as np
from scipy import stats

def calc_ep_factor(df):
    """
    计算E/P因子(市盈率倒数)
    输入:df 包含 market_cap, net_profit 字段
    """
    # 避免负值干扰
    df['ep'] = df['net_profit'] / df['market_cap']
    
    # 行业中性化处理
    df['ep_neutral'] = df.groupby('industry')['ep'].transform(
        lambda x: (x - x.mean()) / x.std()
    )
    
    # 市值中性化(可选)
    df['ep_resid'] = stats.linregress(
        df['log_market_cap'], df['ep_neutral']
    ).resid
    
    return df['ep_resid']

嗯,这里要注意几个坑:

  • 极端值处理:我一般用MAD方法(中位数绝对偏差)去极值,比3σ更稳健
  • 缺失值处理:千万别直接dropna,会引入生存偏差。我习惯用行业均值填充
  • 频率对齐:日频因子和月频因子不能混用,要统一到同一个调仓频率

我的小技巧:因子构建完成后,先跑一遍描述性统计。看看均值、标准差、偏度、峰度。如果某个因子的偏度绝对值大于2,那大概率有异常值没处理好。

三、因子有效性检验:IC/IR 分析

因子构建完了,怎么知道它有没有用?这就轮到IC和IR上场了。

3.1 IC(信息系数)

IC衡量的是因子值和未来收益之间的相关性。简单说:因子值高的股票,未来是不是涨得更好?

IC的计算方式有两种:

  • Spearman秩相关系数:我比较推荐这个,因为它对异常值不敏感
  • Pearson相关系数:要求数据正态分布,实际中很少满足
def calc_ic(factor_values, forward_returns):
    """
    计算截面IC
    factor_values: 某期所有股票的因子值
    forward_returns: 对应股票的未来收益
    """
    # 使用Spearman秩相关
    ic, p_value = stats.spearmanr(factor_values, forward_returns)
    return ic, p_value

# 计算时间序列IC
def calc_ic_series(factor_df, return_df):
    """
    计算多期IC序列
    """
    ic_list = []
    for date in factor_df.index:
        ic, _ = calc_ic(
            factor_df.loc[date], 
            return_df.loc[date]
        )
        ic_list.append(ic)
    return pd.Series(ic_list, index=factor_df.index)

3.2 IR(信息比率)

IR = IC的均值 / IC的标准差。它衡量的是因子稳定性的指标。

举个例子:

  • 因子A:IC均值0.05,标准差0.02 → IR = 2.5(优秀)
  • 因子B:IC均值0.08,标准差0.10 → IR = 0.8(不稳定)

因子A虽然IC均值低一些,但非常稳定。因子B偶尔表现很好,但波动太大。实盘中我更倾向于因子A。为什么?因为稳定的因子更容易做仓位管理和风险控制。

我曾经踩过的坑:只看IC均值,忽略了IR。结果选了个IC均值0.12但IR只有0.5的因子。实盘跑了一个月,前两周赚得飞起,后两周亏回去还倒贴。从那以后,我给自己定了个规矩:IR低于1的因子,坚决不上实盘。

3.3 分层回测

除了IC/IR,我还会做分层回测。把股票按因子值分成10组,看每组未来的平均收益。如果第1组(因子值最高)的收益明显高于第10组(因子值最低),而且呈现单调性,那这个因子就靠谱。

def layer_backtest(factor_df, return_df, n_layers=10):
    """
    分层回测
    """
    results = {}
    for date in factor_df.index:
        # 按因子值分组
        factor_series = factor_df.loc[date]
        labels = pd.qcut(factor_series, n_layers, labels=False)
        
        # 计算每组平均收益
        group_returns = return_df.loc[date].groupby(labels).mean()
        results[date] = group_returns
    
    return pd.DataFrame(results).T

四、知识体系总览

说了这么多,我把整个多因子选股的核心逻辑画了张图,方便你理解:

多因子选股模型核心逻辑 原始数据 因子构建与计算 估值因子 成长因子 质量因子 动量因子 情绪因子 因子有效性检验 IC分析 IR分析 分层回测 有效因子组合

五、实战中的几个关键点

最后,分享几个我在实战中总结的经验:

  1. 因子要定期重检:市场在变,因子的有效性也会衰减。我每季度会重新跑一遍IC/IR,把失效的因子剔除。
  2. 警惕数据挖掘偏差:你测试了100个因子,总有几个IC显著。但这可能是巧合。我习惯用滚动窗口验证——用过去3年的数据选因子,用未来1年的数据验证。
  3. 因子组合要分散:别把所有仓位押在一个因子上。我一般选5-8个低相关的因子,等权或按IR加权组合。
  4. 别忘了交易成本:有些因子换手率很高,看起来IC不错,但扣掉手续费就亏了。我每次回测都会加上千分之二的交易成本。

一句话总结:多因子选股不是堆砌指标,而是找到那些逻辑清晰、统计显著、稳定有效的因子,然后用纪律性的方式组合起来。

专注资料整理