You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PyPortfolioOpt库为优化问题添加波动率约束

给PyPortfolioOpt投资组合添加年化波动率约束的正确方法

你当前代码里的ef.add_constraint(lambda x : x[0] == 0.02)是错误的——这个约束是强制第一个资产的权重固定为2%,和波动率限制完全无关,所以你的组合波动率依然高达36.2%。

要实现**年化波动率≤2%**的约束,需要基于协方差矩阵计算组合的年化波动率,并将其作为约束条件添加到优化器中,具体修改如下:

修正后的完整代码

import numpy as np
import pandas as pd
import yfinance as yf  # 修正原代码的拼写错误(yfinances → yfinance)
from pypfopt import risk_models
from pypfopt import expected_returns
from pypfopt import EfficientFrontier

tickers = [ "BLK", "BAC", "AAPL", "TM", "WMT",
       "JD", "INTU", "MA", "UL", "CVS",
       "DIS", "AMD", "NVDA", "PBI", "TGT"]

df = yf.download(tickers)
data = df.copy().dropna()
data.columns = data.columns.droplevel()
data = data["Close"]
data.columns = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", 
               "11", "12", "13", "14", "15"]

mu = expected_returns.mean_historical_return(data)
Sigma = risk_models.sample_cov(data)  # 默认生成日度协方差矩阵

ef = EfficientFrontier(mu, Sigma)

# 定义年化波动率约束函数:限制年化波动率≤2%
def volatility_constraint(weights):
    daily_volatility = np.sqrt(np.dot(weights.T, np.dot(Sigma, weights)))
    annual_volatility = daily_volatility * np.sqrt(252)  # 日度波动率转年化(一年252个交易日)
    return annual_volatility <= 0.02

ef.add_constraint(volatility_constraint)

# 注意:严格波动率约束下,max_sharpe可能无解,改用max_return更合理(在波动率限制内最大化收益)
weights = ef.max_return()
cleaned_weights = ef.clean_weights()

print("优化后权重:")
print(cleaned_weights)
ef.portfolio_performance(verbose=True)

关键说明

  1. 约束逻辑:

    • sample_cov生成的是日度协方差矩阵,因此需要用sqrt(252)将日度波动率转换为年化波动率。
    • 约束函数通过计算权重与协方差矩阵的二次型,得到组合波动率,再限制其年化值不超过2%。
  2. 优化目标选择:

    • 当波动率约束非常严格(比如2%),max_sharpe()可能找不到可行解(因为夏普比率是收益/波动率,低波动率下难以同时满足夏普最大化的条件)。
    • 改用max_return()可以在波动率限制的前提下,最大化组合的预期收益,更符合这类约束场景的需求。

内容的提问来源于stack exchange,提问作者Lazzal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 05:39:53