Portfolio Efficient Frontier Generator

Here is my capstone comparing a few stocks. This should work in realtime to generate the efficient frontier. Had to improvise a few bits since some of the codeacademy tools weren’t available.

Feedback appreciated!


import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from yahooquery import Ticker

stocks = ['JPM', 'HD', 'MSFT', 'CVX', 'RNG', 'JNJ']
start_date = '2010-01-01'
end_date = '2020-01-01'
# this selects the stocks to compare and the dates to use
tickers = Ticker(stocks)
df = tickers.history(start=start_date, end=end_date)

pivoted = df.reset_index().pivot(index = 'date', columns = 'symbol', values = 'close')


cov_matrix = pivoted.pct_change().apply(lambda x: np.log(1 + x)).cov()
#for reference: this is the covariance matrix between the selected stocks


e_r = pivoted.resample('Y').last().pct_change().mean()
#here is where we annualize the expected returns


s_d = pivoted.pct_change().apply(lambda x: np.log(1 + x)).std().apply(lambda x: x*np.sqrt(250))
#produces the standard deviations


assets = pd.concat([e_r, s_d], axis = 1)
assets.columns = ['Returns', 'Volatility']
#this produces a table comparing the average returns and their volatility of each stock


p_ret = []
p_vol = []
p_weight = []

num_assets = len(pivoted.columns)
num_port = 1000 # number of portfolio combinations to test

for p in range(num_port):
  
  weights = np.random.random(num_assets)
  weights = weights / np.sum(weights)
  p_weight.append(weights)
  returns = np.dot(weights, e_r)
  p_ret.append(returns)
  var= cov_matrix.mul(weights, axis = 0).mul(weights, axis = 1).sum().sum()
  sd= np.sqrt(var)
  ann_sd = sd * np.sqrt(250)
  p_vol.append(ann_sd)
#this is how we test for the different combos
data = {'Returns': p_ret, 'Volatility': p_vol}

for counter, symbol in enumerate(pivoted.columns.tolist()):
  data[symbol +' weight'] = [w[counter] for w in p_weight]

portfolios = pd.DataFrame(data).sort_values('Returns', ascending = False)
#we can print portfolios to see the list of combination weights and their returns/volatility

portfolios.plot.scatter(x = 'Volatility', y = 'Returns', grid = False)
plt.savefig('plot.png')
print(portfolios.head())