83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
import numpy as np
|
||
import pandas as pd
|
||
import matplotlib.pyplot as plt
|
||
import scipy.optimize as sco
|
||
import yfinance as yf
|
||
|
||
# 下载资产历史数据
|
||
assets = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA'] # 资产代码
|
||
data = yf.download(assets, start="2020-01-01", end="2023-01-01")['Adj Close']
|
||
print(data)
|
||
|
||
# 计算每日收益率
|
||
returns = data.pct_change().dropna()
|
||
print(returns)
|
||
|
||
# 计算年化预期收益和协方差矩阵
|
||
annual_returns = returns.mean() * 252
|
||
cov_matrix = returns.cov() * 252
|
||
print(annual_returns)
|
||
print(cov_matrix)
|
||
|
||
# 定义组合的预期收益和风险(方差)
|
||
def portfolio_performance(weights, mean_returns, cov_matrix):
|
||
returns = np.sum(weights * mean_returns)
|
||
volatility = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
|
||
return returns, volatility
|
||
|
||
# 定义目标函数:最小化风险(方差)
|
||
def minimize_volatility(weights, mean_returns, cov_matrix):
|
||
return portfolio_performance(weights, mean_returns, cov_matrix)[1]
|
||
|
||
# 定义约束条件
|
||
def constraint_sum(weights):
|
||
return np.sum(weights) - 1
|
||
|
||
# 初始化权重和边界(每个资产的权重在0-1之间)
|
||
num_assets = len(assets)
|
||
bounds = tuple((0, 1) for asset in range(num_assets))
|
||
initial_weights = num_assets * [1. / num_assets] # 初始等权重
|
||
|
||
# 定义约束条件:总权重为1
|
||
constraints = ({'type': 'eq', 'fun': constraint_sum})
|
||
|
||
# 优化组合,使得组合的方差最小
|
||
opt_result = sco.minimize(minimize_volatility, initial_weights, args=(annual_returns, cov_matrix),
|
||
method='SLSQP', bounds=bounds, constraints=constraints)
|
||
|
||
# 提取最优权重
|
||
optimal_weights = opt_result.x
|
||
|
||
# 计算最优组合的收益和风险
|
||
optimal_return, optimal_volatility = portfolio_performance(optimal_weights, annual_returns, cov_matrix)
|
||
|
||
# 输出最优组合结果
|
||
print("最优资产组合权重:")
|
||
for i, asset in enumerate(assets):
|
||
print(f"{asset}: {optimal_weights[i]:.2%}")
|
||
|
||
print(f"\n最优组合的年化预期收益: {optimal_return:.2%}")
|
||
print(f"最优组合的年化风险(标准差): {optimal_volatility:.2%}")
|
||
|
||
# 可视化有效前沿
|
||
def plot_efficient_frontier(mean_returns, cov_matrix, num_portfolios=10000):
|
||
results = np.zeros((3, num_portfolios))
|
||
for i in range(num_portfolios):
|
||
weights = np.random.random(num_assets)
|
||
weights /= np.sum(weights)
|
||
portfolio_return, portfolio_volatility = portfolio_performance(weights, mean_returns, cov_matrix)
|
||
results[0, i] = portfolio_return
|
||
results[1, i] = portfolio_volatility
|
||
results[2, i] = results[0, i] / results[1, i] # 计算夏普比率
|
||
|
||
plt.figure(figsize=(10, 6))
|
||
plt.scatter(results[1, :], results[0, :], c=results[2, :], cmap='viridis')
|
||
plt.colorbar(label='Sharpe Ratio')
|
||
plt.scatter(optimal_volatility, optimal_return, c='red', marker='*', s=200) # 最优组合
|
||
plt.title('Efficient Frontier')
|
||
plt.xlabel('Volatility (Risk)')
|
||
plt.ylabel('Return')
|
||
plt.show()
|
||
|
||
# 绘制有效前沿
|
||
plot_efficient_frontier(annual_returns, cov_matrix) |