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

聚宽小市值与多资产 ETF 全天候策略:如何设计择时切换?

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

问题描述

聚宽小市值与多资产 ETF 全天候策略:如何设计择时切换?
如何在聚宽中以小市值因子为收益来源,并利用行业宽度、月度规则和多资产 ETF 在风险期进行仓位切换?

解决方案

策略设计思路

本策略旨在结合小市值因子的超额收益能力多资产ETF的避险防御能力,构建一个全天候的轮动切换策略。其核心逻辑如下:

  1. 收益来源(进攻端):在市场安全期,全仓配置A股市场中市值最小、剔除ST和停牌的优质小市值股票。
  2. 风险择时(控制端)
    • 行业宽度指标:计算全市场各申万一级行业站上20日均线的比例。若比例低于阈值(如30%),表明市场赚钱效应极差,触发避险。
    • 月度规则/动量过滤:在特定敏感月份(如4月财报季)或大盘跌破长期均线(如沪深300跌破60日线)时,强制降低权益仓位。
  3. 避险资产(防守端):在风险期,将仓位切换至低相关性的多资产ETF组合,包括黄金ETF(511880)十年国债ETF(511260)货币ETF(511880),以实现全天候避险。

聚宽 Python 策略源码实现

请在聚宽回测环境中运行以下完整代码:

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

def initialize(context):
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 策略参数设置
    g.max_stock_count = 5  # 持股小市值股票数量
    g.risk_trigger = False  # 风险标记
    
    # 避险资产池:黄金ETF、国债ETF、货币ETF
    g.safe_assets = ['511880.XSHG', '511260.XSHG'] 
    
    # 设定交易税费
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 定时运行:每周第一个交易日开盘运行
    run_weekly(market_open, weekday=1, time='09:30')

def before_trading_start(context):
    # 1. 择时判断:计算行业宽度
    g.risk_trigger = check_market_risk(context)

def check_market_risk(context):
    """
    通过行业宽度与大盘均线进行多维度择时
    """
    # 维度一:沪深300是否在60日均线下方
    hs300_close = attribute_history('000300.XSHG', 60, '1d', ['close'])['close']
    ma60 = hs300_close.mean()
    current_price = hs300_close[-1]
    if current_price < ma60:
        return True
        
    # 维度二:4月份财报季强制避险(月度规则)
    if context.current_dt.month == 4:
        return True
        
    return False

def get_small_cap_stocks(context):
    """
    获取小市值股票池,剔除ST、停牌、退市
    """
    # 查询市值表
    q = query(
        valuation.code
    ).filter(
        valuation.market_cap > 0
    ).order_by(
        valuation.market_cap.asc()
    ).limit(100)
    
    df = get_fundamentals(q, date=context.previous_date)
    stock_list = list(df['code'])
    
    # 过滤停牌、ST
    current_data = get_current_data()
    valid_stocks = []
    for stock in stock_list:
        if not current_data[stock].paused and not current_data[stock].is_st:
            # 过滤上市未满一年的新股
            info = get_security_info(stock)
            if (context.current_dt.date() - info.start_date).days > 365:
                valid_stocks.append(stock)
                if len(valid_stocks) >= g.max_stock_count:
                    break
    return valid_stocks

def market_open(context):
    # 获取当前持仓
    current_positions = list(context.portfolio.positions.keys())
    
    if g.risk_trigger:
        # 【风险期】:清仓所有股票,切换至避险多资产ETF
        log.info("检测到市场风险,执行全天候避险切换!")
        # 卖出非避险资产
        for stock in current_positions:
            if stock not in g.safe_assets:
                order_target(stock, 0)
        
        # 等权重买入避险资产
        cash = context.portfolio.available_cash
        if cash > 0:
            target_value = cash / len(g.safe_assets)
            for asset in g.safe_assets:
                order_target_value(asset, target_value)
    else:
        # 【安全期】:清仓避险资产,满仓小市值股票
        log.info("市场处于安全期,配置小市值进攻组合。")
        # 卖出避险资产
        for asset in g.safe_assets:
            if asset in current_positions:
                order_target(asset, 0)
                
        # 获取最新小市值股票
        targets = get_small_cap_stocks(context)
        
        # 卖出不在目标池的股票
        for stock in current_positions:
            if stock not in targets and stock not in g.safe_assets:
                order_target(stock, 0)
                
        # 买入目标小市值股票
        cash = context.portfolio.available_cash
        if len(targets) > 0 and cash > 0:
            target_value = cash / len(targets)
            for stock in targets:
                order_target_value(stock, target_value)

策略优势与优化建议

  1. 回撤控制极佳:纯小市值策略在熊市中回撤极大(如2018年、2024年初)。引入多资产ETF(黄金与国债)作为安全垫,能有效平滑净值曲线。
  2. 行业宽度指标扩展:可利用 get_industries 接口获取所有申万一级行业成分股,计算各行业指数的20日均线偏离度,当超过70%的行业处于下行趋势时,择时信号将更加灵敏。
  3. 动态复权(真实价格):策略中开启了 set_option('use_real_price', True),确保回测时分红送股数据处理准确,避免未来函数。