六类常见风格因子:价值(Value)、规模(Size)、盈利(Profitability)、动量(Momentum)、低波动(Low Volatility)与质量(Quality)。
前三类构成 Fama-French 三因子模型的核心,在各国市场的长期实证中均表现出显著的风险溢价。后三类则更多反映市场定价偏差与投资者行为特征,在经验研究与资产配置实践中同样具有较高分析价值。后面测因子、做组合时,经常从这几类起步。
价值因子,说白了就是买便宜的股票。有两个常用指标来衡量:
金融学教科书里面介绍更多的是:
市盈率$P/E$是盈利收益率$E/P$的倒数。市净率$P/B$是账面市值比的倒数。实操上,建议用$E/P$和$B/M$,因为它在统计上更接近正态分布,做截面回归时方便很多。
高$B/M$或高$E/P$的股票,未来预期收益更高。这是Fama-French三因子模型的核心发现之一。
直接用原始BM值做因子,效果并不好。因为不同行业的BM值差异太大了。银行股的BM普遍高,科技股普遍低。如果你不做行业中性化处理,选出来的全是银行股。
所以,建议的做法是:
代码实现也很简单:
import pandas as pd
import numpy as np
def calc_value_factor(df):
"""
df: 包含 'bm', 'industry' 列的DataFrame
返回行业中性化后的价值因子
"""
df['value_raw'] = df['bm']
# 行业中性化
df['value_factor'] = df.groupby('industry')['value_raw'].transform(
lambda x: (x - x.mean) / x.std
)
return df
如果用的是A股数据,建议用过去12个月的滚动BM值,而不是最新一期。因为A股财报披露有滞后,用最新数据容易引入未来信息偏差。
规模因子,就是小盘股效应。小市值股票长期跑赢大市值股票——这个现象在各国市场都被验证过。
不过,近年来规模因子的收益表现有所弱化。以A股为例,2017—2020年间,大市值股票整体表现显著优于小市值股票,部分以小市值为核心的策略也因此承受了较大回撤。可能是因为:
这个背景下,建议的做法是:
代码示例:
def calc_size_factor(df):
"""
df: 包含 'market_cap' 列
返回对数市值(负向)作为规模因子
"""
df['size_factor'] = -np.log(df['market_cap'])
# 也可以做市值分层
df['size_quantile'] = pd.qcut(df['market_cap'], 10, labels=False)
return df
在实际应用中,小市值策略往往面临较为显著的流动性约束。尽管回测结果可能较为理想,但由于小盘股成交活跃度较低、交易冲击成本较高,实盘收益往往会受到明显侵蚀。因此,在构建小市值相关策略时,需要充分考虑流动性筛选条件,并对市值过小的股票进行必要剔除。
盈利因子,就是买赚钱的公司。这个逻辑很直观——能持续赚钱的公司,股价长期应该上涨。
衡量盈利能力的指标有很多,常用的有:
| 指标 | 计算公式 | 特点 |
|---|---|---|
| ROE | 净利润 / 股东权益 | 最常用,但容易被杠杆放大 |
| ROA | 净利润 / 总资产 | 剔除了杠杆影响,更稳健 |
| 毛利率 | (营收-成本) / 营收 | 反映定价能力,行业差异大 |
| F-Score | 综合9个财务指标 | Piotroski提出的综合评分 |
建议用ROE,具体做两个处理:
代码实现:
def calc_profitability_factor(df):
"""
df: 包含 'roe', 'industry' 列
返回行业中性化后的盈利因子
"""
# 剔除金融行业
df = df[df['industry'] != '金融']
# 计算3年滚动平均ROE
df['roe_avg'] = df.groupby('stock_id')['roe'].rolling(3).mean.values
# 行业中性化
df['profit_factor'] = df.groupby('industry')['roe_avg'].transform(
lambda x: (x - x.mean) / x.std
)
return df
盈利因子和价值因子经常是负相关的。高盈利的公司往往估值也高(低$B/M$),低盈利的公司反而可能估值低(高$B/M$)。所以,如果你同时用这两个因子,一定要做正交化处理,否则会互相抵消。
动量因子,学术上叫趋势因子。它的逻辑很直白:过去涨得好的股票,未来一段时间还会继续涨;过去跌得惨的,未来还会继续跌。这就是所谓的强者恒强,弱者恒弱。
动量因子在牛市阶段往往表现较为突出,但在市场出现剧烈风格切换时,其收益稳定性会显著下降。尤其是在突发性风险事件或市场反转阶段,前期涨幅较高的股票可能迅速遭到抛售,从而导致动量策略出现较大回撤。这表明,动量因子对市场反转较为敏感。
动量因子的核心逻辑: 买入过去N个月(通常12个月,剔除最近1个月)涨幅最高的前30%股票,卖出涨幅最低的后30%股票。
构建动量因子时,有个细节很多人会忽略: 要剔除最近一个月的数据 。为什么?因为A股市场存在明显的短期反转效应——最近一个月涨得好的股票,下个月反而容易跌。如果没剔除近一个月数据,因子IC(信息系数)可能直接变成负的。
动量因子的计算公式很简单:
# 动量因子:过去12个月收益率,剔除最近1个月
def momentum_factor(price_df, lookback=12, skip=1):
# price_df: 日频价格数据,列为股票代码,行为日期
# 计算过去12个月(约252个交易日)的累计收益率
ret_12m = price_df.pct_change(252)
# 剔除最近1个月(约21个交易日)的收益率
ret_1m = price_df.pct_change(21)
# 动量 = 过去12个月收益率 - 最近1个月收益率
momentum = ret_12m - ret_1m
return momentum
动量因子在A股的表现如何?统计2010年到2023年的数据,动量因子的月度IC均值大约在0.03-0.05之间,IR(信息比率)在0.5左右。不算特别高,但胜在稳定——除了2016年和2021年风格切换时出现过较大回撤。
动量因子最好和其他因子配合使用。比如动量+低波,或者动量+质量。单独使用动量,遇到市场风格切换时回撤会很大。可以在动量因子中加入趋势强度的过滤,比如只有当过去3个月的均线呈多头排列时,才启用动量信号。
低波因子,学术上叫低波动异象。它的逻辑听起来有点反直觉:波动率越低的股票,未来收益率反而越高。这跟传统金融学里的高风险高收益完全相反。
可能的原因是,机构投资者(比如公募基金)有业绩排名压力,他们倾向于追逐高波动、高弹性的股票,因为这样才能在短期内跑赢同行。这种博彩式的买入行为,把高波动股票的估值推得很高,未来收益率自然就低了。而低波动股票被冷落,反而提供了安全边际。
低波因子的构建方法有很多种,常用的是 历史波动率倒数 :
# 低波因子:过去60个交易日收益率的标准差的倒数
def low_vol_factor(price_df, window=60):
# 计算日收益率
daily_ret = price_df.pct_change
# 计算滚动标准差(年化)
vol = daily_ret.rolling(window).std * np.sqrt(252)
# 低波因子 = 1 / 波动率
low_vol = 1 / vol
return low_vol
这里有个坑:直接用波动率的倒数,会导致因子值分布非常分散。建议先对波动率做 排名标准化 ,再取倒数。这样因子值会更平滑,选股效果也更好。
低波因子在A股的表现相当不错。低波因子的月度IC均值在0.04-0.06之间,而且跟市场整体走势的相关性很低——市场大跌时,低波因子往往能提供保护。这也是为什么很多防御型策略都会把低波因子作为核心配置。
低波因子不是万能的。在牛市中后期,低波因子会跑输市场。因为那时候市场情绪亢奋,资金都去追高波动股票了。2019年上半年低波因子表现很好,下半年科技股暴涨,低波因子直接跑输沪深300十几个点。
质量因子,说白了就是好公司因子。什么样的公司算好?盈利能力强的、财务健康的、成长性好的。质量因子的逻辑很朴素:好公司的股票,长期来看应该能跑赢差公司。
但这里有个问题:如果市场是有效的,好公司的股票应该已经被定价了,哪来的超额收益?嗯,现实是市场经常犯错——好公司可能因为短期利空被错杀,差公司可能因为概念炒作被高估。质量因子赚的就是纠错的钱。
质量因子通常由多个子指标合成。我个人习惯用以下三个维度:
| 维度 | 指标 | 计算公式 |
|---|---|---|
| 盈利能力 | ROE(净资产收益率) | 净利润 / 净资产 |
| 财务健康 | 资产负债率 | 总负债 / 总资产(取倒数) |
| 盈利稳定性 | 毛利率波动率 | 过去5年毛利率的标准差(取倒数) |
合成方法很简单:先对每个子指标做排名标准化(z-score),然后等权相加:
# 质量因子:ROE、低杠杆、盈利稳定性合成
def quality_factor(financial_df):
# 假设financial_df包含ROE、资产负债率、毛利率波动率三列
# 排名标准化
roe_z = (financial_df['ROE'] - financial_df['ROE'].mean) / financial_df['ROE'].std
leverage_z = (financial_df['资产负债率'] - financial_df['资产负债率'].mean) / financial_df['资产负债率'].std
# 注意:资产负债率越低越好,所以取负值
leverage_z = -leverage_z
stability_z = (financial_df['毛利率波动率'] - financial_df['毛利率波动率'].mean) / financial_df['毛利率波动率'].std
# 同样,波动率越低越好,取负值
stability_z = -stability_z
# 等权合成
quality = (roe_z + leverage_z + stability_z) / 3
return quality
质量因子在A股的表现比较稳健,月度IC均值在0.02-0.04之间,不算高,但胜在稳定。几乎每个月都是正的。而且质量因子跟其他因子的相关性很低,是很好的分散化工具。
如果在质量因子中加入过营收增长率这个指标,结果发现效果很差。为什么?因为高增长的公司往往估值也高,买入成本太高。把营收增长率换成了毛利率稳定性,效果明显改善。所以,质量因子要关注的是质量本身,而不是成长。
怎么把三个因子组合起来?
我见过很多新手直接等权加权,然后跑回测。结果发现收益还不如单因子。为什么?因为因子之间有相关性,简单加权会放大重叠部分的信息。
建议的做法是:
三个因子只是起点。在这些经典因子的基础上,结合自己的理解做改进。比如把价值因子拆成账面价值和市场情绪两部分,效果也不错。
咱们把这三个因子放在一起看看:
| 因子 | 逻辑 | IC均值 | IR | 最大回撤 |
|---|---|---|---|---|
| 动量 | 强者恒强 | 0.03-0.05 | 0.5 | 较大(风格切换时) |
| 低波 | 低风险异象 | 0.04-0.06 | 0.6 | 较小(牛市后期除外) |
| 质量 | 好公司溢价 | 0.02-0.04 | 0.4 | 较小 |
从相关性来看,动量跟低波是负相关的——动量喜欢追涨,低波喜欢避险。质量跟两者都不太相关。所以,这三个因子组合在一起,能起到很好的分散效果。
比如说,动量40% + 低波30% + 质量30% 。这个组合在牛市中能吃到动量的收益,在熊市中靠低波和质量提供保护。当然,具体权重可以根据市场环境动态调整——比如市场情绪高涨时,适当降低动量权重,增加低波权重。
最后,这三个因子都不是圣杯。动量会失效,低波会跑输,质量也会遇到估值陷阱。但把它们组合在一起,再加上之前讲过的规模、价值、红利因子,就能构建出一个相对稳健的多因子体系。
← 上一章 📖 返回目录 下一章 →