# Reading in the stocks of each stock and then creating a central data frame of each. 

import numpy as np
import pandas as pd
import pandas_datareader.data as web
# Get stock data  
all_data = {ticker: web.DataReader(ticker,'stooq')
           for ticker in ['AAPL', 'NVDA', 'MSFT', 'TSLA', 'AMZN', 'NFLX', 'QCOM', 'SBUX']}
# Extract the 'Adjusted Closing Price'
price = pd.DataFrame({ticker: data['Close']
                     for ticker, data in all_data.items() })

price
AAPL NVDA MSFT TSLA AMZN NFLX QCOM SBUX
Date
2023-09-08 178.1800 455.7200 334.270 248.5000 138.2300 442.80 106.1400 95.2800
2023-09-07 177.5600 462.4100 329.910 251.4900 137.8500 443.14 106.4000 95.1000
2023-09-06 182.9100 470.6100 332.880 251.9200 135.3600 445.76 114.6800 95.9500
2023-09-05 189.7000 485.4800 333.550 256.4900 137.2700 448.68 116.5500 96.8400
2023-09-01 189.4600 485.0900 328.660 245.0100 138.1200 439.88 115.3850 98.0000
... ... ... ... ... ... ... ... ...
2018-09-17 52.3882 67.9180 106.981 19.6560 95.4015 350.35 65.4799 50.1628
2018-09-14 53.8258 68.5376 108.142 19.6800 98.5095 364.56 67.1352 50.3259
2018-09-13 54.4400 67.2726 107.695 19.2973 99.4935 368.15 66.7036 50.4535
2018-09-12 53.1598 66.4911 106.564 19.3693 99.5000 369.95 64.1461 50.5281
2018-09-11 53.8288 67.6353 106.107 18.6293 99.3575 355.93 64.8282 50.6646

1257 rows × 8 columns

import matplotlib.pyplot as plt
  This next code plots all 8 stocks on different planes on the same figure. This can be helpful for viewing each stock individually yet able to quickly see the rest of the stocks.  
  This code works by creating the figure, and set the figure to be broken into 8 squares (2 x 4). Then it sets the X and Y axis to be shared. Then each stock is plotted on their respective graph, set the color, line type, and the, legend.  
fig1, axes1 = plt.subplots(2,4, sharex = True, sharey = True)

axes1[0,0].plot(price['AAPL'],'-', color = 'gold', label = 'AAPL')
axes1[0,0].legend(loc = 'best')

axes1[0,1].plot(price['NVDA'],'-', color = 'red', label = 'NVDA')
axes1[0,1].legend(loc = 'best')

axes1[0,2].plot(price['MSFT'],'-', color = 'blue', label = 'MSFT')
axes1[0,2].legend(loc = 'best')

axes1[0,3].plot(price['TSLA'],'-', color = 'royalblue', label = 'TSLA')
axes1[0,3].legend(loc = 'best')

axes1[1,0].plot(price['AMZN'],'-', color = 'black', label = 'AMZN')
axes1[1,0].legend(loc = 'best')

axes1[1,1].plot(price['NFLX'],'-', color = 'purple', label = 'NFLX')
axes1[1,1].legend(loc = 'best')

axes1[1,2].plot(price['QCOM'],'-', color = 'pink', label = 'QCOM')
axes1[1,2].legend(loc = 'best')

axes1[1,3].plot(price['SBUX'],'-', color = 'green', label = 'SBUX')
axes1[1,3].legend(loc = 'best') 

# fig1.savefig('stocks1.pdf')
<matplotlib.legend.Legend at 0x11aa78490>

png

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
plt.plot(price['AAPL'], '-',color = 'gold', label = 'AAPL')
plt.plot(price['NVDA'],'-', color = 'red', label = 'NVDA')
plt.plot(price['MSFT'],'-', color = 'blue', label = 'MSFT')
plt.plot(price['TSLA'],'-', color = 'royalblue', label = 'TSLA')
plt.plot(price['AMZN'],'-', color = 'black', label = 'AMZN')
plt.plot(price['NFLX'],'-', color = 'purple', label = 'NFLX')
plt.plot(price['QCOM'],'-', color = 'pink', label = 'QCOM')
plt.plot(price['SBUX'],'-', color = 'green', label = 'SBUX')
ax.legend(loc = 'best')
ax.set_ylabel("Price", fontsize=12)
ax.set_xlabel("Year", fontsize=12)
ax.set_title("Sample Portfolio", fontsize = 16)
Text(0.5, 1.0, 'Sample Portfolio')

png

  The standard deviation is how investors measure volatility and risk. STD measures the average distance from the mean, so the higher the STD the less concise the data is. In the finance world, if the STD is higher, that means that the price of the stock can be more unpredictable. This equates to risk. The lower the STD the better, and vice versa.  
# finding standard deviation
price.std()
AAPL     47.338524
NVDA    103.414854
MSFT     73.290376
TSLA    112.395614
AMZN     32.606867
NFLX    116.806046
QCOM     35.416767
SBUX     17.012365
dtype: float64
  The correlation between each of the stocks shows how well the portfolio will do. The correlation in math shows the relationship and the proportion between two variables. In finance the correlation dictates how two stocks will react in relationship. In layman terms it shows if one stock will go up what will another stock do. Correlation ranges from -1 to 1, where -1 is the most optimal.  
colors = ['gold', 'red', 'blue', 'royalblue', 'black', 'purple', 'pink', 'green']

fig6 = plt.figure(figsize=(6, 6))
axes6 = fig6.add_subplot(1, 1, 1)

# Create the bar chart with custom colors
priceSTD = price.std()
priceSTD.plot(ax=axes6, kind="bar", rot=45, color=colors)

axes6.set_ylabel("STD", fontsize=12)
axes6.set_xlabel("Stocks", fontsize=12)
axes6.set_title("STD of all 8 stocks", fontsize=20)

plt.show()

fig6.savefig('stocks4.png')

png

# finding correlation of stocks
price.corr()
AAPL NVDA MSFT TSLA AMZN NFLX QCOM SBUX
AAPL 1.000000 0.885723 0.974317 0.917979 0.606571 0.243950 0.882031 0.712675
NVDA 0.885723 1.000000 0.908441 0.766796 0.483660 0.305642 0.684728 0.635631
MSFT 0.974317 0.908441 1.000000 0.911730 0.659440 0.352975 0.871591 0.760423
TSLA 0.917979 0.766796 0.911730 1.000000 0.724181 0.353676 0.928775 0.667272
AMZN 0.606571 0.483660 0.659440 0.724181 1.000000 0.773166 0.759327 0.590947
NFLX 0.243950 0.305642 0.352975 0.353676 0.773166 1.000000 0.402769 0.513502
QCOM 0.882031 0.684728 0.871591 0.928775 0.759327 0.402769 1.000000 0.735396
SBUX 0.712675 0.635631 0.760423 0.667272 0.590947 0.513502 0.735396 1.000000
priceCORR = price.corr()

colors = ['gold', 'red', 'blue', 'royalblue', 'black', 'purple', 'pink', 'green']

fig, ax = plt.subplots(figsize=(10, 6))
priceCORR.plot(kind='bar', stacked=True, ax=ax, color=colors)
ax.set_ylabel("Correlation", fontsize=12)
ax.set_xlabel("Stocks", fontsize=12)
ax.set_title("Correlation between Stocks", fontsize=16)

plt.legend(title='Stocks', loc='upper right')
plt.xticks(rotation=0)  # Rotate x-axis labels if needed
plt.show()

fig.savefig('stocks5.png')

png

  By finding the correlation of the entire portfolio, it will show how well it will do. The closer to -1 the better.  
# Finding average correlation to show profability of portfolio
averageCorr = price.corr()
averageCorrMean = averageCorr.mean()
averageCorrMean

column_sum = 0

# For loop to find the mean of the entire data table
for i in range(len(averageCorrMean)):
    column_sum += averageCorrMean[i]
column_sum = column_sum/len(averageCorrMean)
column_sum
0.719166124873851
  This is where the math and the real fun begins. This next code finds the optimal weights of each stock. It does this by running through 6000 differnt scenarios each with different weighting. It finds the weights by finding the retention factor and the volatility of each stock and then compare it to each of the other 7 stocks. Then once it has done that it’ll compare it to average yearly stock prices where it will then compare all 6000 scenarios and output the most optimal.  
# finding weights, return, volitilty, and sharpe ratio. 

stocks = pd.concat([price['AAPL'], price['NVDA'], price['MSFT'], price['TSLA'], price['AMZN'], price['NFLX'], price['QCOM'], price['SBUX']], axis = 1)
log_ret = np.log(stocks/stocks.shift(1))

# setting up variables
np.random.seed(42)
num_ports = 6000
num_stocks = 8
all_weights = np.zeros((num_ports, len(stocks.columns)))
ret_arr = np.zeros(num_ports)
vol_arr = np.zeros(num_ports)
sharpe_arr = np.zeros(num_ports)

# going through all possible weights
for x in range(num_ports):
    # Weights
    weights = np.array(np.random.random(num_stocks))
    weights = weights/np.sum(weights)
    
    # Save weights
    all_weights[x,:] = weights
    
    # Expected return
    ret_arr[x] = np.sum( (log_ret.mean() * weights * 252))
    
    # Expected volatility
    vol_arr[x] = np.sqrt(np.dot(weights.T, np.dot(log_ret.cov()*252, weights)))
    
    # Sharpe Ratio
    sharpe_arr[x] = ret_arr[x]/vol_arr[x]
  The Sharpe Ratio is how investors determine the profability of a portfolio in a single number that can be compared to other portfolios. In finance, the Sharpe ratio measures the performance of an investment such as a security or portfolio compared to a risk-free asset, after adjusting for its risk.  
# printing the max sharpe ratio
print("Max Sharpe Ratio = ",sharpe_arr.max())
sharpe_arr.argmax()
max_sr_ret =  ret_arr[sharpe_arr.argmax()]
max_sr_vol =  vol_arr[sharpe_arr.argmax()]
Max Sharpe Ratio =  -0.31396283816463905
  This is my favorite and probably the most important graph. It may not look like it but there are 6000 points on this graph. Each point represents one of the possible portfolios that the code simulated to find the most optimal weightings. It graphs this by volatilty by return. The graph also represents the Sharpe Ratio of each possible portfolio. With all these calculations in mind, it finds the most opitmal portfolio and then highlights in red (the red dot). In finance this graph is part of a larger graph is called a efficient frontier.  
import matplotlib.pyplot as plt
plt.figure(figsize=(12,8))
plt.scatter(vol_arr, ret_arr, c=sharpe_arr, cmap='viridis')
plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Volatility')
plt.ylabel('Return')
plt.scatter(max_sr_vol, max_sr_ret,c='red', s=50) # red dot
plt.show()

png