马科维茨的投资组合理论介绍(1)

量化 2023年7月24日

这是现代投资组合理论的基础,CTA交易人员基本都要了解一下。

Harry Markowitz 在他 1952 年题为“投资组合选择”的论文中介绍了现代投资组合理论。他首先概述了投资组合选择是一个两步过程;首先,投资者必须考虑可用资产的未来表现(风险和回报),然后决定如何构建投资组合(即为每项资产分配多少钱)。

马科维茨专注于投资组合构建方面,并将预测未来表现这一更具投机性的任务留给了读者。事实上,在整篇论文中,回报都被假设遵循简单的高斯(正态)分布。这一假设是整个现代投资组合理论的基础,但也引起了很多批评,因为股票价格回报已被证明不遵循正态分布。

然而,其中依旧有很多有意义的深入的思考,一起了解为马科维茨赢得诺贝尔奖的数学理论。

我们的数据包含六只股票的每日回报,如下所示。回报范围为2000年初至2018年底。

我们可以使用该数据中的两行代码立即获得预期年化回报、方差和协方差矩阵。我们注意到,通过使用这样的过去数据,我们假设未来将遵循过去的趋势。这在金融市场上是一个颇具争议的假设,但目前来说是可行的。

#-- Get annualised mean returns
mus = (1+daily_returns.mean())**252 - 1

#-- Get covariances and variances
#- Variance along diagonal of covariance matrix
#- Multiply by 252 to annualise it
#- https://quant.stackexchange.com/questions/4753/annualized-covariance
cov = daily_returns.cov()*252

获取投资组合

在不使用 numpy 以外的任何包的情况下,我们可以使用以下代码快速轻松地创建均值方差图。均值方差图使我们能够看到每个投资组合的风险和回报之间的权衡。


#- How many assests to include in each portfolio
n_assets = 5
#-- How many portfolios to generate
n_portfolios = 1000

#-- Initialize empty list to store mean-variance pairs for plotting
mean_variance_pairs = []

np.random.seed(75)
#-- Loop through and generate lots of random portfolios
for i in range(n_portfolios):
    #- Choose assets randomly without replacement
    assets = np.random.choice(list(daily_returns.columns), n_assets, replace=False)
    #- Choose weights randomly
    weights = np.random.rand(n_assets)
    #- Ensure weights sum to 1
    weights = weights/sum(weights)

    #-- Loop over asset pairs and compute portfolio return and variance
    #- https://quant.stackexchange.com/questions/43442/portfolio-variance-explanation-for-equation-investments-by-zvi-bodie
    portfolio_E_Variance = 0
    portfolio_E_Return = 0
    for i in range(len(assets)):
        portfolio_E_Return += weights[i] * mus.loc[assets[i]]
        for j in range(len(assets)):
            #-- Add variance/covariance for each asset pair
            #- Note that when i==j this adds the variance
            portfolio_E_Variance += weights[i] * weights[j] * cov.loc[assets[i], assets[j]]
            
    #-- Add the mean/variance pairs to a list for plotting
    mean_variance_pairs.append([portfolio_E_Return, portfolio_E_Variance])

我们使用以下公式计算预期回报:
\[ \operatorname{E}(R_p)=\sum_iw_i\operatorname{E}(R_i) \]
以及以下投资组合方差公式(包括协方差和个体方差):
\[ \sigma_p^2=\sum_i\sum_jw_iw_j\sigma_{ij} \]

使用我们生成的均值-方差对列表,我们现在可以绘制这些投资组合:

#-- Plot the risk vs. return of randomly generated portfolios
#- Convert the list from before into an array for easy plotting
mean_variance_pairs = np.array(mean_variance_pairs)
risk_free_rate=0 #-- Include risk free rate here for sharpe ratio

#-- Create Plot
fig = go.Figure()
fig.add_trace(go.Scatter(x=mean_variance_pairs[:,1]**0.5, 
                         y=mean_variance_pairs[:,0], 
                      #- Add color scale for sharpe ratio   
                      marker=dict(color=(mean_variance_pairs[:,0]-risk_free_rate)/(mean_variance_pairs[:,1]**0.5), 
                                  showscale=True, 
                                  size=7,
                                  line=dict(width=1),
                                  colorscale="RdBu",
                                  colorbar=dict(title="Sharpe<br>Ratio")
                                 ), 
                      mode='markers'))
#- Add title/labels
fig.update_layout(template='plotly_white',
                  xaxis=dict(title='Annualised Risk (Volatility)'),
                  yaxis=dict(title='Annualised Return'),
                  title='Sample of Random Portfolios',
                  coloraxis_colorbar=dict(title="Sharpe Ratio"))

在此图中,每个点代表一个投资组合。这里需要注意的是,这里显示的大多数投资组合都不在有效边界上。我们将在本文的下一部分中讨论这个问题。

Tags