4、单因子测试框架:IC/IR分析、分组回测法、多空组合收益计算、因子衰减与换手率
做量化投资的朋友都知道,因子开发是策略研究的基石。但说实话,很多人卡在第一步——因子造出来了,怎么判断它到底有没有用?
我见过不少新手,拿着一个因子回测曲线漂亮得不行,结果实盘一跑就崩。为什么?因为没有经过严格的单因子测试框架检验。今天我就把这套框架掰开揉碎了讲给你听。
4.1 IC/IR分析:因子的预测能力怎么量化?
IC(信息系数)和IR(信息比率),是衡量因子预测能力的两个核心指标。说白了,IC看的是因子值和未来收益的相关性,IR看的是这种相关性的稳定性。
4.1.1 IC的计算方式
IC通常用Spearman秩相关系数来计算。为什么用秩相关?因为因子值分布往往有偏,用秩相关更稳健。
import pandas as pd
import numpy as np
from scipy.stats import spearmanr
def calc_ic(factor_series, return_series):
"""
计算截面IC值
factor_series: 某期因子值
return_series: 对应下期收益
"""
ic, p_value = spearmanr(factor_series, return_series)
return ic, p_value
# 举个实际例子
# 假设我们有100只股票的因子值和下月收益
np.random.seed(42)
factor = np.random.randn(100)
returns = factor * 0.05 + np.random.randn(100) * 0.02
ic_val, p_val = calc_ic(factor, returns)
print(f"IC值: {ic_val:.4f}, p值: {p_val:.4f}")
关键点:IC值在-1到1之间。正IC表示因子值越大,未来收益越高。绝对值超过0.05就算有预测能力了,超过0.1就很不错。
4.1.2 IR:IC的稳定性更重要
IR = mean(IC) / std(IC)。为什么IR重要?我在项目中遇到过这样的情况:一个因子IC均值0.08,但标准差0.15,IR只有0.53。另一个因子IC均值0.05,标准差0.03,IR达到1.67。你猜哪个更靠谱?
答案是后者。因为稳定的预测能力,比偶尔爆发但经常失效的因子更有实战价值。
我的习惯:IR低于0.5的因子,我基本不会纳入最终模型。IR超过1.0的因子,我会重点研究。
4.2 分组回测法:最直观的因子检验
IC/IR是统计指标,但分组回测更直观。你想想看,把股票按因子值分成10组,看第1组和第10组的收益差异,一眼就能看出因子有没有区分度。
4.2.1 分组回测的实现
def group_backtest(factor_df, return_df, n_groups=10):
"""
分组回测函数
factor_df: 日期×股票的因子值矩阵
return_df: 日期×股票的收益矩阵
"""
results = {}
for date in factor_df.index:
# 获取当期因子值
factors = factor_df.loc[date].dropna()
# 按因子值排序分组
groups = pd.qcut(factors, n_groups, labels=False)
# 计算每组下期收益
for g in range(n_groups):
stocks_in_group = factors[groups == g].index
group_return = return_df.loc[date, stocks_in_group].mean()
if g not in results:
results[g] = []
results[g].append(group_return)
# 计算每组累计收益
group_performance = {}
for g, returns in results.items():
group_performance[g] = (1 + pd.Series(returns)).cumprod()
return pd.DataFrame(group_performance)
我曾经踩过的坑:分组时要注意因子值的分布。如果因子值集中在某个区间,用等宽分组会导致某些组股票太少。我建议用分位数分组(qcut),保证每组股票数量均衡。
4.3 多空组合收益计算
分组回测看的是单调性,多空组合看的是绝对收益。多空组合就是做多因子值最高的组,做空因子值最低的组。
4.3.1 多空收益的计算逻辑
假设我们分成10组,多空组合就是第10组(多头)减去第1组(空头)的收益。这个差值就是因子带来的超额收益。
def long_short_return(group_returns):
"""
计算多空组合收益
group_returns: 分组收益DataFrame
"""
# 假设第0组是空头,第9组是多头
long_return = group_returns[9]
short_return = group_returns[0]
# 多空收益
ls_return = long_return - short_return
# 累计多空收益
cum_ls = (1 + ls_return).cumprod()
return ls_return, cum_ls
实战要点:多空组合的年化收益超过5%,夏普比率超过1.0,这个因子才算有实战价值。我见过一些因子多空收益很高,但夏普比率只有0.3,这种因子在实盘中很容易回撤。
4.4 因子衰减:因子的寿命有多长?
因子衰减,说白了就是因子的预测能力随时间下降的速度。为什么会这样?因为市场在进化,套利者在消灭alpha。
4.4.1 衰减分析的方法
我通常用两种方法分析因子衰减:
- 滚动IC分析:计算过去12个月的滚动IC,看IC是否在下降
- 分层衰减分析:看因子对未来1个月、3个月、6个月收益的预测能力
def decay_analysis(factor_df, return_df, horizons=[1, 3, 6, 12]):
"""
因子衰减分析
horizons: 预测期数(月)
"""
decay_results = {}
for h in horizons:
# 计算未来h个月的累计收益
future_returns = return_df.shift(-h).rolling(h).mean()
# 计算IC
ics = []
for date in factor_df.index[: -h]:
if date in future_returns.index:
ic, _ = calc_ic(factor_df.loc[date], future_returns.loc[date])
ics.append(ic)
decay_results[h] = np.mean(ics)
return decay_results
我的经验:如果一个因子对未来1个月的IC是0.08,对未来3个月降到0.03,对未来6个月变成0.01,说明这个因子衰减很快。这种因子适合做高频交易,不适合做长期配置。
4.5 换手率:交易成本的真实考验
很多人在回测中忽略换手率,这是大忌。一个因子换手率太高,交易成本会吃掉所有收益。
4.5.1 换手率的计算
换手率 = 每期调仓时,组合中股票变动比例的平均值。
def calc_turnover(portfolio_weights):
"""
计算组合换手率
portfolio_weights: 每期持仓权重DataFrame
"""
turnover = []
for i in range(1, len(portfolio_weights)):
# 计算本期与上期权重的差异
prev_weights = portfolio_weights.iloc[i-1]
curr_weights = portfolio_weights.iloc[i]
# 换手率 = 权重变化绝对值之和 / 2
change = (curr_weights - prev_weights).abs().sum() / 2
turnover.append(change)
return pd.Series(turnover, index=portfolio_weights.index[1:])
我曾经犯过的错:有一个因子IC很高,IR也不错,但换手率每月达到80%。算上双边千三的交易成本,年化收益从15%直接降到3%。所以我现在做因子测试,一定会把交易成本算进去。
4.6 综合框架:把这些工具串起来
好了,现在我们把所有工具整合成一个完整的单因子测试框架。我个人习惯按这个流程走:
- 数据准备:清洗因子数据,处理缺失值和极端值
- IC/IR分析:计算截面IC、时间序列IC、IR值
- 分组回测:分成10组,看收益单调性
- 多空组合:计算多空收益和夏普比率
- 衰减分析:看因子在不同预测期的表现
- 换手率分析:计算调仓成本,评估净收益
下面这张图展示了整个框架的流程:
这个框架看起来步骤多,但每一步都有它的意义。IC/IR告诉你因子有没有预测能力,分组回测告诉你预测能力是否稳定,多空组合告诉你收益空间有多大,衰减分析告诉你因子能活多久,换手率告诉你交易成本会不会吃掉收益。
总结一下:一个合格的因子,IC绝对值超过0.05,IR超过0.5,分组收益单调递增,多空组合夏普超过1.0,衰减速度慢,换手率低于30%。满足这些条件,这个因子才值得你花时间去优化和实盘。
嗯,单因子测试框架就讲到这里。这套方法我用了好几年,踩过不少坑,也积累了一些心得。希望对你有所帮助。
公众号:蓝海资料掘金营,微信deep3321