因子工程基础:因子定义、常见因子分类与计算实现

做量化投资这几年,我越来越觉得因子工程才是策略的灵魂。很多人一上来就搞机器学习模型,结果数据质量不行,因子逻辑混乱,模型再花哨也白搭。说白了,因子工程就是把你对市场的理解,翻译成计算机能算的数学表达式。

今天咱们就聊聊因子工程最基础的东西——因子是什么、怎么分类、怎么算。嗯,这部分内容虽然基础,但我在项目中踩过的坑可不少,后面会一一说到。

1. 因子到底是什么?

因子,简单说就是一个能预测股票未来收益的特征变量。它可以是价格数据算出来的,也可以是财务数据加工过的,甚至可以是新闻情绪、舆情热度这类非结构化数据。

我习惯把因子理解成「信号的量化表达」。你想想看,如果一个指标能区分出未来涨的股票和跌的股票,那它就是有价值的因子。

因子的三个核心属性:

  • 有效性:因子对未来收益有显著预测能力
  • 稳定性:因子在不同时间窗口、不同市场环境下表现一致
  • 独立性:因子与其他因子之间的相关性低,避免冗余

我在做第一个多因子模型时,就犯过一个低级错误——把两个高度相关的动量因子同时放进去,结果模型过拟合得一塌糊涂。后来才明白,因子不是越多越好,质量比数量重要得多。

2. 常见因子分类

因子的分类方式很多,我个人习惯按逻辑来源分成四大类:动量、反转、价值、质量。这四类基本覆盖了市场上90%以上的主流因子。

因子类别 核心逻辑 典型因子 适用场景
动量因子 强者恒强,趋势延续 过去N日收益率、均线乖离率 趋势行情、高流动性市场
反转因子 物极必反,均值回归 过去N日涨跌幅、RSI极端值 震荡行情、小市值股票
价值因子 价格低于内在价值 PE、PB、PS、股息率 低估值修复行情
质量因子 公司基本面优秀 ROE、毛利率、资产负债率 长期持有、防御型策略

3. 动量因子与反转因子

这两个因子经常被放在一起讨论,因为它们本质上是一枚硬币的两面。动量因子认为趋势会延续,反转因子认为趋势会回归。

动量因子的计算逻辑:

最简单的动量因子就是过去N日的累计收益率。比如过去20个交易日的收益率,就是最常见的短期动量因子。

# 动量因子:过去20日收益率
def momentum_factor(df, window=20):
    """
    df: 包含收盘价的DataFrame
    window: 回溯窗口
    """
    df['momentum'] = df['close'] / df['close'].shift(window) - 1
    return df

反转因子的计算逻辑:

反转因子正好相反,它关注的是过去一段时间涨得太多或跌得太狠的股票。我常用的一个反转因子是「过去5日涨跌幅的相反数」。

# 反转因子:过去5日涨跌幅取负值
def reversal_factor(df, window=5):
    df['reversal'] = -(df['close'] / df['close'].shift(window) - 1)
    return df

我的经验:动量因子在A股的有效期通常不超过3个月。我曾经用60日动量做策略,回测效果很好,但实盘时正好遇到风格切换,亏得挺惨。后来我改用20日动量+5日反转的组合,效果稳定多了。

4. 价值因子

价值因子是基本面量化最经典的领域。它的核心思想很简单:买便宜的股票。

但「便宜」怎么定义?我常用的几个价值因子:

  • 市盈率倒数(E/P):比直接用PE更符合因子逻辑,因为数值越大代表越便宜
  • 市净率倒数(B/P):适合银行、地产等重资产行业
  • 股息率(D/P):分红高的公司通常估值偏低
  • 市销率倒数(S/P):适合亏损但营收增长快的公司
# 价值因子:市盈率倒数
def value_factor_ep(df):
    # 假设df包含pe_ttm字段
    df['EP'] = 1 / df['pe_ttm']
    # 处理极端值:将超过3倍标准差的值截断
    mean_ep = df['EP'].mean()
    std_ep = df['EP'].std()
    df['EP'] = df['EP'].clip(mean_ep - 3*std_ep, mean_ep + 3*std_ep)
    return df

注意:价值因子最大的坑是「价值陷阱」。有些股票PE很低,不是因为便宜,而是因为基本面在恶化。我曾经踩过这个坑——一只银行股PE只有4倍,我重仓买入,结果半年后跌了30%。后来我学会了在价值因子中加入质量因子做过滤。

5. 质量因子

质量因子衡量的是公司的「好」——盈利能力、成长性、财务健康度。它和价值因子是绝配,一个负责找便宜的,一个负责找好的。

我常用的质量因子组合:

维度 指标 计算公式
盈利能力 ROE 净利润 / 净资产
盈利质量 毛利率 (营收 - 成本) / 营收
财务安全 资产负债率 总负债 / 总资产(取负值)
成长性 营收增长率 同比营收增速
# 质量因子:综合质量得分
def quality_factor(df):
    # 标准化处理
    df['ROE_z'] = (df['roe'] - df['roe'].mean()) / df['roe'].std()
    df['gross_margin_z'] = (df['gross_margin'] - df['gross_margin'].mean()) / df['gross_margin'].std()
    # 资产负债率取负值(负债越低越好)
    df['debt_ratio_z'] = -(df['debt_ratio'] - df['debt_ratio'].mean()) / df['debt_ratio'].std()
    # 综合得分:等权相加
    df['quality_score'] = (df['ROE_z'] + df['gross_margin_z'] + df['debt_ratio_z']) / 3
    return df

6. 因子计算的通用框架

不管什么因子,计算流程都差不多。我总结了一个通用框架,你直接套用就行:

  1. 数据准备:获取原始数据(价格、财务、另类数据)
  2. 因子计算:按公式算出因子值
  3. 异常处理:去极值、填充缺失值
  4. 标准化:将因子值映射到统一尺度(如Z-score)
  5. 中性化:剔除行业、市值等干扰因素
# 因子计算通用流程
def factor_pipeline(df, factor_func, **kwargs):
    """
    df: 原始数据
    factor_func: 因子计算函数
    """
    # 1. 计算因子
    df = factor_func(df, **kwargs)
    
    # 2. 去极值(MAD方法)
    median = df['factor'].median()
    mad = (df['factor'] - median).abs().median()
    df['factor'] = df['factor'].clip(median - 5*mad, median + 5*mad)
    
    # 3. 标准化
    df['factor_z'] = (df['factor'] - df['factor'].mean()) / df['factor'].std()
    
    return df

避坑指南:我曾经在因子标准化时忘记处理缺失值,结果导致整个因子分布偏移。后来我养成了一个习惯——在标准化之前先检查缺失值比例,超过30%的因子直接废弃。

7. 因子工程的知识体系

下面这张图是我自己整理的因子工程核心逻辑,你看一眼就能明白整体框架:

因子工程核心知识体系 因子定义 动量因子 反转因子 价值因子 质量因子 过去N日收益率 均线乖离率 过去N日涨跌幅 RSI极端值 PE倒数、PB倒数 股息率、市销率 ROE、毛利率 资产负债率 数据准备 → 因子计算 → 异常处理 → 标准化 → 中性化 高质量因子矩阵

这张图把因子工程的脉络理得很清楚。从因子定义出发,到四大分类,再到具体因子和计算流程,最后输出高质量因子矩阵。你每次做因子研究时,都可以拿这张图对照一下,看看自己卡在哪一步。

好了,因子工程的基础内容就聊到这儿。这部分虽然看起来简单,但真正做好需要大量实践。我建议你从最简单的动量因子开始,跑一遍完整的计算流程,慢慢积累经验。

专注资料整理