Hi All,

I have recently completed the Python for Finance course. Since I have a degree in Finance and am on my way to becoming a CFA charter holder, I didn’t feel creating a presentation for recommending a stock was going to add much value to my education.

I decided instead to create a program that will take in a user-inputted list of stocks and create mean-variance portfolio optimization output, utilizing 5 years of historical data. The program will prompt you for how many stocks you want to include - then you will input the stocks you want to include. It will show you the weights for the max-sharpe portfolio, and the weights for the minimum variance portfolio, plus their respective expected returns and risks. It will then prompt you if you want to include a dollar value for your portfolio, and it will try it’s best to tell you how many shares of each company to buy, and how much $ will be left over. At the end, it will plot a bar graph the shows the tradeoff between risk and return for the stocks in your portfolio, and also show the efficient frontier including where the max-sharpe portfolio lies.

I utilized the pyportfolioopt package for this project - so you will need to have this downloaded. There may be some other packages you need to download, so if you have any trouble you can ask me and I will point you in the right direction.

You will also need to have a Tiingo API key, which you can get for free from their website. You will ned to put in your Tiingo API key in the program where it says INPUT-API-KEY-HERE.

Hope someone gets to check this out, and please leave any feedback you may have!

Thanks,

Mike

[codebyte]

from tiingo import TiingoClient

import matplotlib.pyplot as plt

import matplotlib.ticker as mtick

import numpy as np

from pypfopt import EfficientFrontier, risk_models, expected_returns, plotting

from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices

from datetime import date, timedelta

client = TiingoClient({‘api_key’:‘INSERT-API-KEY-HERE’})

# Create an empty list to be populated by user input

list_of_stocks =

# Find out how many stocks the user wants to include

number_of_stocks = int(input(‘How many stocks would you like to include?’))

# Prompt user to input list of tickers, to appended to list_of_stocks above

print("Enter each ticker you’d like to include, one at a time (pressing after each ticker), below: ")

# Loop through n iterations defined by user to create list of stocks

for i in range(0,number_of_stocks):

ele = input()

list_of_stocks.append(ele)

# Define variables that hold today’s date, and the day five years ago to be used in the dataframe of historical prices

today = date.today()

yesterday = today - timedelta(days=1)

yesterday1 = yesterday.strftime(’%Y%m%d’)

five_years_ago = today - timedelta(days=(365*5))

five_years_ago1 = five_years_ago.strftime(’%Y%m%d’)

# Create dataframe with user-defined list of stocks of the adjusted closes for 5 years

all_history = client.get_dataframe(list_of_stocks,

metric_name=‘adjClose’,

startDate=five_years_ago1,

endDate=yesterday1,

frequency=‘daily’)

# Calculate daily returns from dataframe

stocks = list(all_history.columns[0:])

daily_returns = all_history[stocks].pct_change()

# find expected return of each stock and annualize them. Express as a percent

expected_return = daily_returns.mean()

annual_exp_return = expected_return * 252

annual_exp_return_pct = annual_exp_return * 100

# find std dev of returns, express as a percent.

std = daily_returns.std()

std_year = std * 252**.5

std_year_pct = std_year * 100

# find covariance matrix of returns

returns_cov = daily_returns.cov()

# find correlation between stocks

returns_corr = daily_returns.corr()

# Calculate expected returns and sample covariance

mu = expected_returns.mean_historical_return(all_history)

S = risk_models.sample_cov(all_history)

# Find portfolio optimized for maximal Sharpe ratio

print(‘These are the weights of the long-only, maximum Sharpe ratio portfolio:’)

ef = EfficientFrontier(mu, S, weight_bounds=(0,1))

raw_weights = ef.max_sharpe()

cleaned_weights = ef.clean_weights()

ef.save_weights_to_file(“weights.csv”) # saves to file

print(cleaned_weights)

ef.portfolio_performance(verbose=True)

ef = EfficientFrontier(mu, S, weight_bounds=(0,1))

# Create a figure

plt.figure(figsize=(10,5))

# Plot the efficient frontier line

ax3 = plt.subplot(1,2,2)

plotting.plot_efficient_frontier(ef, ax=ax3, show_assets=True)

# find the portfolio optimized for minimum volatility

print(‘These are the weights of the long-only, minimum volatility portfolio:’)

min_vol = ef.min_volatility()

print(min_vol)

performance = ef.portfolio_performance(verbose=True)

# Create side-by-side bar graph comparing volatility (annualized std dev.) vs avg annualized returns for each stock

n=1

t=2

d= number_of_stocks

w=.8

x_values_one = [t * element + w * n for element in range(d)]

n=2

t=2

d= number_of_stocks

w=.8

x_values_two = [t * element + w * n for element in range(d)]

ax = plt.subplot(1,2,1)

plt.bar(x_values_one, annual_exp_return_pct)

plt.bar(x_values_two, std_year_pct)

plt.title(‘Expected Return vs Volatility’)

plt.xlabel(‘Stocks’)

plt.ylabel(‘Expected Return (annualized) vs Volatility (annualized std dev’)

plt.legend([‘Expected Return’, ‘Volatility’])

ax.set_xticks(x_values_one)

ax.set_xticklabels(all_history[stocks])

ax.yaxis.set_major_formatter(mtick.PercentFormatter())

# create a graph showing the efficient frontier with 5000 random portfolios

# Find the tangency portfolio

ef.max_sharpe()

ret_tangent, std_tangent, _ = ef.portfolio_performance()

ax2=plt.subplot(1,2,2)

plt.scatter(std_tangent, ret_tangent, marker="*", s=100, c=“r”, label=“Max Sharpe”)

# Generate random portfolios and plot them

n_samples = 5000

w = np.random.dirichlet(np.ones(len(mu)), n_samples)

rets = w.dot(mu)

stds = np.sqrt(np.diag(w @ S @ w.T))

sharpes = rets / stds

ax1=plt.subplot(1,2,2)

plt.scatter(stds, rets, marker=".", c=sharpes, cmap=“viridis_r”)

ax1.set_title(“Efficient Frontier with Random Portfolio Weights”)

ax1.legend()

ax1.xaxis.set_major_formatter(mtick.PercentFormatter(1))

ax1.yaxis.set_major_formatter(mtick.PercentFormatter(1, decimals=1))

plt.tight_layout()

# Print the previous day’s closing prices

print(“These are the previous day’s closing prices:”)

latest_prices = get_latest_prices(all_history)

print(latest_prices)

# Find out if user wants to include a $ value of their portfolio to find exact amounts of stock to buy

yes_or_no = input(‘Do you want to give a dollar value of your portfolio to find the exact amounts of stock to buy? (Answer yes or no)’)

# Include portfolio value to come up with exact amount of stocks to buy

if yes_or_no == ‘yes’:

dollar_value = int(input(‘What is the dollar value of your portfolio? (Leave out the dollar sign)’))

discrete = DiscreteAllocation(cleaned_weights,

latest_prices,

total_portfolio_value=dollar_value,

short_ratio=None)

allocation, leftover = discrete.greedy_portfolio()

print('You should buy the following amounts of shares: ', allocation)

print(‘This is the amount of money you will have leftover: ${:.2f}’.format(leftover))

# Show the figure

plt.show()[/codebyte]