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

如何在 joinquant 中使用组合优化器构建夏普比率最大化的资产配置策略?

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

问题描述

请根据以下 SEO 主题生成完整页面内容:

Title: joinquant 组合优化器:MaxSharpeRatio 夏普比率最大化模型应用

Question: 如何在 joinquant 中使用组合优化器构建夏普比率最大化的资产配置策略?

解决方案

joinquant 组合优化器:MaxSharpeRatio 夏普比率最大化模型应用

在量化投资与资产配置中,**夏普比率(Sharpe Ratio)**是衡量单位风险下超额收益的核心指标。利用 JoinQuant(聚宽)内置的 portfolio_optimizer 投资组合优化器,我们可以便捷地使用 MaxSharpeRatio 目标函数,在满足多种约束条件(如单标的权重限制、行业暴露限制等)的前提下,自动化计算出最优资产配置权重。


1. 组合优化器核心 API:portfolio_optimizer

在 JoinQuant 中,进行组合优化的核心函数为 portfolio_optimizer,其导入方式与函数定义如下:

from jqlib.optimizer import portfolio_optimizer, MaxSharpeRatio, Bound, WeightConstraint

optimized_weight = portfolio_optimizer(
    date=context.previous_date,
    securities=g.buy_list,
    target=MaxSharpeRatio(rf=0.0, weight_sum_equal=0.5, count=250),
    constraints=[],
    bounds=[Bound(0, 0.1)],
    default_port_weight_range=[0.0, 1.0],
    ftol=1e-09,
    return_none_if_fail=True
)

MaxSharpeRatio 参数详解:

  • rf:年化无风险利率(Risk-Free Rate),默认值为 0.0
  • weight_sum_equal:组合总权重的约束值。在进行夏普比率最大化优化时,通常需要约束组合权重的和为固定值(例如 0.51.0)。
  • count:向前获取历史收益率天数,默认使用过去 250 个交易日(约 1 年)的数据进行协方差与收益估计。

2. 完整策略示例代码

以下是一个完整的月度调仓策略,选定部分上证 50 成分股与 ETF 基金,使用 MaxSharpeRatio 模型进行组合优化并自动调仓:

import pandas as pd
from jqdata import *
from jqlib.optimizer 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')
    
    # 定时运行:每月第一个交易日开盘调仓
    run_monthly(before_market_open, monthday=1, time='09:00', reference_security='000300.XSHG')
    run_monthly(market_open, monthday=1, time='09:30', reference_security='000300.XSHG')

def before_market_open(context):
    # 筛选标的池:上证50后15只股票 + 选定ETF
    etf = ['159902.XSHE', '159903.XSHE', '510050.XSHG', '510880.XSHG', '510440.XSHG']
    g.buy_list = list(get_index_stocks('000016.XSHG')[-15:]) + etf

def market_open(context):
    # 1. 卖出不在股票池中的标的
    sell_list = set(context.portfolio.positions.keys()) - set(g.buy_list)
    for stock in sell_list:
        order_target_value(stock, 0)
        
    # 2. 调用组合优化器计算最优权重(夏普比率最大化)
    # 约束:单只标的权重上限为 10%,组合总权重和约束为 0.5
    optimized_weight = portfolio_optimizer(
        date=context.previous_date,
        securities=g.buy_list,
        target=MaxSharpeRatio(rf=0.0, weight_sum_equal=0.5, count=250),
        constraints=[],
        bounds=[Bound(0, 0.1)],
        default_port_weight_range=[0., 1.0],
        ftol=1e-09,
        return_none_if_fail=True
    )
    
    # 3. 检查优化结果并调仓
    if optimized_weight is None:
        log.warn('组合优化失败,维持现有持仓')
    else:
        log.info('优化权重结果:\n%s' % optimized_weight)
        total_value = context.portfolio.total_value
        for stock, weight in optimized_weight.items():
            target_value = total_value * weight
            order_target_value(stock, target_value)

3. 组合优化的最佳实践与注意事项

  1. 动态复权模式:建议在 initialize 函数中设置 set_option('use_real_price', True),确保组合优化器基于历史真实真实价格进行精确计算,避免未来函数。
  2. 求解失败处理:设置 return_none_if_fail=True,当约束条件过于苛刻导致优化无解时,API 会返回 None。策略应捕获此状态,避免出现报错中断。
  3. 灵活使用 Constraints 与 Bounds
    • Bound(low, high):限制单只股票的权重(例如单股不超过 10%)。
    • IndustryConstraint / MarketConstraint:可用于限制特定行业或资产类别(股票/ETF)的总权重上限,进一步实现多资产风险分散。