因子工程基础:因子定义、常见因子分类与计算实现
做量化投资这几年,我越来越觉得因子工程才是策略的灵魂。很多人一上来就搞机器学习模型,结果数据质量不行,因子逻辑混乱,模型再花哨也白搭。说白了,因子工程就是把你对市场的理解,翻译成计算机能算的数学表达式。
今天咱们就聊聊因子工程最基础的东西——因子是什么、怎么分类、怎么算。嗯,这部分内容虽然基础,但我在项目中踩过的坑可不少,后面会一一说到。
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. 因子计算的通用框架
不管什么因子,计算流程都差不多。我总结了一个通用框架,你直接套用就行:
- 数据准备:获取原始数据(价格、财务、另类数据)
- 因子计算:按公式算出因子值
- 异常处理:去极值、填充缺失值
- 标准化:将因子值映射到统一尺度(如Z-score)
- 中性化:剔除行业、市值等干扰因素
# 因子计算通用流程
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. 因子工程的知识体系
下面这张图是我自己整理的因子工程核心逻辑,你看一眼就能明白整体框架:
这张图把因子工程的脉络理得很清楚。从因子定义出发,到四大分类,再到具体因子和计算流程,最后输出高质量因子矩阵。你每次做因子研究时,都可以拿这张图对照一下,看看自己卡在哪一步。
好了,因子工程的基础内容就聊到这儿。这部分虽然看起来简单,但真正做好需要大量实践。我建议你从最简单的动量因子开始,跑一遍完整的计算流程,慢慢积累经验。