Markowitz有效邊界和投資組合優化基於Python(附代碼)

本期作者:Bernard Brenyah

本期翻譯:Barry

未經授權,嚴禁轉載

哈里馬科維茨對金融和經濟學的世界的貢獻是怎麼強調都不過分的。憑藉其於 1952年發表的開創性論文“資產組合選擇”,他被廣泛的視作現代資產組合理論(MPT)的開拓者。最終在1990年,基於對這一領域的巨大貢獻,他獲得了諾貝爾經濟學獎。

如今,幾乎全世界的任何一門商科、金融課程都會教授MPT理論。本文將通過真實的股票數據用python來介紹這一理論的基礎和有效前沿的構建。

那麼什麼是MPT,爲什麼你要理解它,又怎麼用python來實現它呢?

與大多數理論一樣,MPT也是建立在對真實世界一些假設之上。對MPT的的解釋將從闡述它的基本假設開始:

MPT的假設:

  • 投資者是理性的並且風險厭惡
  • 投資者追求收益最大化
  • 所有投資者都想最大化期望收益
  • 不考慮佣金和稅費
  • 所有投資者都可以接觸到同樣的信息源和與投資決策相關的全部必要信息
  • 投資者可以以無風險利率不受限制的借入和貸出資金

現代資產組合理論是關於在特定風險水平下投資者(風險厭惡)如何構建組合來最大化期望收益的理論。MPT的突破性在於提出不需將衆多投資的風險和收益特徵孤立分析,而是去研究這些投資如何對組合的表現產生影響。因此,MPT的假設強調投資者只有在可能得到更高期望收益時會有額外風險出現---也就是高風險,高收益。

這一理論最基本的原則是投資者可以構建投資組合的有效集合,即有效前沿。有效前沿可以在特定風險水平下使期望收益最大化。投資者對風險的容忍度將決定他所選擇的有效前沿。低容忍度的投資者會選在最低風險下可以提供最大收益的組合,高容忍度的會選擇高風險下的可以提供最大收益的組合。可以從下圖大致理解有效前沿的概念:

不同的股票組合將產生不同的期望收益。在馬科維茨證明了有效前沿之後人們最重要的一個發現是分散化投資的力量。因爲組合中資產的相關性和權重可以極大地影響組合收益,所以投資者可以在他們的風險偏好下通過用不同的證券簡單地構建組合來實現期望收益最大化。

那麼我們該怎麼通過python用真實股價數據來建立有效前沿組合呢?

數據獲取

import quandl
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

quandl.ApiConfig.api_key = 'PASTE YOUR API KEY HERE'
selected = ['CNP', 'F', 'WMT', 'GE', 'TSLA']
data = quandl.get_table('WIKI/PRICES', ticker = selected,
                        qopts = { 'columns': ['date', 'ticker', 'adj_close'] },
                        date = { 'gte': '2014-1-1', 'lte': '2016-12-31' }, paginate=True)
data.head()
date        ticker  adj_close
None      
0  2014-01-02  CNP  19.290792
1  2014-01-03  CNP  19.282339
2  2014-01-06  CNP  19.307699
3  2014-01-07  CNP  19.510582
4  2014-01-08  CNP  19.307699

接下來是數據處理步驟,我們根據tickers來給調整後的收盤價排序:

clean = data.set_index('date')
table = clean.pivot(columns='ticker')
table.head()
adj_close
ticker    CNP    F    GE    TSLA  WMT
date          
2014-01-02  19.290792  12.884511  24.266002  150.10  71.343743
2014-01-03  19.282339  12.942926  24.248354  149.56  71.108673
2014-01-06  19.307699  13.001340  24.054226  147.00  70.710863
2014-01-07  19.510582  12.834442  24.080698  149.36  70.927850
2014-01-08  19.307699  12.967960  24.010106  151.28  70.367299

爲了得到有效前沿,我們需要模擬很多的投資組合(50000個)。

port_returns = []
port_volatility = []
stock_weights = []

num_assets = len(selected)
num_portfolios = 50000

for single_portfolio in range(num_portfolios):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    returns = np.dot(weights, returns_annual)
    volatility = np.sqrt(np.dot(weights.T, np.dot(cov_annual, weights)))
    port_returns.append(returns)
    port_volatility.append(volatility)
    stock_weights.append(weights)


portfolio = {'Returns': port_returns,
             'Volatility': port_volatility}

and weight in the portfolio
for counter,symbol in enumerate(selected):
    portfolio[symbol+' weight'] = [weight[counter] for weight in stock_weights]

df = pd.DataFrame(portfolio)

column_order = ['Returns', 'Volatility'] + [stock+' weight' for stock in selected]
df = df[column_order]
df.head()
Returns    Volatility  CNP weight  F weight  WMT weight  GE weight  TSLA weight
0  0.051471  0.139810  0.193275  0.144265  0.286315  0.037991  0.338155
1  0.098057  0.205745  0.001220  0.192939  0.271552  0.359363  0.174927
2  0.042783  0.160203  0.281532  0.442986  0.164275  0.022419  0.088788
3  0.090758  0.199514  0.113044  0.344052  0.238166  0.293816  0.010922
4  0.053179  0.159999  0.212643  0.283324  0.015256  0.168772  0.320006

棒極了!繁瑣的步驟現在都已經完成了!我們來看一下有效前沿長什麼樣:

希望現在你對MPT有了基本的瞭解!

前面我們瞭解了資產組合理論(MPT)的基本內容並通過Monte Carlo模擬產生了有效前沿組合。下面我們專注於組合優化的概念。

50000個不同權重的投資組合產生了不同的期望收益和期望波動率。線上的每個點代表了股票的一個最優組合(CenterPoint Energy,Facebook,Walmart,General Electric,Tesla),最優組合在特定的風險水平下最大化了期望收益率。如果有效前沿曲線上的所有點都是最優組合,那麼在這些組合中的最優投資組合是什麼呢?優中最優組合的選取標準又是什麼呢?

另一個諾貝爾獎得主William F. Sharpe 拓展了Markowitz的工作,開發了資本資產定價模型(CAPM)。本文不會設計CAPM,但是我們會用到他的一個成果(Sharpe Ratio)最爲選擇最優的準則。

夏普比率可以用來衡量特定風險下投資收益的表現。這個比率調整了投資的收益,使我們可以在一定規模風險的情況下比較不同的投資表現。沒有規模風險的限制,我們無法比較不同證券組合的收益與風險表現。注:出於簡化,本文無風險收益率設爲0%。

我們將對上面的代碼做一些小改變。我們已經有了模擬出的組合的期望收益率和風險。接下來,我們將計算這些組合的風險調整收益率(藉助夏普比率),並且以夏普比率爲值畫出色標圖:

import quandl
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

quandl.ApiConfig.api_key = 'INSERT YOUR API KEY HERE'
selected = ['CNP', 'F', 'WMT', 'GE', 'TSLA']
data = quandl.get_table('WIKI/PRICES', ticker = selected,
                        qopts = { 'columns': ['date', 'ticker', 'adj_close'] },
                        date = { 'gte': '2014-1-1', 'lte': '2016-12-31' }, paginate=True)

clean = data.set_index('date')
table = clean.pivot(columns='ticker')

returns_daily = table.pct_change()
returns_annual = returns_daily.mean() * 250

cov_daily = returns_daily.cov()
cov_annual = cov_daily * 250

port_returns = []
port_volatility = []
sharpe_ratio = []
stock_weights = []

num_assets = len(selected)
num_portfolios = 50000

np.random.seed(101)

for single_portfolio in range(num_portfolios):
    weights = np.random.random(num_assets)
    weights /= np.sum(weights)
    returns = np.dot(weights, returns_annual)
    volatility = np.sqrt(np.dot(weights.T, np.dot(cov_annual, weights)))
    sharpe = returns / volatility
    sharpe_ratio.append(sharpe)
    port_returns.append(returns)
    port_volatility.append(volatility)
    stock_weights.append(weights)

portfolio = {'Returns': port_returns,
             'Volatility': port_volatility,
             'Sharpe Ratio': sharpe_ratio}

for counter,symbol in enumerate(selected):
    portfolio[symbol+' Weight'] = [Weight[counter] for Weight in stock_weights]

df = pd.DataFrame(portfolio)

column_order = ['Returns', 'Volatility', 'Sharpe Ratio'] + [stock+' Weight' for stock in selected]

df = df[column_order]

plt.style.use('seaborn-dark')
df.plot.scatter(x='Volatility', y='Returns', c='Sharpe Ratio',
                cmap='RdYlGn', edgecolors='black', figsize=(10, 8), grid=True)
plt.xlabel('Volatility (Std. Deviation)')
plt.ylabel('Expected Returns')
plt.title('Efficient Frontier')
plt.show()

通過上述代碼,我們得到了下圖:

接着,試着找出最優組合和有着最低波動率的組合(也就是風險厭惡最嚴重的投資者的偏好組合):

min_volatility = df['Volatility'].min()
max_sharpe = df['Sharpe Ratio'].max()

sharpe_portfolio = df.loc[df['Sharpe Ratio'] == max_sharpe]
min_variance_port = df.loc[df['Volatility'] == min_volatility]

plt.style.use('seaborn-dark')
df.plot.scatter(x='Volatility', y='Returns', c='Sharpe Ratio',
                cmap='RdYlGn', edgecolors='black', figsize=(10, 8), grid=True)
plt.scatter(x=sharpe_portfolio['Volatility'], y=sharpe_portfolio['Returns'], c='red', marker='D', s=200)
plt.scatter(x=min_variance_port['Volatility'], y=min_variance_port['Returns'], c='blue', marker='D', s=200 )
plt.xlabel('Volatility (Std. Deviation)')
plt.ylabel('Expected Returns')
plt.title('Efficient Frontier')
plt.show()

接下來輸出這兩個特殊組合的具體信息:

print(min_variance_port.T)
print(sharpe_portfolio.T)

  17879
Returns    0.045828
Volatility  0.138552
Sharpe Ratio  0.330761
CNP Weight  0.240327
F Weight  0.104659
WMT Weight  0.257760
GE Weight  0.001487
TSLA Weight  0.395767

31209
Returns      0.116145
Volatility    0.175045
Sharpe Ratio    0.663514
CNP Weight    0.372890
F Weight    0.008482
WMT Weight    0.404987
GE Weight    0.211450
TSLA Weight    0.002190

風險厭惡最嚴重的投資者將會選擇最小方差組合,它的期望收益率是4.58%,期望波動率是13.86%。追求最大風險調整收益率的投資者將會構建有着最大夏普比率的投資組合,它的期望收益率是11.61%,期望波動率是17.50%。

通過一些優化的數學技巧也可以得到相同的結論,但這裏,用了Monte Carlo模擬來解釋有效前沿和最有投資組合的概念。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章