第四章:因子评价体系——IC分析、分层回测与实战避坑
各位同学,欢迎来到因子评价体系这一章。说实话,这一章是整个因子挖掘流程里最“枯燥”但也是最“要命”的部分。为什么这么说?因为我见过太多人挖出一堆花里胡哨的因子,结果一上回测就崩盘。嗯,我自己也踩过这个坑。
因子评价,说白了就是回答三个问题:这个因子到底有没有预测能力?它的收益稳不稳定?实盘能不能用?今天我们就围绕这三个问题,把IC分析、分层回测、因子收益率和容量分析讲透。
一、IC分析:因子预测能力的“体检报告”
IC,全称是Information Coefficient,信息系数。它衡量的是因子值与未来收益之间的相关性。我个人习惯把IC看作因子的“体检报告”——数值越高,说明因子对未来的预测越准。
1. Normal IC(皮尔逊IC)
Normal IC就是普通的皮尔逊相关系数。它假设因子值和未来收益之间存在线性关系。公式很简单:
Normal IC = corr(因子值, 未来一期收益)
但这里有个大坑——皮尔逊相关系数对异常值极其敏感。我在项目中遇到过一只小盘股因为突发利好一天涨了20%,结果当天的IC直接被这个异常值拉到了0.8以上。你以为因子很牛?其实只是噪音。
2. Rank IC(斯皮尔曼IC)
Rank IC用的是秩相关系数,说白了就是只看排序不看数值。你想想看,如果因子值排第1的股票未来收益也排第1,那Rank IC就是1,哪怕因子值本身差100倍都不影响。
我个人更偏爱Rank IC,为什么?因为它稳健。在A股市场,很多因子值分布是偏态的——比如市值因子,大市值和小市值差几个数量级。用Normal IC会被极端值带偏,但Rank IC只看排名,稳得很。
# Python代码示例:计算Rank IC
import pandas as pd
from scipy.stats import spearmanr
def calc_rank_ic(factor_series, return_series):
"""
计算Rank IC
factor_series: 因子值序列
return_series: 未来一期收益序列
"""
# 去掉缺失值
valid = pd.concat([factor_series, return_series], axis=1).dropna()
if len(valid) < 30:
return 0, 1 # 样本太少,返回不显著
ic, p_value = spearmanr(valid.iloc[:, 0], valid.iloc[:, 1])
return ic, p_value
# 使用示例
ic_value, p_val = calc_rank_ic(factor_data['因子值'], future_returns['未来收益'])
print(f"Rank IC: {ic_value:.4f}, p值: {p_val:.4f}")
二、分层回测法:眼见为实的收益检验
IC分析告诉你因子“有没有用”,但分层回测告诉你“怎么用”。说白了,就是把股票按因子值从大到小分成N组(通常是5组或10组),然后看每组未来的收益表现。
为什么要做分层回测?我记得有一次,一个因子的IC高达0.08,看起来很不错。但分层回测一跑,发现只有第一组(因子值最大的组)有超额收益,其他组全是负的。这说明什么?说明这个因子只能做多头,不能做空头。如果直接做多空组合,反而会亏钱。
# 分层回测核心逻辑
def layer_backtest(factor_df, return_df, n_groups=5):
"""
分层回测
factor_df: 因子值DataFrame,行是时间,列是股票
return_df: 未来收益DataFrame
"""
results = {}
for date in factor_df.index:
# 获取当期的因子值和收益
factors = factor_df.loc[date].dropna()
returns = return_df.loc[date]
# 按因子值分组
sorted_factors = factors.sort_values()
group_size = len(sorted_factors) // n_groups
for g in range(n_groups):
start = g * group_size
end = (g + 1) * group_size if g < n_groups - 1 else len(sorted_factors)
group_stocks = sorted_factors.iloc[start:end].index
# 计算该组等权收益
group_return = returns[group_stocks].mean()
results.setdefault(g, []).append(group_return)
# 计算每组累计收益
group_cum_returns = {g: np.cumprod(1 + np.array(ret)) for g, ret in results.items()}
return group_cum_returns
三、因子收益率与t值:统计显著性的“照妖镜”
因子收益率,通常通过Fama-MacBeth回归来估计。简单说就是两步走:第一步,每个时间截面做一次横截面回归;第二步,把时间序列上的回归系数取均值,就是因子收益率。
t值呢?就是因子收益率除以其标准误。t值大于2,通常认为因子在统计上显著。但这里我要说一句:t值大不代表因子一定能赚钱,它只代表因子收益率不是随机波动出来的。
- t值 > 2:显著,可以考虑
- t值 > 3:非常显著,值得重仓
- t值 < 1.5:基本可以放弃
# Fama-MacBeth回归简化版
def fama_macbeth(factor_matrix, return_matrix):
"""
factor_matrix: T x N 的因子值矩阵
return_matrix: T x N 的收益矩阵
返回因子收益率序列和t值
"""
T = factor_matrix.shape[0]
factor_returns = []
for t in range(T):
# 横截面回归:收益 ~ 因子值
X = sm.add_constant(factor_matrix.iloc[t])
y = return_matrix.iloc[t]
model = sm.OLS(y, X, missing='drop').fit()
factor_returns.append(model.params.iloc[1]) # 因子系数
# 计算均值和t值
mean_return = np.mean(factor_returns)
std_return = np.std(factor_returns, ddof=1)
t_value = mean_return / (std_return / np.sqrt(T))
return mean_return, t_value
四、换手率与容量分析:实盘前的“压力测试”
这是最容易被忽略的一环。很多人在回测里赚得盆满钵满,一上实盘就亏成狗。为什么?因为没考虑换手率和容量。
换手率,说白了就是你的策略每天要买卖多少股票。如果一个因子每天换手率高达50%,那交易成本就能吃掉你大部分收益。我见过一个因子,年化收益20%,但双边换手率300%,扣除千分之一的印花税和佣金后,实际收益只剩8%。
容量分析更关键。你的策略能容纳多少资金?如果只有1000万的容量,你拿一个亿去跑,冲击成本会直接把alpha打没。
# 换手率计算
def calc_turnover(weights_history):
"""
weights_history: 每日持仓权重DataFrame
返回日均双边换手率
"""
daily_turnover = []
for t in range(1, len(weights_history)):
prev_weights = weights_history.iloc[t-1]
curr_weights = weights_history.iloc[t]
turnover = np.sum(np.abs(curr_weights - prev_weights))
daily_turnover.append(turnover)
avg_daily_turnover = np.mean(daily_turnover)
annual_turnover = avg_daily_turnover * 252
return avg_daily_turnover, annual_turnover
五、综合评价:如何给因子“打分”?
说了这么多,到底怎么综合判断一个因子好不好?我个人习惯用下面这个打分表:
| 评价维度 | 优秀 | 合格 | 不合格 |
|---|---|---|---|
| Rank IC均值 | > 0.05 | 0.02 ~ 0.05 | < 0.02 |
| IC的t值 | > 3 | 2 ~ 3 | < 2 |
| 分层回测单调性 | 严格单调 | 基本单调 | U型或混乱 |
| 多空组合夏普比 | > 2 | 1 ~ 2 | < 1 |
| 年化换手率 | < 100% | 100% ~ 300% | > 300% |
| 资金容量 | > 10亿 | 1亿 ~ 10亿 | < 1亿 |
嗯,这个表是我自己总结的,不一定适合所有策略。比如高频策略换手率天然高,那就要看扣除交易成本后的净收益。低频策略换手率低,但容量大,适合大资金。
最后说一句:因子评价不是一锤子买卖。我建议每季度重新评估一次因子,因为市场环境在变,因子的有效性也在变。曾经有效的因子,可能过半年就失效了。保持警惕,持续迭代,这才是量化投资的生存之道。