🚀 AI 一键生成 joinquant 策略代码
立即体验

如何在聚宽中计算带标准化偏离和递近权重的均线动量因子,并与经典动量因子进行回测比较?

joinquant | 发布时间: 2026/8/11
以下内容由 EasyQuant 生成。

问题描述

聚宽均线动量因子与经典动量因子:如何编写并比较两种选股策略?
如何在聚宽中计算带标准化偏离和递近权重的均线动量因子,并与经典动量因子进行回测比较?

解决方案

1. 因子定义与数学原理

在多因子选股中,**动量因子(Momentum)**是极其经典的一类风格因子。为了捕捉不同维度的动量效应,我们在此定义并比较两种动量因子:

  • 经典动量因子(Momentum):通常定义为过去一段时间(如 504 个交易日,滞后 21 个交易日)的超额对数收益率的指数加权之和。在聚宽风险模型中,其核心描述为 relative_strength
  • 带标准化偏离和递近权重的均线动量因子(MA_Momentum_Weighted)
    该因子不仅考虑价格相对于均线的偏离度,还引入了递近权重(时间衰减)波动率标准化。其数学公式如下:
    $$\text{MA_Momentum_Weighted} = \frac{\sum_{t=1}^{N} w_t \times \left( \frac{P_t - \text{MA}_t(M)}{\text{MA}_t(M)} \right)}{\sigma_N}$$
    其中:
    • $P_t$ 为 $t$ 日的收盘价。
    • $\text{MA}_t(M)$ 为 $t$ 日的 $M$ 日简单移动平均价。
    • $w_t = t$ 为递近权重(越接近当前交易日,权重越大)。
    • $\sigma_N$ 为过去 $N$ 天价格偏离度的标准差(用于标准化波动率)。

2. 聚宽自定义因子编写

我们继承聚宽的 Factor 类,实现上述带标准化偏离和递近权重的均线动量因子:

import numpy as np
import pandas as pd
from jqfactor import Factor, calc_factors

class MA_Momentum_Weighted(Factor):
    name = 'ma_momentum_weighted'
    # 需要过去 20 天的偏离度,而计算 MA5 需要额外 5 天,因此窗口设为 25
    max_window = 25 
    dependencies = ['close']

    def calc(self, data):
        close = data['close'] # DataFrame: index为日期(25天), columns为股票代码
        
        # 1. 计算 5 日均线 (MA5)
        ma5 = close.rolling(window=5).mean()
        
        # 2. 计算价格相对于 MA5 的偏离度
        bias = (close - ma5) / ma5
        
        # 3. 取最近 20 天的偏离度数据进行加权
        bias_20 = bias.iloc[-20:]
        
        # 4. 定义递近权重 (1 到 20)
        weights = np.arange(1, 21).reshape(-1, 1)
        
        # 5. 计算加权偏离度均值
        weighted_bias = (bias_20 * weights).sum(axis=0) / weights.sum()
        
        # 6. 计算过去 20 天偏离度的标准差,用于标准化
        sigma_20 = bias_20.std(axis=0)
        
        # 7. 避免除以 0,进行标准化处理
        factor_value = weighted_bias / (sigma_20 + 1e-6)
        
        return pd.Series(factor_value, index=close.columns)

3. 策略回测与对比框架

以下是一个完整的聚宽策略模板,通过 initialize 设定定时任务,每月初计算两类动量因子,并分别构建多头组合进行回测对比:

from jqdata import *
from jqfactor import get_factor_values
# 导入自定义因子类(若在研究环境中,可直接复制上述类定义)

def initialize(context):
    set_benchmark('000300.XSHG')
    set_option('use_real_price', True)
    
    # 佣金印花税设置
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 策略参数设置
    g.factor_type = 'MA_MOMENTUM' # 可选: 'MA_MOMENTUM' 或 'CLASSIC_MOMENTUM'
    g.hold_num = 10 # 持股数量
    
    # 每月第一个交易日开盘运行
    run_monthly(rebalance, monthday=1, time='09:30')

def rebalance(context):
    # 1. 获取沪深300成分股
    stocks = get_index_stocks('000300.XSHG', date=context.previous_date)
    
    # 2. 获取因子值
    if g.factor_type == 'CLASSIC_MOMENTUM':
        # 获取聚宽因子库中的经典动量因子 momentum
        factor_data = get_factor_values(
            securities=stocks, 
            factors=['momentum'], 
            end_date=context.previous_date, 
            count=1
        )['momentum'].iloc[-1]
    else:
        # 计算自定义的带权重均线动量因子
        # 在回测中,可使用 calc_factors 实时计算
        factor_dict = calc_factors(
            securities=stocks, 
            factors=[MA_Momentum_Weighted()], 
            start_date=context.previous_date, 
            end_date=context.previous_date
        )
        factor_data = factor_dict['ma_momentum_weighted'].iloc[-1]
    
    # 3. 因子值去极值与标准化(可选,此处直接按因子值从大到小排序)
    factor_data = factor_data.dropna().sort_values(ascending=False)
    
    # 4. 选取前 10 只高动量股票
    target_list = list(factor_data.index[:g.hold_num])
    
    # 5. 调仓执行
    # 卖出不在目标池的股票
    for stock in list(context.portfolio.positions.keys()):
        if stock not in target_list:
            order_target(stock, 0)
            
    # 等权重买入目标股票
    position_value = context.portfolio.total_value / g.hold_num
    for stock in target_list:
        order_target_value(stock, position_value)

4. 策略比较维度建议

在聚宽回测结束后,建议从以下三个维度对比两种动量策略的表现:

  1. 收益风险比(Sharpe Ratio & Max Drawdown):带标准化偏离的均线动量因子由于引入了波动率分母 $\sigma_N$,通常在高波动市场中具有更好的防守性,最大回撤表现往往优于经典动量。
  2. 换手率(Turnover Rate):经典动量因子(基于长周期收益率)的换手率通常较低;而均线动量因子对中期价格变化更敏感,换手率相对较高,需注意滑点和交易成本对净值的影响。
  3. 行业暴露(Industry Exposure):经典动量容易抱团于单一强势行业,建议在聚宽归因分析中查看其 Brinson 归因,观察超额收益是来源于行业配置还是个股选择。