Python Portfolio Optimizer 无法生成有效前沿仅输出散点团问题求助
问题核心原因
- 代码未计算日度收益率的协方差矩阵
cov_matrix,计算组合波动率时调用了未定义的变量,导致散点分布逻辑错误 - 仅生成了随机权重的组合散点,未通过凸优化求解有效边界上的最优组合,无法生成连续的前沿曲线
- 循环内重复定义
data字典属于无效代码,且weights变量行存在缩进错误
修复步骤与完整代码
首先在计算完单资产年化波动率后,补全协方差矩阵的定义:
# 你原有代码的前面部分保持不变,补全下面两行 log_ret = df.pct_change().apply(lambda x: np.log(1+x)).dropna() cov_matrix = log_ret.cov() # 之前完全缺失的协方差矩阵计算步骤
修正原有循环的缩进问题和data定义位置:
p_ret = [] p_vol = [] p_weights = [] num_assets = len(df.columns) num_portfolios = 10000 for portfolio in range(num_portfolios): weights = np.random.random(num_assets) weights = weights/np.sum(weights) # 修正原代码的缩进错误 p_weights.append(weights) returns = np.dot(weights, ind_er) p_ret.append(returns) var = cov_matrix.mul(weights, axis=0).mul(weights, axis=1).sum().sum() sd = np.sqrt(var) ann_sd = sd*np.sqrt(250) p_vol.append(ann_sd) # 把data定义移到循环外面 data = {'Returns':p_ret, 'Volatility':p_vol} portfolios = pd.DataFrame(data)
新增有效前沿求解代码:
import matplotlib.pyplot as plt from scipy.optimize import minimize # 定义组合波动率计算函数 def portfolio_vol(weights): return np.sqrt(np.dot(weights.T, np.dot(cov_matrix*250, weights))) # 定义组合收益计算函数 def portfolio_ret(weights): return np.dot(weights, ind_er) # 约束条件:权重和为1 cons = ({'type':'eq', 'fun':lambda x: np.sum(x) - 1}) # 边界:每个资产权重在0到1之间(不允许做空) bnds = tuple((0,1) for _ in range(num_assets)) # 遍历不同收益目标,求最小波动率,得到有效前沿点 target_returns = np.linspace(min(p_ret), max(p_ret), 100) efficient_vols = [] for ret in target_returns: cons_new = (cons, {'type':'eq', 'fun':lambda x: portfolio_ret(x) - ret}) # 初始权重用平均权重 init_w = np.ones(num_assets)/num_assets result = minimize(portfolio_vol, init_w, method='SLSQP', bounds=bnds, constraints=cons_new) efficient_vols.append(result['fun'])
新增绘图代码即可同时展示散点和有效前沿:
plt.figure(figsize=(10,6)) plt.scatter(portfolios['Volatility'], portfolios['Returns'], c=portfolios['Returns']/portfolios['Volatility'], cmap='viridis', alpha=0.6) plt.plot(efficient_vols, target_returns, 'r-', linewidth=3, label='有效前沿') plt.xlabel('年化波动率') plt.ylabel('年化收益率') plt.legend() plt.colorbar(label='夏普比率') plt.show()
其他TODO问题说明
- 对数收益率的使用是合理的,符合复利计算逻辑,无需修改
- 250是通用的年化交易日系数,A股可调整为252,差异极小,不影响有效前沿形状
内容的提问来源于stack exchange,提问作者Sloane Marshall
相关产品推荐
相关产品推荐

