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

joinquant 投资组合优化:如何使用 MaxSharpeRatio 实现夏普比率最大化策略

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

问题描述

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

Title: joinquant 投资组合优化:MaxSharpeRatio 夏普比率最大化策略实战

Question: 请问在 joinquant 中如何使用 portfolio_optimizer 构建夏普比率最大化的投资组合?

解决方案

joinquant 投资组合优化:MaxSharpeRatio 夏普比率最大化策略实战

在量化投资中,**夏普比率(Sharpe Ratio)**是衡量策略性价比(单位风险带来的超额收益)的核心指标。聚宽(joinquant)内置了强大的投资组合优化器 portfolio_optimizer,支持直接使用 MaxSharpeRatio 目标函数快速求解最佳资产配置权重。


一、portfolio_optimizer 及 MaxSharpeRatio 函数解析

在聚宽平台中,使用内置模块 jqlib.optimizer 可以轻松调用优化器。

1. 目标函数:MaxSharpeRatio

MaxSharpeRatio(rf=0.0, weight_sum_equal=1.0, count=250)
  • rf: 年化无风险利率,默认为 0.0。
  • weight_sum_equal: 组合总权重的约束值,默认为 1.0。在最大化夏普比率时,通常约束组合权重和为特定值(如 0.5 或 1.0)。
  • count: 回溯计算历史收益率的天数,默认为 250(约 1 个交易年)。

2. 优化器主函数:portfolio_optimizer

portfolio_optimizer(date, securities, target, constraints, bounds=[Bound(0.0, 1.0)], default_port_weight_range=[0.0, 1.0], ftol=1e-9, return_none_if_fail=True)
  • date: 优化计算发生的日期(通常传 context.previous_date 避免未来函数)。
  • securities: 待优化的标的代码列表(如股票池/ETF池)。
  • target: 优化目标函数,此处传入 MaxSharpeRatio(...)
  • constraints: 约束条件列表(如权重和限制等)。
  • bounds: 单个标的的权重边界限制,如 [Bound(0, 0.1)] 表示单只标的权重不超过 10%。

二、夏普比率最大化策略完整 Python 源码

以下策略每月初在上证 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')
    
    # 设定每月第1个交易日定时调仓
    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部分成分股 + ETF
    etf_list = ['159902.XSHE', '510050.XSHG', '510880.XSHG']
    stocks = list(get_index_stocks('000016.XSHG')[-15:])
    g.buy_list = stocks + etf_list

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. 调用投资组合优化器,构建夏普比率最大化组合
    # 设定无风险利率为 0,单只标的权重上限为 10%
    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", 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)

三、注意事项与实战技巧

  1. 避开未来函数:在传入 date 参数时,请务必传入 context.previous_date(前一交易日),以确保策略仅使用盘前可获取的已知历史数据进行矩阵求解。
  2. 单标的权重约束(Bound):由于未受限制的夏普最大化往往会将过高权重集中在极少数极端走势的标的上,强烈建议通过 bounds=[Bound(0, 0.1)] 设置单标的上限(如 10% 或 20%),实现风险分散。
  3. 求解失败处理:由于历史协方差矩阵可能存在奇异性或无解情况,建议将 return_none_if_fail 设为 True,并在返回 None 时添加日志提示或保底调仓逻辑。