BigQuant 2026年度私享会

保温杯-因子简约之美

由bqf6mces创建,最终由bqf6mces 被浏览 8 用户

保温杯策略回顾

保温杯策略是一种基于机器学习的风格因子动态配置方法,其设计思路源于对A股市场风格轮动特性的深刻洞察。该策略将Barra风险模型中的核心风格因子包括规模(Size)、价值(Value)、动量(Momentum)、波动率(Volatility)、质量(Quality)及成长(Growth)等维度作为XGBoost模型的输入特征,通过滚动训练机制捕捉市场风格的非线性转换规律,实现因子权重的动态优化。 相较于传统静态因子加权方法,该策略具备三重优势:

  1. 非线性关系捕捉:XGBoost算法有效识别因子间复杂的交互效应,例如价值与动量因子在不同市场环境下的拮抗关系
  2. 动态适应性:通过月度/周度滚动训练机制,模型能够及时响应市场风格切换,避免传统模型的滞后性缺陷
  3. 噪声过滤:内置正则化机制与特征重要性评估,自动降低低信息量因子的权重,提升策略稳健性

2024年1月-8月A整体呈现下跌趋势,2月5日探底至2635.09点,随后反弹至2月29日的3015.17点。3-4月在3000-3100点区间震荡,5月触及3174点高点后开始回落,属于熊市阶段。2024年10月8日上证指数从9月24日的2749点快速上涨至3490点,10月11日收于3217.74点,10月28日盘中突破4000点整数关口,标志着市场进入慢牛阶段。这一时段覆盖了完整的牛熊转换周期,为节省回测时间,我们将此时间点作为策略回测的关键时间窗口。通过2024年1月-2025年12月回归该策略展现出显著的超额收益能力。后续策略对比我们也将基于此时间段进行,有能力的同学可以调大回测周期。

保温杯回测2024-01-01 至 2025-12-31 策略风险概览

保温杯策略的双面性

保温杯策略具有灵活性与局限性双面特效,保温杯其核心价值在于通过引入多元化Barra风格因子体系,实现了对不同市场环境的动态适应能力。这一策略如同"保温杯"之名所示,旨在无论市场冷热,都能保持相对稳定的收益特征。策略通过多因子轮动机制,持续捕捉市场风格变迁,理论上能够在不同市场周期中保持韧性。 然而,正是这种多因子架构构成了保温杯策略的内在局限。在实际应用中,过多的因子不仅增加了模型复杂度,也引入了更多的噪声因子,过度拟合风险和更高的交易成本。更为关键的是,A股市场展现出独特的"风格持续性"特征——在中短期内,市场往往呈现较为明确且持续的风格偏好,而非频繁切换。这一市场特质使得复杂的多因子体系在某些阶段反而成为累赘,无法充分发挥其理论优势。

熊市环境下的防御性不足(2024年1月-8月) 在2024年上半年持续的熊市环境中,保温杯策略的动态调整机制反应滞后,未能及时识别市场风险偏好下降的趋势。相比之下,红利股策略凭借其稳定的股息回报和低估值特性,在市场下行期间展现出更强的防御能力。回测显示,该期间红利股策略平均跑赢保温杯策略约5.8个百分点,尤其在3月和6月的市场急跌阶段,差距更为显著。 这一现象映射了市场的一个基本规律:在极端风险厌恶环境下,投资者更倾向于确定性收益而非策略灵活性。保温杯策略的多因子动态权重调整机制在快速下跌市场中反而成为负担,频繁的再平衡操作放大了交易损耗。

通过回测我们可以发现,在2024年1月-8月极端市场情况下,红利股最大回测仅10.84%且仍有可观的超额收益,体现了比保温杯策略更高的稳健性。

回测周期2024-01-01 至 2025-12-01 回测周期2024-01-01 至 2024-08-31

慢牛行情中的进攻性欠缺(2024年10月) 进入10月后,市场转向温和上涨的慢牛格局,小市值策略凭借其高贝塔特性和流动性溢价迅速占据优势。保温杯策略的均衡配置原则在此时成为制约因素,其风险控制模块过度平滑了收益曲线,导致无法充分捕捉成长型资产的超额收益。2025年全年回测,保温杯使用22个经典因子的情况下回测与小市值策略夏普基本一致,但是收益略低于小市值策略。

保温杯 回测周期2025-01-01 至 2025-12-01 小市值 回测周期2025-01-01 至 2025-12-01

因子简约之美

从多因子复杂性到风格驱动的简约之美

保温杯策略到风格驱动的精简因子模型,A股市场风格特征与策略适配 深入研究A股历史数据可见,中国市场在6-12个月的时间维度上通常呈现明显的风格持续性。例如,2019-2020年的核心资产行情、2021年的成长风格主导、2022年的价值回归,以及2023年的红利策略盛行等。这种相对稳定的风格周期为策略设计提供了重要启示:在特定阶段,精准识别并聚焦于主导风格,可能比广泛覆盖所有可能风格因子带来更优的风险调整后收益。 策略优化新思维:"少即是多"的量化哲学 基于上述市场特征,量化策略优化应遵循"less is more"的核心理念,追求因子体系的简约之美。这一理念并非简单地减少因子数量,而是通过深度理解市场状态,构建与当前环境高度适配的精简因子组合。策略优化路径可概括为:市场风格识别→关键因子筛选→简约模型构建。

具体而言,我们可以通过以下方式实现策略升级: 建立市场风格监测系统,实时判断当前主导风格 基于风格判断,仅保留与当前市场最相关的3-5个核心因子 采用XGBoost等机器学习算法,训练高度聚焦的策略模型 设置风格转换预警机制,确保策略及时响应市场变化 因子选择方法论比较与融合 在简约策略框架下,因子选择的科学性尤为重要。

目前主流方法包括:

IC/IR导向法:通过信息系数(IC)和信息比率(IR)筛选具有稳定预测能力的因子,优势在于统计严谨性,但对非线性关系捕捉不足

XGBoost特征重要性:利用机器学习算法自身的特征选择机制,通过gain值评估因子贡献度,能有效捕捉非线性关系和交互效应

Barra风格择时法:基于市场状态判别,动态选择适配当前环境的风格因子,强调市场环境与因子表现的相关性

经济逻辑驱动法:结合宏观周期、政策导向和市场情绪等基本面逻辑筛选因子,增强策略可解释性

以下回测对比仅加入了因子择时,回测周期与原因子输了完全相同。

数据验证

IC/IR因子择时

在量化投资和因子分析中,IR(Information Ratio,信息比率) 是一个关键绩效指标,尤其在因子分析的上下文中,它有特定含义,IR指的是因子IC序列的信息比率,计算公式为:IR = 平均IC / IC的标准差

  1. IC (Information Coefficient):
    • 因子值与未来收益之间的相关系数(通常使用Spearman秩相关系数)
    • 衡量因子预测能力的强弱
    • |IC|越大,表示预测能力越强
  2. IR的意义:
    • 不仅考虑IC的大小,还考虑IC的稳定性

    • 高IR值表示因子不仅有预测能力,而且这种预测能力稳定可靠

    • 例如:两个因子平均IC都是0.05,但标准差分别为0.02和0.10,前者的IR=2.5,后者IR=0.5,前者更优。

      高IR因子通常能带来更稳定、更可预测的超额收益,这里通过计算窗口周期内各因子的IR值,来评估和筛选出表现稳定且显著的优质因子。

def get_ic_score_columns(
        hist_df: pd.DataFrame,
        factor_cols: List[str],
        label_col: str,
        min_samples_per_day: int = 30,
        min_valid_days: int = 10,
        ir_clip_range: tuple = (-5.0, 5.0)
):
    # 根据ic选择效果好的列
    """
        对每个因子,计算其历史 IC 序列的 IR(信息比率)作为打分。

        返回: {factor_name: IR}
        """
    scores = {}
    dates = sorted(hist_df['date'].unique())
    for factor in factor_cols:
        ics = []
        for d in dates:
            daily = hist_df[hist_df['date'] == d]
            valid = daily[[factor, label_col]].dropna()
            if len(valid) >= min_samples_per_day:
                ic, _ = spearmanr(valid[factor], valid[label_col])
                ics.append(ic)
        # 至少需要一定天数的有效 IC
        if len(ics) < min_valid_days:
            scores[factor] = 0.0
            continue

        mean_ic = np.mean(ics)
        std_ic = np.std(ics, ddof=1)

        if std_ic == 0:
            ir = 0.0 if mean_ic == 0 else np.inf * np.sign(mean_ic)
        else:
            ir = mean_ic / std_ic

        # 截断极端值(防止数值不稳定)
        ir = np.clip(ir, ir_clip_range[0], ir_clip_range[1])
        scores[factor] = float(ir)
    return scores

通过回测我们可以发现,实用IR top5因子作为xgboost因子输入,既可以得到年华收益52.7%的收益,远高于同回测周期原版的26.49%

gain因子择时

在XGBoost(极端梯度提升)算法中,Gain值(信息增益)是评估特征价值的核心指标,它量化了特征在决策树节点分裂时带来的预测能力提升。相较于XGBoost提供的其他特征重要性指标(Weight:特征被用作分裂点的次数;Cover:特征分裂覆盖的样本数),Gain更能反映特征的真实预测价值。

这一特性在量化投资的因子择时中具有独特优势:Gain能够识别那些IC值(信息系数)不高,但在特定市场环境下具有决定性作用的关键因子。以熊市为例,传统估值因子(如PE)往往表现出较低的IC值,容易被常规因子筛选方法忽略。然而,历史数据表明,当市场进入下行周期,低估值股票往往展现出更强的抗跌性和更快的恢复能力。通过基于Gain的特征选择机制,我们可以捕捉到这种"条件重要性"——即在特定市场状态下才显现价值的因子。例如,在熊市阶段,PE等估值因子虽然整体IC偏低,但在XGBoost模型中的Gain值却显著提升,这正是因为它在市场恐慌时期成为了区分优质资产与价值陷阱的关键判别依据。这种基于Gain的因子择时方法,帮助我们超越静态IC评估的局限,构建更具市场适应性的动态选股策略。


import xgboost as xgb

# 假设 train 和 test 已经定义
# 选择ic/ir较高的因子
X_train = train[train_col]
y_train = train['label']
X_test = test[train_col]

# 创建 DMatrix
dtrain = xgb.DMatrix(X_train, label=y_train)

# 设置参数
params = {
    'objective': 'reg:squarederror',
    'max_depth': 3,
    'eta': 0.1,
    'eval_metric': 'rmse',
    'tree_method': 'gpu_hist',
}
num_round = 100

# 预训练模型
bst = xgb.train(params, dtrain, num_round)

gain_score_columns = bst.get_score(importance_type='gain')
gain_score_columns = sorted(gain_score_columns, key=gain_score_columns.get, reverse=True)[:3]
print(f'train_sd={train_sd},train_ed={train_ed},test_sd={test_sd},test_ed={test_ed},top5 columns={gain_score_columns}')
X_train = train[gain_score_columns]
y_train = train['label']
X_test = test[gain_score_columns]

# 创建 DMatrix
dtrain = xgb.DMatrix(X_train, label=y_train)

# 设置参数
params = {
    'objective': 'reg:squarederror',
    'max_depth': 3,
    'eta': 0.1,
    'eval_metric': 'rmse',
    'tree_method': 'gpu_hist',
}
num_round = 100

# 训练模型
bst = xgb.train(params, dtrain, num_round)

通过回测我们发现,通过gain进行择时,选择gain top3,每次回测仅输入3个贡献度最高的因子进行回测,即可得到和原版保温杯相同收益率但更低的最大回撤。

回测曲线

barra风格因子择时

barra风格因子择时的主要作用是评估自定义因子(custom factors)在风格因子暴露方面的有效性,为量化投资策略中的因子选择提供参考。具体来说:

  1. 核心功能:计算每个自定义因子对Barra风格因子体系的暴露(beta),并结合近期风格因子的表现,给出一个综合得分。
  2. 计算逻辑
    • 首先确定回溯期(默认30天)内各Barra风格因子的平均回报
    • 通过线性回归分析,计算每个自定义因子对Barra风格因子的暴露程度(beta)
    • 综合得分 = Σ(自定义因子对风格因子的beta × 该风格因子的平均回报)
  3. 业务意义
    • 得分高的自定义因子意味着它更多地暴露于近期表现良好的风格因子
    • 帮助投资经理理解自定义因子的风险和收益来源
    • 为因子组合构建和权重分配提供依据
    • 识别哪些自定义因子可能在未来市场环境中表现较好

barra风格因子择时在量化投资中"理解因子风险来源"的核心理念,通过将自定义因子与标准化的Barra风格因子体系进行映射,使得因子评估更加系统化和透明化。

def get_style_export_score_columns(
        context,
        hist_df: pd.DataFrame,
        custom_factor_cols: List[str],
        barra_style_cols: List[str],
        barra_return_df: pd.DataFrame,
        lookback_days: int = 30,
) -> Dict[str, float]:
    
    available_dates = sorted(hist_df['date'].unique())
    if not available_dates:
        return {f: 0.0 for f in custom_factor_cols}

    end_date = max(available_dates)
    log_info(context, f">>>>>>>>>> get_style_export_score_columns max_date={end_date}")

    if not isinstance(barra_return_df.index, pd.DatetimeIndex):
        barra_return_df = barra_return_df.set_index('date')
        barra_return_df.index = pd.to_datetime(barra_return_df.index)


    recent_dates = [d for d in sorted(barra_return_df.index) if d <= end_date][-lookback_days:]
    if not recent_dates:
        return {f: 0.0 for f in custom_factor_cols}
   
    recent_barra_rets = barra_return_df.loc[recent_dates, barra_style_cols]

    style_effectiveness = {}
    for style in barra_style_cols:
        if style in recent_barra_rets.columns:
            avg_ret = recent_barra_rets[style].mean()
            style_effectiveness[style] = avg_ret
        else:
            style_effectiveness[style] = 0.0


    factor_betas = {f: {s: 0.0 for s in barra_style_cols} for f in custom_factor_cols}
    valid_day_count = {f: 0 for f in custom_factor_cols}

    for d in available_dates:
        daily = hist_df[hist_df['date'] == d]
        for factor in custom_factor_cols:
            needed_cols = [factor] + barra_style_cols
            valid = daily[needed_cols].dropna()
            X = valid[barra_style_cols].values
            y = valid[factor].values

            try:
                reg = LinearRegression().fit(X, y)
                betas = reg.coef_
                for i, style in enumerate(barra_style_cols):
                    factor_betas[factor][style] += betas[i]
                valid_day_count[factor] += 1
            except Exception:
                continue
    # 平均 beta
    avg_betas = {}
    for f in custom_factor_cols:
        if valid_day_count[f] > 0:
            avg_betas[f] = {
                s: factor_betas[f][s] / valid_day_count[f]
                for s in barra_style_cols
            }
        else:
            avg_betas[f] = {s: 0.0 for s in barra_style_cols}
    # Step 3: 综合得分 = Σ(beta_style × avg_barra_return_style)
    scores = {}
    for f in custom_factor_cols:
        total_score = sum(
            avg_betas[f][style] * style_effectiveness[style]
            for style in barra_style_cols
        )
        scores[f] = float(total_score)
    return scores

使用barra风格进行因子择时后,收益率明显高于原版策略。

\

总结展望

XGBoost作为当前量化投资领域的主流机器学习工具,其强大的非线性建模能力和特征选择机制为因子投资带来了革命性变革。然而,本研究通过保温杯策略与风格驱动简约因子模型的对比实证,揭示了一个关键洞见:XGBoost模型的预测效能不仅取决于算法本身,更取决于输入特征与市场状态的匹配程度

当我们将XGBoost从"多而全"的因子输入转向"少而精"的风格适配型因子选择时,模型的样本外预测能力显著提升,这一发现为XGBoost选股策略优化提供了全新思路。无论算法如何演进,量化投资的核心目标始终如一:在风险可控的前提下,为投资者创造可持续的超额收益。XGBoost作为工具,其价值不在于技术本身的复杂度,而在于如何以最简约的方式,捕捉市场最本质的规律。这或许就是量化投资的最高境界——用最精简的模型,解最复杂的市场

当前研究仍存在诸多局限,因子择时只提供了一种保温杯因子风格择时的投研思路,代码还有很多优化空间和调惨空间,可以通过自定义因子择时组合或者结合大盘走势选择gain择时还是ic择时,同学们也可以加入自己的因子和高频因子进行回测测试。有兴趣的同学也可以进一步进行验证。

投研代码

https://bigquant.com/codesharev3/20fa3333-9141-484d-b7fd-478fc9cd3f19

标签

机器学习
{link}