Python for Finance: Part II: 4 Markowitz Portfolio Optimization
Portfolio Theory
1952, Harry Markowitz published a paper.
– investors should understand the relationship between securities in their portfolio.
Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import numpy as np import pandas as pd from pandas_datareader import data as wb import matplotlib.pyplot as plt %matplotlib inline assets = ['DIS', 'AMZN'] pf_data = pd.DataFrame() for a in assets: pf_data[a] = wb.DataReader(a, data_source = 'google', start = '2010-1-1')['Close'] pf_data.tail() (pf_data / pf_data.iloc[0] * 100).plot(figsize=(10,5)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
log_returns = np.log(pf_data / pf_data.shift(1)) log_returns.mean() * 250 // DIS 0.160962 // AMZN 0.268312 // dtype: float64 log_returns.cov() * 250 log_returns.corr() num_assets = len(assets) num_assets // 2 arr = np.random.random(2) arr // array([ 0.52831474, 0.47945205]) arr[0] + arr[1] // 1.0077667888401995 weights = np.random.random(num_assets) weights /= np.sum(weights) weights // array([ 0.47348175, 0.52651825]) weights[0] + weights[1] // 1.0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// Expected Portfolio Return: np.sum(weights * log_returns.mean()) * 250 // 0.2496822910761077 // Expected Portfolio Variance: np.dot(weights.T, np.dot(log_returns.cov() * 250, weights)) // 0.074759086518318432 // Expected Portfolio Volatility: np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights))) // 0.27342107914043212 pfolio_returns = [] pfolio_volatilities = [] for x in range (1000): weights = np.random.random(num_assets) weights /= np.sum(weights) pfolio_returns.append(np.sum(weights * log_returns.mean()) * 250) pfolio_volatilities.append(np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights)))) pfolio_returns, pfolio_volatilities pfolio_returns = [] pfolio_volatilities = [] for x in range (1000): weights = np.random.random(num_assets) weights /= np.sum(weights) pfolio_returns.append(np.sum(weights * log_returns.mean()) * 250) pfolio_volatilities.append(np.sqrt(np.dot(weights.T,np.dot(log_returns.cov() * 250, weights)))) pfolio_returns = np.array(pfolio_returns) pfolio_volatilities = np.array(pfolio_volatilities) pfolio_returns, pfolio_volatilities portfolios = pd.DataFrame({'Return': pfolio_returns, 'Volatility': pfolio_volatilities}) portfolios.head() portfolios.tail() portfolios.plot(x='Volatility', y='Return', kind='scatter', figsize=(10,6)); plt.xlabel('Expected Volatility') plt.ylabel('Expected Return') |