因子构建与筛选:从数据到信号的实战之路

因子构建,说白了就是给市场做「体检」。

我刚开始做量化那会儿,总觉得因子越多越好。后来被市场狠狠教育过——因子多了,噪音也多了。今天我们就聊聊,怎么从一堆原始数据里,提炼出真正有用的信号。

常见动量因子:市场里的「惯性」

动量因子,本质上是利用市场的惯性效应。涨的还会涨,跌的还会跌——至少在短期内是这样。

我个人习惯把动量因子分成三类:

  • 价格动量:过去N天的收益率。比如过去20天涨了5%,这就是一个信号。
  • 成交量动量:过去N天的成交量变化。量在价先,这个道理你懂的。
  • 复合动量:价格和成交量的组合。比如「价涨量增」就是典型的强势信号。

我在项目中遇到过一个问题:单纯用过去20天收益率做因子,结果在震荡市里频繁打脸。后来我加入了成交量确认,效果好了不少。

下面是一个简单的动量因子计算代码:

import pandas as pd
import numpy as np

def calc_momentum_factor(price_df, window=20):
    """
    计算价格动量因子
    price_df: DataFrame, 每列是一只股票的收盘价
    window: 回看窗口
    """
    # 计算过去N天的收益率
    ret = price_df.pct_change(window)
    
    # 标准化处理,让因子更稳定
    factor = (ret - ret.mean()) / ret.std()
    
    return factor
小技巧:窗口参数别死板。我一般会同时算5天、20天、60天三个窗口,然后看哪个效果最好。

因子IC分析:检验因子的「预测力」

因子建好了,怎么知道它有没有用?IC(信息系数)就是干这个的。

IC的计算很简单:每个时间点上,算因子值和未来收益的相关系数。IC越高,说明因子预测能力越强。

我一般关注三个指标:

指标 含义 经验阈值
IC均值 因子整体的预测能力 绝对值 > 0.02 算不错
IC标准差 因子预测的稳定性 越小越好
ICIR IC均值除以标准差 > 0.5 算优秀

举个例子:

def calc_ic(factor_series, forward_returns):
    """
    计算截面IC
    factor_series: 当前时点的因子值
    forward_returns: 未来N天的收益率
    """
    from scipy.stats import spearmanr
    
    # 去掉缺失值
    mask = factor_series.notna() & forward_returns.notna()
    
    # 计算秩相关系数
    ic, p_value = spearmanr(factor_series[mask], forward_returns[mask])
    
    return ic, p_value
注意:IC高不代表一定能赚钱。我曾经遇到一个因子,IC高达0.08,但实盘就是亏钱。为什么?因为它的IC不稳定,有时候正有时候负。所以一定要看IC的稳定性。

因子收益率分析:多空组合的「真金白银」

IC是理论值,因子收益率才是真金白银。

做法很简单:每个月按因子值把股票分成10组,做多最高组,做空最低组,看看这个多空组合能赚多少钱。

我习惯看这几个指标:

  • 年化收益率:多空组合一年能赚多少
  • 夏普比率:收益风险比,一般要大于1
  • 最大回撤:最惨的时候亏多少
  • 胜率:赚钱月份占比

我记得有一次,一个因子的年化收益率高达15%,但最大回撤超过30%。这种因子你敢用吗?反正我不敢。

def factor_return_analysis(factor_df, return_df, groups=10):
    """
    因子收益率分析
    factor_df: 因子值矩阵
    return_df: 收益率矩阵
    """
    # 按因子值分组
    ranks = factor_df.rank(axis=1, pct=True)
    groups_labels = (ranks * groups).astype(int).clip(0, groups-1)
    
    # 计算每组平均收益
    group_returns = {}
    for g in range(groups):
        mask = groups_labels == g
        group_returns[g] = (return_df * mask).sum(axis=1) / mask.sum(axis=1)
    
    # 多空组合收益
    long_short = group_returns[groups-1] - group_returns[0]
    
    return long_short

因子相关性控制:别让因子「互相打架」

因子多了,难免有相关性。比如「过去20天收益率」和「过去60天收益率」,相关性肯定高。

因子相关性高有什么问题?

  • 组合后效果会打折扣
  • 容易过拟合
  • 解释起来很麻烦

我一般设一个阈值:相关性超过0.7的因子,只保留一个。保留哪个?看IC和ICIR,哪个好留哪个。

下面是一个相关性矩阵的示例:

def check_factor_correlation(factor_list):
    """
    检查因子之间的相关性
    factor_list: 因子DataFrame的列表
    """
    # 合并所有因子
    all_factors = pd.concat(factor_list, axis=1)
    
    # 计算相关性矩阵
    corr_matrix = all_factors.corr()
    
    # 找出高相关对
    high_corr_pairs = []
    for i in range(len(corr_matrix.columns)):
        for j in range(i+1, len(corr_matrix.columns)):
            if abs(corr_matrix.iloc[i, j]) > 0.7:
                high_corr_pairs.append(
                    (corr_matrix.columns[i], 
                     corr_matrix.columns[j], 
                     corr_matrix.iloc[i, j])
                )
    
    return corr_matrix, high_corr_pairs
核心原则:因子之间要「低相关、高IC」。相关性低,组合起来才能分散风险;IC高,每个因子都有贡献。

因子合成方法:把「好因子」变成「好策略」

因子筛选完了,怎么合成一个综合信号?

我常用的方法有三种:

  1. 等权合成:每个因子权重一样。简单粗暴,但效果往往不错。
  2. IC加权:IC高的因子给更高权重。逻辑上合理,但要注意IC的稳定性。
  3. 机器学习合成:用回归或树模型学习最优权重。效果最好,但容易过拟合。

我个人习惯先用等权合成做基准,然后尝试IC加权。如果效果明显更好,再考虑机器学习。

def combine_factors(factor_dict, method='equal'):
    """
    因子合成
    factor_dict: {'因子名': factor_series}
    method: 'equal', 'ic_weighted', 'ml'
    """
    factor_df = pd.DataFrame(factor_dict)
    
    if method == 'equal':
        # 等权合成
        combined = factor_df.mean(axis=1)
        
    elif method == 'ic_weighted':
        # IC加权,需要提前计算IC
        # 这里假设ic_dict已经算好
        weights = pd.Series(ic_dict)
        weights = weights / weights.sum()
        combined = factor_df.dot(weights)
    
    return combined
避坑指南:我曾经用机器学习合成因子,回测效果特别好,年化收益率30%+。结果实盘一跑,直接亏了两个月。后来发现是过拟合了。所以,机器学习合成一定要做严格的交叉验证。

本章知识体系

下面这张图,把因子构建与筛选的整个流程串起来了:

因子构建与筛选流程 原始数据 因子构建:动量因子、价值因子等 因子检验:IC分析 + 收益率分析 相关性控制:剔除高相关因子 因子合成:等权/IC加权/ML

嗯,因子构建与筛选,说白了就是「去粗取精」的过程。从海量数据里找到真正有用的信号,然后组合起来,形成稳定的策略。

记住一句话:因子不是越多越好,而是越精越好。一个IC稳定、逻辑清晰的因子,胜过十个花里胡哨的因子。

专注资料整理