Modern portfolio theory (MPT) also known as Mean-Variance Portfolio Theory (MVP) is a mathematical framework by Markowitz introduced in a 1952 essay, for which he was awarded a Nobel Prize in economics. Wikipedia entry
Import the required modules/packages.
In [51]:
import numpy as np
import pandas as pd
from pandas_datareader import data as web
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
%matplotlib inline
import warnings; warnings.simplefilter('ignore')
Here, I'm retrieving stock price data to build a portfolio of tech companies.
In [52]:
symbols = ['AAPL', 'AMZN', 'GOOG', 'IBM', 'MSFT'] # stock symbols
data = pd.DataFrame() # empty DataFrame
for sym in symbols:
data[sym] = web.DataReader(sym, data_source='google')['Close']
In [53]:
data.columns
Out[53]:
In [54]:
data.tail() # the final five rows
Out[54]:
A graphical comparison of the time series data with the starting values of 100.
In [55]:
(data / data.ix[0] * 100).plot(figsize=(20, 10));
To calculate a portfolio return, let's compute the annualized returns of the stocks based on the log returns for the respective time series.
In [56]:
log_rets = np.log(data / data.shift(1))
In [57]:
rets = log_rets.mean() * 252
rets
Out[57]:
An equal weighting scheme can be used to represent a portfolio by (normalized) weightings for the single stocks
In [58]:
weights = np.array([0.2, 0.2, 0.2, 0.2, 0.2])
In [59]:
np.dot(weights, rets)
Out[59]:
The annualized covariance matrix can be calculted in python like this:
In [60]:
log_rets.cov() * 252
Out[60]:
In [61]:
pvar = np.dot(weights.T, np.dot(log_rets.cov() * 252, weights))
pvar
Out[61]:
The portfolio volatility, in this case, is:
In [62]:
pvol = pvar ** 0.5
pvol
Out[62]:
First, generate a random portfolio composition before calculating the portfolio return and variance.
In [63]:
# random numbers
weights = np.random.random(5)
weights /= np.sum(weights)
In [64]:
# generated portfolio composition
weights
Out[64]:
In [65]:
np.dot(weights, rets)
Out[65]:
In [66]:
np.dot(weights.T, np.dot(log_rets.cov() * 252, weights))
Out[66]:
The Monte Carlo method is implemented to collect the resulting portfolio returns and volatilities.
In [67]:
%%time
prets = []
pvols = []
for p in xrange(5000):
weights = np.random.random(5)
weights /= np.sum(weights)
prets.append(np.sum(log_rets.mean() * weights) * 252)
pvols.append(np.sqrt(np.dot(weights.T,
np.dot(log_rets.cov() * 252, weights))))
prets = np.array(prets)
pvols = np.array(pvols)
portfolio = pd.DataFrame({'return': prets, 'volatility': pvols})
In [68]:
portfolio.plot(x='volatility', y='return', kind='scatter', figsize=(12, 8));