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

聚宽红利低波选股策略:结合 MA120 均线实现轻度仓位风控(附 Python 源码)

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

问题描述

JoinQuant 红利低波策略:如何用 MA120 进行轻度仓位风控?
如何在聚宽中筛选高股息、稳定 ROE 和低波动股票,并在指数跌破 MA120 时将组合仓位降至 95%?

解决方案

策略核心逻辑

红利低波(Dividend Low Volatility)是量化投资中非常经典的 Smart Beta 策略。本策略在聚宽(JoinQuant)平台上实现,主要包含以下两个核心模块:

  1. 多因子选股模块

    • 高股息:通过聚宽财务估值表 valuation 中的 dividend_payable(应付股利)或直接使用聚宽因子库中的股息率指标进行筛选。
    • 稳定 ROE:利用 indicator.roe 筛选出最新一期 ROE 大于 8% 且近几年表现稳定的上市公司。
    • 低波动:计算候选股票池过去 60 个交易日的日收益率标准差(Volatility),选择波动率最低的前 N 只股票。
  2. MA120 均线轻度风控模块

    • 每日或每周获取基准指数(如沪深 300 指数 000300.XSHG)的收盘价。
    • 计算其 120 日简单移动平均线(MA120)。
    • 风控触发:若沪深 300 指数收盘价跌破 MA120,则将整体持仓仓位上限控制在 95%(保留 5% 现金防范风险)。
    • 正常状态:若指数在 MA120 之上,则保持 100% 满仓运行。

聚宽策略源码实现

以下是完整的 Python 策略代码,可直接复制到聚宽回测研究环境中运行:

import numpy as np
import pandas as pd
from jqdata import *

def initialize(context):
    # 设定沪深300作为基准
    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.benchmark_index = '000300.XSHG' # 风控基准指数
    g.stock_num = 10                  # 持股数量
    
    # 每月第一个交易日开盘运行调仓
    run_monthly(my_rebalance, monthday=1, time='09:30')
    # 每日运行风控检查
    run_daily(risk_control, time='14:50')

def get_dividend_low_vol_pool(context):
    """筛选高股息、稳定ROE、低波动的股票池"""
    # 1. 获取全A股作为初始池,过滤掉ST、退市及上市未满一年的股票
    all_stocks = list(get_all_securities(['stock'], date=context.current_dt).index)
    current_data = get_current_data()
    initial_pool = [s for s in all_stocks if not current_data[s].is_st 
                    and not current_data[s].paused 
                    and (context.current_dt.date() - get_security_info(s).start_date).days > 365]
    
    # 2. 查询财务数据:ROE > 8% 且 股息率(用应付股利/市值近似或直接查询估值表)
    # 聚宽中可以通过 valuation 表和 indicator 表联合查询
    q = query(
        valuation.code,
        valuation.market_cap,
        indicator.roe
    ).filter(
        valuation.code.in_(initial_pool),
        indicator.roe > 8  # ROE 大于 8%
    )
    df_fundamental = get_fundamentals(q, date=context.previous_date)
    
    if df_fundamental.empty:
        return []
    
    # 3. 计算过去60天的历史波动率
    candidate_stocks = df_fundamental['code'].tolist()
    history_price = history(60, unit='1d', field='close', security_list=candidate_stocks, df=True)
    
    # 计算日收益率的标准差作为波动率
    returns = history_price.pct_change().dropna()
    volatility = returns.std() * np.sqrt(252) # 年化波动率
    
    df_vol = pd.DataFrame({'volatility': volatility})
    df_merged = df_fundamental.merge(df_vol, left_on='code', right_index=True)
    
    # 4. 综合排序:选择波动率最低的前 30 只,再从中选择市值/股息性价比高的前 N 只
    # 这里简化为直接选择波动率最低的前 g.stock_num 只股票
    target_stocks = df_merged.sort_values(by='volatility', ascending=True).head(g.stock_num)['code'].tolist()
    
    return target_stocks

def my_rebalance(context):
    """每月调仓逻辑"""
    g.target_list = get_dividend_low_vol_pool(context)
    if not g.target_list:
        return
        
    # 获取当前持仓
    current_positions = list(context.portfolio.positions.keys())
    
    # 卖出不在目标池中的股票
    for stock in current_positions:
        if stock not in g.target_list:
            order_target(stock, 0)
            log.info(f"卖出不在红利低波池中的股票: {stock}")
            
    # 执行风控仓位分配
    adjust_portfolio_weights(context)

def risk_control(context):
    """每日尾盘风控检查"""
    # 获取沪深300过去120天的收盘价
    hist = attribute_history(g.benchmark_index, 120, '1d', ['close'])
    ma120 = hist['close'].mean()
    current_price = hist['close'][-1]
    
    # 判断是否跌破 MA120
    if current_price < ma120:
        if not g.get('is_risk_mode', False):
            log.warn(f"大盘跌破MA120均线(当前价:{current_price:.2f} < MA120:{ma120:.2f}),触发轻度风控,降仓至95%!")
            g.is_risk_mode = True
            adjust_portfolio_weights(context)
    else:
        if g.get('is_risk_mode', True):
            log.info(f"大盘重回MA120均线之上(当前价:{current_price:.2f} >= MA120:{ma120:.2f}),恢复满仓运行!")
            g.is_risk_mode = False
            adjust_portfolio_weights(context)

def adjust_portfolio_weights(context):
    """根据风控状态调整仓位"""
    if not hasattr(g, 'target_list') or not g.target_list:
        return
        
    # 确定总可用资金比例
    total_ratio = 0.95 if g.get('is_risk_mode', False) else 1.0
    
    # 计算单只股票的目标价值
    total_value = context.portfolio.total_value * total_ratio
    single_stock_value = total_value / len(g.target_list)
    
    # 调仓买入
    for stock in g.target_list:
        order_target_value(stock, single_stock_value)

策略优势与风控效果

  1. 防御性极佳:红利因子(高股息)提供了天然的估值安全边际,而低波因子(Low Volatility)在熊市和震荡市中具有极强的抗跌属性。
  2. 轻度风控避免踏空:传统的均线风控往往在跌破时直接清仓,容易在震荡市中因频繁磨损而产生高额交易成本。本策略采用轻度减仓至 95% 的方案,既保留了对市场的敏感度,又在极端系统性风险来临时锁定了部分现金,是一种非常实用的渐进式风控手段。