🚀 AI 一键生成 joinquant 策略代码

如何使用 JoinQuant 优化器构建风险最低的投资组合?

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

问题描述

请帮我编写一个风险最低的资产配置策略

解决方案

为了实现“风险最低”的资产配置策略,最科学的方法是采用最小方差模型(Minimum Variance Model)。该模型利用现代投资组合理论(MPT),通过计算不同资产之间的历史波动率和相关性,自动计算出组合波动率最低的权重配置。

为了进一步降低风险,我们在资产池中选择了低相关性本身波动较小的ETF标的,包括债券、货币基金、黄金和宽基指数。

策略核心逻辑

  1. 资产池选择
    • 国债ETF (511010.XSHG):核心防守资产,波动极低。
    • 银华日利 (511880.XSHG):货币基金ETF,现金管理工具,风险接近零。
    • 黄金ETF (518880.XSHG):避险资产,与其他资产相关性低。
    • 沪深300ETF (510300.XSHG):少量配置以获取市场平均收益,利用负相关性对冲风险。
  2. 优化目标:使用聚宽内置的 MinVariance 优化器,目标是最小化组合的历史方差(风险)。
  3. 调仓频率:按月调仓,根据最新的市场波动率调整权重。

以下是完整的策略代码:

# -*- coding: utf-8 -*-
# 导入函数库
from jqdata import *
from jqlib.optimizer import *
import pandas as pd

def initialize(context):
    """
    初始化函数
    """
    # 1. 设定基准(这里使用国债指数作为基准更合适,但为了对比通常设为沪深300)
    set_benchmark('000300.XSHG')
    
    # 2. 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 3. 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    # 4. 设定ETF基金交易手续费
    # ETF买卖无印花税,佣金设为万分之三,最低5元
    set_order_cost(OrderCost(open_tax=0, close_tax=0, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='fund')
    
    # 5. 定义低风险资产池
    # 511010: 国债ETF (极低风险)
    # 511880: 银华日利 (货币ETF,极低风险)
    # 518880: 黄金ETF (避险资产,低相关性)
    # 510300: 沪深300ETF (权益类资产,用于分散化)
    g.etf_pool = [
        '511010.XSHG', 
        '511880.XSHG', 
        '518880.XSHG', 
        '510300.XSHG'
    ]
    
    # 6. 设定调仓周期:每月第一个交易日运行
    run_monthly(rebalance, monthday=1, time='09:30')

def rebalance(context):
    """
    调仓函数:计算最小方差权重并调仓
    """
    log.info("开始进行最小方差资产配置优化...")
    
    # 获取当前日期
    date = context.previous_date
    
    # 1. 使用聚宽内置优化器计算权重
    # target=MinVariance(count=250): 目标是最小化过去250个交易日的组合方差
    # constraints: 约束条件,这里限制总权重之和为1 (100%仓位)
    # bounds: 边界条件,每个标的权重在 0.0 到 1.0 之间 (不做空)
    try:
        optimized_weight = portfolio_optimizer(
            date=date,
            securities=g.etf_pool,
            target=MinVariance(count=250), 
            constraints=[WeightConstraint(low=1.0, high=1.0)],
            bounds=[Bound(0.0, 1.0)],
            default_port_weight_range=[0.0, 1.0],
            ftol=1e-09,
            return_none_if_fail=True
        )
    except Exception as e:
        log.error("优化器运行异常: %s" % e)
        return

    # 2. 检查优化结果
    if optimized_weight is None:
        log.warn("组合优化失败,本次不调仓")
        return
    
    log.info("目标权重: \n%s" % optimized_weight)
    
    # 3. 执行调仓
    # 获取当前总资产
    total_value = context.portfolio.total_value
    
    # 先卖出不在目标池或权重降低的标的
    current_positions = context.portfolio.positions
    for security in current_positions:
        if security not in optimized_weight.index:
            order_target_value(security, 0)
    
    # 根据优化后的权重买入/调整
    for security in g.etf_pool:
        if security in optimized_weight.index:
            target_value = total_value * optimized_weight[security]
            order_target_value(security, target_value)

def handle_data(context, data):
    """
    按分钟回测时必须实现,这里为空
    """
    pass

策略详解

  1. 资产选择逻辑

    • 策略没有只选择单一资产,而是构建了一个组合。因为单一资产(即使是债券)也面临特定风险(如利率风险)。
    • 通过引入货币ETF国债ETF,奠定了极低波动的基础。
    • 优化器会自动识别出权益类资产(沪深300)的高波动性,因此在计算“最小方差”时,通常会给予权益类资产极低的权重(往往低于5%),而将绝大部分仓位分配给国债和货币基金。
  2. 优化器设置 (MinVariance)

    • 使用了 jqlib.optimizer 中的 MinVariance 目标函数。
    • count=250 表示使用过去一年的历史数据来计算协方差矩阵。这意味着策略会根据长期的波动特征来配置资产,避免因短期市场噪音频繁剧烈调仓。
  3. 预期表现

    • 回撤极小:由于重仓债券和货币基金,历史最大回撤通常控制在极低水平(往往小于2%)。
    • 收益稳定:收益率略高于货币基金,属于典型的理财替代型策略。

Q&A

Q: 为什么不直接全仓买货币基金?
A: 全仓货币基金虽然风险极低,但收益也最低且无法抵抗通胀。最小方差策略利用了资产间的不完全相关性(例如股票跌时债市可能涨),在数学上可以在保持同等低风险水平的同时,通过分散化获得比单一货币基金稍高的夏普比率。

Q: 这个策略适合什么资金?
A: 适合对回撤极其敏感、追求绝对收益、或者作为闲置资金管理的投资者。

Q: 如果我想稍微提高一点收益怎么办?
A: 可以修改代码中的 target 参数。将 MinVariance 改为 RiskParity(风险平价),这会稍微增加股票和黄金的配置比例,风险略微上升,但长期潜在收益会更高。