上周在介绍VaR风险管理时,提到投资组合的风险并不等于各个资产的风险,和它们的价格相关性有关。以两个资产为例,如果它们的正相关性非常强,也就说同涨同跌,那么分散做多投资不会降低风险,如果负相关性很强,分散投资可以显著降低风险。自然的问题是,在投资一个组合时,如何在一定的风险水平下,收益最大化?就要用到今天要介绍的马科维茨理论。
马科维茨投资组合理论(Modern Portfolio Theory, MPT),由哈里·马科维茨于1952年提出,是一种投资组合选择的数学框架,旨在通过选择不同的风险资产组合来最大化预期收益,同时控制风险。核心思想是资产之间的价格不完全同步变动(即资产之间存在不完全的相关性),可以通过资产配置的多样化来降低整体的投资风险。
预期收益率:这是投资者持有资产或投资组合预期能够获得的收益,通常基于历史收益数据来预测。
$E(R_p) = \sum_{i=1}^{n} w_i E(R_i)$
其中,$E(R_p)$ 是投资组合的预期收益率,$w_i$ 是第 $i$ 个资产在投资组合中的权重,$E(R_i)$ 是第 $i$ 个资产的预期收益率。
风险(波动性或标准差):用来衡量投资回报的不确定性或投资的波动性。
$\sigma_p = \sqrt{\sum_{i=1}^{n} \sum_{j=1}^{n} w_i w_j \sigma_{ij}}$
其中,$\sigma_p$ 是投资组合的总风险,$\sigma_{ij}$ 是资产 $i$ 和资产 $j$ 的协方差,它衡量了这两个资产之间的价格变动关系。
协方差:衡量两个资产之间价格变动的相互关系。
$\sigma_{ij} = \rho_{ij} \sigma_i \sigma_j$
其中,$\rho_{ij}$ 是资产 $i$ 和资产 $j$ 的相关系数,$\sigma_i$ 和 $\sigma_j$ 分别是资产 $i$ 和资产 $j$ 的标准差。
有效边界:在风险-收益坐标系统中,有效边界是那些给定风险水平下能够提供最大预期收益的投资组合集合。
上图就是一个有效边界的示意图,每个点代表一种不同权重的投资组合,横坐标为波动率也就是风险水平,纵坐标为收益率。显然,我们关注于图中的上边,这条边在相同的风险水平下,取得了最高的收益。
在量化交易和投资组合管理中,应用这些原则需要对历史数据进行统计分析,使用数学模型来估计各种资产的预期收益、标准差和协方差。然后,运用优化技术来找到最佳的资产权重配置。这个过程通常涉及到复杂的数学运算和大量的计算机处理,这也是为什么量化分析在现代金融领域变得非常重要的原因。下面将以具体的Python例子来说明如何优化。
计算马科维茨最优组合是一个多步骤的过程,涉及到数据准备、模拟投资组合、计算指标等多个关键步骤。参考资料:https://plotly.com/python/v3/ipython-notebooks/markowitz-portfolio-optimization/
获取行情数据:
get_data
函数,获取所选数字货币的历史价格数据。这是计算收益率和风险所必需的数据,它们用于构建投资组合和计算夏普比率。计算收益率和风险:
calculate_returns_risk
函数计算每个数字货币的年化收益率和年化风险(标准差)。这是为了量化每个资产的历史表现,以便在最优组合中使用。计算马科维茨最优组合:
calculate_optimal_portfolio
函数,模拟了多个投资组合。在每个模拟中,随机生成资产权重,然后根据这些权重计算投资组合的预期收益率和风险。整个过程的目的是找到在给定风险水平下获得最佳预期收益的投资组合。通过模拟多个可能的组合,投资者可以更好地了解不同配置的表现,并选择最适合其投资目标和风险承受能力的组合。这种方法有助于优化投资决策,使投资更有效。
import numpy as np
import pandas as pd
import requests
import matplotlib.pyplot as plt
# 获取行情数据
def get_data(symbols):
data = []
for symbol in symbols:
url = 'https://api.binance.com/api/v3/klines?symbol=%s&interval=%s&limit=1000'%(symbol,'1d')
res = requests.get(url)
data.append([float(line[4]) for line in res.json()])
return data
def calculate_returns_risk(data):
returns = []
risks = []
for d in data:
daily_returns = np.diff(d) / d[:-1]
annualized_return = np.mean(daily_returns) * 365
annualized_volatility = np.std(daily_returns) * np.sqrt(365)
returns.append(annualized_return)
risks.append(annualized_volatility)
return np.array(returns), np.array(risks)
# 计算马科维茨最优组合
def calculate_optimal_portfolio(returns, risks):
n_assets = len(returns)
num_portfolios = 3000
results = np.zeros((4, num_portfolios), dtype=object)
for i in range(num_portfolios):
weights = np.random.random(n_assets)
weights /= np.sum(weights)
portfolio_return = np.sum(returns * weights)
portfolio_risk = np.sqrt(np.dot(weights.T, np.dot(np.cov(returns, rowvar=False), weights)))
results[0, i] = portfolio_return
results[1, i] = portfolio_risk
results[2, i] = portfolio_return / portfolio_risk
results[3, i] = list(weights) # 将权重转换为列表
return results
symbols = ['BTCUSDT','ETHUSDT', 'BNBUSDT','LINKUSDT','BCHUSDT','LTCUSDT']
data = get_data(symbols)
returns, risks = calculate_returns_risk(data)
optimal_portfolios = calculate_optimal_portfolio(returns, risks)
max_sharpe_idx = np.argmax(optimal_portfolios[2])
optimal_return = optimal_portfolios[0, max_sharpe_idx]
optimal_risk = optimal_portfolios[1, max_sharpe_idx]
optimal_weights = optimal_portfolios[3, max_sharpe_idx]
# 输出结果
print("最优组合:")
for i in range(len(symbols)):
print(f"{symbols[i]}权重: {optimal_weights[i]:.4f}")
print(f"预期收益率: {optimal_return:.4f}")
print(f"预期风险(标准差): {optimal_risk:.4f}")
print(f"夏普比率: {optimal_return / optimal_risk:.4f}")
# 可视化投资组合
plt.figure(figsize=(10, 5))
plt.scatter(optimal_portfolios[1], optimal_portfolios[0], c=optimal_portfolios[2], marker='o', s=3)
plt.title('portfolio')
plt.xlabel('std')
plt.ylabel('return')
plt.colorbar(label='sharp')
plt.show()
最终输出结果: 最优组合: BTCUSDT权重: 0.0721 ETHUSDT权重: 0.2704 BNBUSDT权重: 0.3646 LINKUSDT权重: 0.1892 BCHUSDT权重: 0.0829 LTCUSDT权重: 0.0209 预期收益率: 0.4195 预期风险(标准差): 0.1219 夏普比率: 3.4403