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

使用Scipy进行投资组合优化:风险得分异常偏低问题排查

问题排查:有效前沿未贴合投资组合上边界

我用Python代码解决「指定风险水平下选择最优投资组合权重以优化收益」的问题,具体配置如下:

  • 4类资产构建有效前沿:
    1. 3只股票:仅允许多头头寸
    2. 1只标普500 ETF:允许多头或最高200%杠杆的空头头寸
      已提前计算方差-协方差矩阵及资产统计量,但运行代码绘制有效前沿后,发现红色有效前沿线未贴合有效投资组合的上边界,不符合金融理论预期,求排查问题。

代码实现

#GENERATING RANDOM WEIGHTS FOR QUESTION 2
np.random.seed(42)

num_portfolios = 10000
weights = np.zeros((num_portfolios, 4))

for i in range(num_portfolios):
    # Step 1: Generate initial random weights for the first three stocks
    w = np.random.random(3)
    w = w / w.sum() * 2  # Normalize these weights to sum to a value between 0 and 2

    # Step 2: Weight for the S&P500 ETF can be between -1 and 1
    w_spx = np.random.uniform(-1, 1)
    
    # Step 3: Combine weights and adjust to ensure they sum to 1
    total_investment = w.sum()
    total = total_investment + w_spx  # This can range from 1 to 3
    weights[i, :3] = w / total  # Scale down the weights for the first three stocks
    weights[i, 3] = w_spx / total  # Adjust the S&P500 ETF weight to maintain the sum of 1

# Check that the weights sum to 1 and the S&P500 weight is at maximum -1
assert np.allclose(weights.sum(axis=1), 1) and (weights[:, 3] >= -1).all()
# Portfolios returns
portfolio_returns2 = np.dot(weights, annual_returns)

# Portfolios volatility
portfolio_volatilities2 = np.sqrt(np.diag(np.dot(weights, np.dot(cov_mat, weights.T))))
portfolio_var2 = np.diag(np.dot(weights, np.dot(cov_mat, weights.T)))
portfolios_2 = pd.DataFrame({'ret':portfolio_returns2, 'risk':portfolio_var2})
weights = pd.DataFrame(weights)
weights.columns = ['w1', 'w2', 'w3', 'w4']
portfolios_q2 = portfolios_2.join(weights)

portfolios_q2.head()
#Again, to find the efficient frontier, we generate the "grids" over portfolio returns
#we want to calculate the minimum variance for all the point on the grids of portfolio returns

min_var_ret2 = portfolios_2.ret.iloc[portfolios_2.risk.idxmin()] 

eff_ret2 = np.arange(min_var_ret2, portfolios_2.ret.max(), 
                  (portfolios_2.ret.max()-min_var_ret2)/100)
eff_risk2 = np.zeros(len(eff_ret2))


#then we can use the minimize function over each point on "eff_risk":
f = lambda x: x@cov_mat@x.T
x0 = np.array((0.25, 0.25, 0.25, 0.25)) #set the initial value of x, y, w, z

for ind in range(len(eff_ret2)):
    
    #set the optimization problem constraints:
    cons = ({'type':'eq','fun':lambda x:x[0] + x[1] + x[2] + x[3] - 1},  #constraint:x+y+z+w = 1
        {'type':'eq','fun':lambda x:x@asset_ret - eff_ret[ind]},  #constraint: set the return of the portfolio to be constant
        {'type': 'ineq', 'fun': lambda x: x[0]},                        # Weights of first 3 stocks must be >= 0
        {'type': 'ineq', 'fun': lambda x: x[1]},
        {'type': 'ineq', 'fun': lambda x: x[2]},
        {'type': 'ineq', 'fun': lambda x: 1 + x[3]},                    # Weight of S&P500 index can be down to -1
        {'type': 'ineq', 'fun': lambda x: 2 - x[0] - x[1] - x[2]}       # Sum of weights of first 3 stocks <= 2
    )
    
#find the minimum variance of the portfolio given certain return level
    res = minimize(f, x0, constraints=cons)
    eff_risk2[ind] = res.fun
    #print(eff_y)

    
#now the eff_x and eff_y describe the risk and return combination on the efficient frontier.
#let's plot the efficient frontier:

plt.subplots(figsize=[10,10])
plt.xlabel('Risk', fontsize=18)
plt.ylabel('Return', fontsize=16)
plt.scatter(portfolios_q2['risk'], portfolios_q2['ret'],marker='o', s=10, alpha=0.3)
plt.scatter(eff_risk2, eff_ret2, color='r', marker='x', linestyle='-', linewidth=1)

问题排查关键点

  1. 约束条件错误:
    • 标普500 ETF的空头限制应为权重≤-2(对应200%杠杆空头),但当前约束1 + x[3] ≥ 0仅允许权重≥-1,直接限制了空头杠杆上限,无法构建理论上的高收益组合。
    • 前三只股票权重总和约束2 - x[0]-x[1]-x[2] ≥0(总和≤2),结合权重总和为1的条件,当ETF为-2权重时,前三只股票权重总和应为3,当前约束限制了该情况,导致无法生成更高收益的组合。
  2. 有效前沿收益区间不足:
    • eff_ret2的上限取随机组合的最大收益,但随机组合未覆盖所有可行的极端头寸组合,导致有效前沿仅覆盖部分区间,无法贴合真实上边界。
  3. 优化初始值局限性:
    • 固定初始值x0 = (0.25,0.25,0.25,0.25)可能导致优化陷入局部最优,未找到全局最小方差的高收益组合,建议每次迭代根据目标收益调整初始值。
  4. 风险指标不一致:
    • 随机组合的risk列用方差,若绘图预期用波动率(标准差),会导致轴刻度错位,需统一风险指标(方差或标准差)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 23:48:16