%%javascript
$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')
import numpy as np
import pandas as pd
import pandas_datareader as pdr
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
#ax.yaxis.set_major_formatter(mtick.PercentFormatter())
pd.options.display.float_format = '${:,.2f}'.format
%matplotlib inline
#format DataFrame example
#formatted = df.style.format({'EPS': '${:,.2f}', 'PE':'{:,.2f}', 'Exp_Ret': '{:,.2%}', 'Price': '${:,.2f}'})
stocks = 'AAPL GLD'.split()
from datetime import datetime, timedelta
oneYearsAgo = (datetime.now() - timedelta(days=365)).date().isoformat()
data = pdr.get_data_yahoo(stocks, start=oneYearsAgo)['Close']
volatility = pd.DataFrame()
for stock in stocks:
if stock not in volatility:
volatility[stock] = np.log(data[stock]).diff()
volatility.info()
<class 'pandas.core.frame.DataFrame'> DatetimeIndex: 253 entries, 2018-12-24 to 2019-12-24 Data columns (total 2 columns): AAPL 252 non-null float64 GLD 252 non-null float64 dtypes: float64(2) memory usage: 5.9 KB
#get annual variance
variance_aapl = volatility['AAPL'].var() * len(volatility['AAPL'])
variance_gld = volatility['GLD'].var() * len(volatility['GLD'])
print('AAPL variance: {}, Gold variance {}'.format(variance_aapl,variance_gld))
AAPL variance: 0.07377679084088176, Gold variance 0.013643578043018223
#make up portfolio weights
weight_aapl = .9
weight_gld = 1 - weight_aapl
expectedReturn_aapl = .14
expectedReturn_gld = .07
expectedReturn = weight_aapl * expectedReturn_aapl + weight_gld * expectedReturn_gld
'Expected return: {:,.2%}'.format(expectedReturn)
'Expected return: 13.30%'
#get the covariance annualized
#ignore the first row since it contains NaN values
covariance = np.cov(volatility['AAPL'][1:],volatility['GLD'][1:])[0,1] * len(volatility['AAPL'])
portfolio_stddev = np.sqrt(variance_aapl * weight_aapl **2 + variance_gld * weight_gld **2 + 2 * covariance * weight_aapl * weight_gld)
portfolio_stddev
0.241855424595427
stepsize = .05
steps = int(1 / .05 + 1)
effic = pd.DataFrame({'weight_aapl':np.zeros(steps), 'exp_ret': np.zeros(steps), 'stddev': np.zeros(steps)})
w_aapl = 0.0
for weight in range(steps):
w_gld = (1-w_aapl)
effic['weight_aapl'][weight] = w_aapl
effic['exp_ret'][weight] = w_aapl * expectedReturn_aapl + w_gld * expectedReturn_gld
effic['stddev'][weight] = np.sqrt(variance_aapl * w_aapl ** 2 + variance_gld * w_gld ** 2 + covariance * w_aapl * w_gld)
w_aapl = w_aapl + stepsize
effic.style.format({
'weight_aapl': '{:,.2%}'.format,
'exp_ret': '{:,.2%}'.format,
'stddev': '{:,.2%}'.format,
})
weight_aapl | exp_ret | stddev | |
---|---|---|---|
0 | 0.00% | 7.00% | 11.68% |
1 | 5.00% | 7.35% | 11.01% |
2 | 10.00% | 7.70% | 10.53% |
3 | 15.00% | 8.05% | 10.26% |
4 | 20.00% | 8.40% | 10.22% |
5 | 25.00% | 8.75% | 10.40% |
6 | 30.00% | 9.10% | 10.81% |
7 | 35.00% | 9.45% | 11.42% |
8 | 40.00% | 9.80% | 12.18% |
9 | 45.00% | 10.15% | 13.09% |
10 | 50.00% | 10.50% | 14.11% |
11 | 55.00% | 10.85% | 15.22% |
12 | 60.00% | 11.20% | 16.39% |
13 | 65.00% | 11.55% | 17.63% |
14 | 70.00% | 11.90% | 18.91% |
15 | 75.00% | 12.25% | 20.22% |
16 | 80.00% | 12.60% | 21.57% |
17 | 85.00% | 12.95% | 22.94% |
18 | 90.00% | 13.30% | 24.33% |
19 | 95.00% | 13.65% | 25.74% |
20 | 100.00% | 14.00% | 27.16% |
with plt.style.context('seaborn'):
plt.scatter(effic['stddev'],effic['exp_ret'])
plt.xlabel('StdDev/Risk')
plt.ylabel('Expected Return')
# to add a third security and get additional benefit from diversification you would need to adjust the weights
# accordingly and add in terms for covariation of security 1 & 3 and security 2 & 3
# so for an equal weight portfolio it would look something like this:
# np.sqrt(.333 ** 2 * sec1_var + .333 ** 2 * sec2_var + .333 ** 2 * sec3_var +
# 2 * cov_sec1_sec2 + 2 * cov_sec_1_sec2 + 2 * cov_sec2_sec3)