第四章:多因子合成——从单因子到组合的艺术

说实话,多因子合成这一步,是很多量化团队的分水岭。

单因子研究做得再好,如果不会合成,就像手里有一堆好食材却不会做菜。我见过不少团队,单因子IC都挺漂亮,一组合起来反而跑不过基准。问题出在哪?就在合成方法上。

今天咱们就把五种主流方法掰开揉碎讲清楚。等权、市值加权、ICIR加权、PCA降维、因子正交化——每种我都踩过坑,咱们边讲边避雷。

4.1 等权加权法——最简单的往往最稳健

等权加权,说白了就是给每个因子相同的权重。比如你有5个因子,每个权重就是20%。

你可能会问:「这也太简单了吧?」

嗯,我刚开始做量化时也这么想。但后来发现,在因子相关性较高的情况下,等权加权反而比很多复杂方法更稳定。为什么?因为它不会过度依赖某个因子,天然分散风险。

适用场景:因子数量较少(3-8个),且因子间相关性较高时,等权加权是个不错的起点。
import pandas as pd
import numpy as np

def equal_weight_synthesis(factor_df):
    """
    等权加权合成
    factor_df: DataFrame, 每列为一个因子,行为股票
    """
    # 先做横截面标准化
    zscore_df = factor_df.apply(lambda x: (x - x.mean()) / x.std())
    # 等权合成
    composite = zscore_df.mean(axis=1)
    return composite
我的经验:等权加权适合做基准模型。我一般先用它跑一遍,看看因子组合的底线在哪。如果等权加权都跑不好,那复杂方法大概率也救不了。

4.2 市值加权法——让大股票多说话

市值加权,就是按股票市值大小分配权重。市值大的股票,在因子合成中影响力更大。

这个方法在A股有个天然问题——大市值股票往往被机构重仓,因子收益已经被充分挖掘。我曾经用市值加权合成过一组反转因子,结果回测曲线惨不忍睹。后来发现,小市值股票的反转效应更强,但市值加权把它们压得太低了。

def market_cap_weighted_synthesis(factor_df, market_cap):
    """
    市值加权合成
    market_cap: Series, 每只股票的市值
    """
    # 市值归一化作为权重
    weights = market_cap / market_cap.sum()
    # 因子标准化
    zscore_df = factor_df.apply(lambda x: (x - x.mean()) / x.std())
    # 加权合成
    composite = (zscore_df.multiply(weights, axis=0)).sum(axis=1)
    return composite
注意:市值加权容易导致因子暴露集中在少数大市值股票上。如果你做的是小盘股策略,慎用。

4.3 ICIR加权法——让预测能力强的因子多说话

ICIR加权,是我个人最常用的方法之一。它结合了IC(信息系数)和IR(信息比率),本质上是「用历史表现来分配权重」。

具体来说:IC衡量因子与未来收益的相关性,IR衡量这个相关性的稳定性。ICIR = IC均值 / IC标准差。ICIR越高,说明因子预测能力越强且越稳定。

def icir_weighted_synthesis(factor_df, forward_returns):
    """
    ICIR加权合成
    forward_returns: DataFrame, 未来N日收益
    """
    weights = {}
    for col in factor_df.columns:
        # 计算每日IC
        daily_ic = factor_df[col].rolling(20).corr(forward_returns)
        # ICIR = IC均值 / IC标准差
        ic_mean = daily_ic.mean()
        ic_std = daily_ic.std()
        weights[col] = ic_mean / ic_std if ic_std != 0 else 0
    
    # 归一化权重
    total = sum(weights.values())
    weights = {k: v/total for k, v in weights.items()}
    
    # 合成
    zscore_df = factor_df.apply(lambda x: (x - x.mean()) / x.std())
    composite = sum(zscore_df[col] * weights[col] for col in factor_df.columns)
    return composite
避坑指南:我曾经用ICIR加权时,发现某个因子ICIR特别高,结果给它分配了40%的权重。后来回测发现,这个因子只是运气好,在样本内表现好,样本外直接崩了。建议用滚动窗口计算ICIR,比如用过去12个月的数据,避免过拟合。

4.4 主成分分析(PCA)降维——从10个因子到3个主成分

PCA降维,说白了就是把多个因子压缩成少数几个「主成分」。这些主成分是原始因子的线性组合,彼此正交(不相关)。

我刚开始用PCA时犯过一个错误:直接对所有因子做PCA,然后取前几个主成分。结果发现第一个主成分解释方差超过60%,但它其实是个「市场因子」,把所有股票都拉在一起了。这导致选股效果很差。

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

def pca_synthesis(factor_df, n_components=3):
    """
    PCA降维合成
    n_components: 保留的主成分数量
    """
    # 标准化
    scaler = StandardScaler()
    scaled_data = scaler.fit_transform(factor_df)
    
    # PCA
    pca = PCA(n_components=n_components)
    pca_data = pca.fit_transform(scaled_data)
    
    # 用解释方差比作为权重,合成一个综合得分
    explained_ratio = pca.explained_variance_ratio_
    composite = pca_data @ explained_ratio
    
    return composite, pca
关键点:PCA降维后,每个主成分都有明确的含义吗?不一定。我建议对主成分做因子载荷分析,看看每个主成分主要代表了哪些原始因子。如果第一个主成分把所有因子都正相关地加载在一起,那它可能就是个「市场噪音」。

4.5 因子正交化处理——消除冗余,保留纯净信号

因子正交化,是我认为最「硬核」的合成方法。它的核心思想是:把因子之间的相关性剥离掉,让每个因子只贡献「独特」的信息。

举个例子:你有一个估值因子(PE)和一个盈利因子(ROE)。它们天然相关——高ROE的公司往往PE也高。如果不做正交化,这两个因子会互相「抢功劳」,导致组合后的信号有冗余。

import statsmodels.api as sm

def factor_orthogonalization(factor_df, target_factor):
    """
    因子正交化:将target_factor对其他因子做回归,取残差
    """
    X = factor_df.drop(columns=[target_factor])
    X = sm.add_constant(X)
    y = factor_df[target_factor]
    
    model = sm.OLS(y, X).fit()
    # 残差就是正交化后的纯净因子
    orthogonal_factor = model.resid
    return orthogonal_factor
注意:正交化不是万能的。我见过有人把所有因子两两正交化,结果每个因子都被「削」得面目全非,失去了预测能力。建议只对相关性超过0.6的因子做正交化,相关性低的保持原样。

4.6 五种方法对比——怎么选?

方法 优点 缺点 我的推荐场景
等权加权 简单、稳健、不易过拟合 忽略因子质量差异 新手入门、因子数量少
市值加权 贴近市场真实结构 小盘股被压制 大盘股策略
ICIR加权 动态调整、自适应 容易过拟合 成熟因子库、有足够历史数据
PCA降维 降维、去噪 主成分含义不明确 因子数量多(>10个)
因子正交化 消除冗余、信号纯净 可能过度削除信号 因子间高度相关

4.7 知识体系图——多因子合成的完整流程

多因子合成知识体系 原始因子矩阵 标准化 / 去极值 / 中性化 等权加权 市值加权 ICIR加权 PCA降维 正交化 合成因子得分

这张图把整个流程串起来了。从原始因子出发,经过标准化预处理,然后选择一种或多种合成方法,最终得到合成因子得分。我个人建议:先用等权加权跑通流程,再逐步尝试复杂方法。

最后说一句:没有最好的方法,只有最适合你数据的方法。我一般会同时跑等权、ICIR加权和PCA三种,然后对比它们的IC序列和分层回测结果。哪个稳定用哪个,不盲目追求复杂度。

专注资料整理