Blue-Chip Stock Portfolios for Quant Traders (2024)

  • In this post, we will revisit most popular blue-chip stock portfolios using Python fintech libraries.
  • Our objective is to optimize currently available quant trading and investing solutions for private DIY self-traders. Our trading approach consists of the following 4 steps:
  • Step 1: Examine the AAPL trading signals and support/resistance regression lines.
  • Step 2: Compare AAPL vs MSFT in terms of returns, volatility, covariance, and correlations.
  • Step 3: Compare MA 10-20-30, daily returns, pair plots, correlations, Monte Carlo simulations, and Sharpe ratios of AAPL, AMZN, MSFT, and TSLA stocks.
  • Step 4: Perform the SPY stock price analysis and FB Prophet forecast.

Let’s dive into the details below.

Table of Contents

  1. AAPL Trading Signals Verified
  2. AAPL/MSFT Risk vs ROI Analysis
  3. Popular 4-Stock Portfolio
  4. Monte-Carlo Predictions
  5. SPY Return/Volatility
  6. SPY Prophet Forecast
  7. Summary
  8. References
  9. Explore More

AAPL Trading Signals Verified

Let’s set the working directory YOURPATH

import osos.chdir('YOURPATH') # Set working directoryos. getcwd()

Let’s import the key libraries and define the following functions

import numpy as npimport pandas as pdfrom math import sqrtimport matplotlib.pyplot as pltimport pandas_datareader as webfrom scipy.signal import savgol_filterfrom sklearn.linear_model import LinearRegressionfrom pandas_datareader import data as pdrimport yfinance as yfinyfin.pdr_override()def pythag(pt1, pt2): a_sq = (pt2[0] - pt1[0]) ** 2 b_sq = (pt2[1] - pt1[1]) ** 2 return sqrt(a_sq + b_sq)def regression_ceof(pts): X = np.array([pt[0] for pt in pts]).reshape(-1, 1) y = np.array([pt[1] for pt in pts]) model = LinearRegression() model.fit(X, y) return model.coef_[0], model.intercept_def local_min_max(pts): local_min = [] local_max = [] prev_pts = [(0, pts[0]), (1, pts[1])] for i in range(1, len(pts) - 1): append_to = '' if pts[i-1] > pts[i] < pts[i+1]: append_to = 'min' elif pts[i-1] < pts[i] > pts[i+1]: append_to = 'max' if append_to: if local_min or local_max: prev_distance = pythag(prev_pts[0], prev_pts[1]) * 0.5 curr_distance = pythag(prev_pts[1], (i, pts[i])) if curr_distance >= prev_distance: prev_pts[0] = prev_pts[1] prev_pts[1] = (i, pts[i]) if append_to == 'min': local_min.append((i, pts[i])) else: local_max.append((i, pts[i])) else: prev_pts[0] = prev_pts[1] prev_pts[1] = (i, pts[i]) if append_to == 'min': local_min.append((i, pts[i])) else: local_max.append((i, pts[i])) return local_min, local_max
Blue-Chip Stock Portfolios for Quant Traders (1)

Let’s look at the smoothed version if the above plot

month_diff = series.shape[0] // 30if month_diff == 0: month_diff = 1month_diff

6

smooth = int(2 * month_diff + 3)smooth

15

pts = savgol_filter(series, smooth, 3)plt.title(symbol)plt.xlabel('Days')plt.ylabel('Prices')plt.plot(pts, label=f'Smooth {symbol}')plt.legend()
Blue-Chip Stock Portfolios for Quant Traders (2)

Let’s combine these two curves into the single joint plot

plt.title(symbol)plt.xlabel('Days')plt.ylabel('Prices')plt.plot(series, label=symbol)plt.plot(pts, label=f'Smooth {symbol}')plt.legend()
Blue-Chip Stock Portfolios for Quant Traders (3)

Let’s generate the trading signals using the smoothed price curve

local_min, local_max = local_min_max(pts)plt.title(symbol)plt.xlabel('Days')plt.ylabel('Prices')plt.plot(pts, label=f'Smooth {symbol}')for pt in local_min: plt.scatter(pt[0], pt[1], c='r')for pt in local_max: plt.scatter(pt[0], pt[1], c='g')plt.legend()
Blue-Chip Stock Portfolios for Quant Traders (4)

Let’s calculate the local support and resistance lines using the regression_ceof function

local_min_slope, local_min_int = regression_ceof(local_min)local_max_slope, local_max_int = regression_ceof(local_max)support = (local_min_slope * np.array(series.index)) + local_min_intresistance = (local_max_slope * np.array(series.index)) + local_max_int
plt.title(symbol)plt.xlabel('Days')plt.ylabel('Prices')plt.plot(pts, label=f'Smooth {symbol}')plt.plot(support, label='Support', c='r')plt.plot(resistance, label='Resistance', c='g')plt.legend()
Blue-Chip Stock Portfolios for Quant Traders (5)
plt.title(symbol)plt.xlabel('Days')plt.ylabel('Prices')plt.plot(series, label=symbol)plt.plot(support, label='Support', c='r')plt.plot(resistance, label='Resistance', c='g')plt.legend()
Blue-Chip Stock Portfolios for Quant Traders (6)

Let’s plot the AAPL Simple Moving Average (SMA) to verify the 5-year MA crossover strategy

# import modulesfrom datetime import datetimeimport yfinance as yfimport matplotlib.pyplot as plt # initialize parametersstart_date = datetime(2017, 1, 1)end_date = datetime(2023, 9, 26) # get the datadf = yf.download('AAPL', start = start_date, end = end_date) 
import matplotlibfrom pylab import rcParamsmatplotlib.rcParams.update({'font.size': 18})rcParams['figure.figsize'] = 15, 6simple_ma = df["Close"].rolling(window=100).mean()plt.figure(figsize=(14,8))simple_ma.plot(label="Simple Moving Average")df["Close"].plot(label="Closing Price")plt.xticks(rotation=0)plt.title("Moving Average of Closing Price", size=22)plt.legend()plt.show(
Blue-Chip Stock Portfolios for Quant Traders (7)

AAPL/MSFT Risk vs ROI Analysis

Following the quant trading diversification approach, we will show how a trader can reduce the volatility of the portfolio’s returns by choosing just 2 tech stocks such as AAPL and MSFT.

# Import librariesimport pandas as pdimport numpy as npimport yfinance as yfimport statsmodels.api as smfrom statsmodels.regression.rolling import RollingOLSimport matplotlib.pyplot as pltimport plotly.express as pximport plotly.graph_objects as gofrom IPython.display import clear_output
#Download datastartdate='2023-01-01'enddate='2023-09-26'tickers = ['AAPL', 'MSFT']price = yf.download(tickers, startdate, enddate)['Close']price.tail()
[*********************100%***********************] 2 of 2 completed
Blue-Chip Stock Portfolios for Quant Traders (8)

We can plot these two stocks as follows

# AAPL plotplt.figure(figsize=(10,6))plt.subplot(2, 1, 1) plt.plot(price.AAPL, color='b')plt.ylabel('Price')plt.title('AAPL Daily Close Price USD')# MSFT plotplt.subplot(2, 1, 2)plt.plot(price.MSFT, color='g')plt.ylabel('Price')plt.title('MSFT Daily Close Price USD')# Use plt.tight_layout() to improve the spacing between subplotsplt.tight_layout()plt.show()
Blue-Chip Stock Portfolios for Quant Traders (9)

We can calculate their daily returns

returns = price.pct_change().dropna()print(returns.tail())
 AAPL MSFTDate 2023-09-19 0.006181 -0.0012462023-09-20 -0.019992 -0.0239772023-09-21 -0.008889 -0.0038662023-09-22 0.004945 -0.0078872023-09-25 0.007380 0.001672
 AAPLMSFTcount182.000000182.000000mean0.0019700.001689std0.0133940.016852min-0.048020-0.04374325%-0.006398-0.00841450%0.0018380.00090175%0.0093000.011763max0.0469270.072435

We can plot histograms or probabilities of their daily returns

import seaborn as snsfig = plt.figure(figsize=(10,10))# AAPL plotplt.subplot(2, 1, 1) sns.distplot(returns.AAPL, color='b');plt.xlabel('Return')plt.ylabel('Probability')plt.title('AAPL Returns')# MSFT plotplt.subplot(2, 1, 2) sns.distplot(returns.MSFT, color='g')plt.xlabel('Return')plt.ylabel('Probability')plt.title('MSFT Returns')plt.show()
Blue-Chip Stock Portfolios for Quant Traders (10)

It is very interesting to compare Maximum Drawdown of these 2 stocks

wealth_index = (1+returns['AAPL']).cumprod()previous_peaks_MSFT = wealth_index.cummax()drawdowns_MSFT = (wealth_index - previous_peaks_MSFT)/previous_peaks_MSFTdrawdowns_MSFT.plot.line()plt.ylabel('Drawdown')plt.title('AAPL Maximum Drawdown')drawdowns_MSFT.min(), drawdowns_MSFT.idxmin()
Blue-Chip Stock Portfolios for Quant Traders (11)
wealth_index = (1+returns['MSFT']).cumprod()previous_peaks_MSFT = wealth_index.cummax()drawdowns_MSFT = (wealth_index - previous_peaks_MSFT)/previous_peaks_MSFTdrawdowns_MSFT.plot.line()plt.ylabel('Drawdown')plt.title('MSFT Maximum Drawdown')drawdowns_MSFT.min(), drawdowns_MSFT.idxmin()
Blue-Chip Stock Portfolios for Quant Traders (12)

It is worthwhile to look at correlations of their returns

corr = returns[['AAPL', 'MSFT']].corr()print(corr)sns.scatterplot(x="AAPL", y="MSFT", data=returns)sns.regplot(x="AAPL", y="MSFT", data=returns)
 AAPL MSFTAAPL 1.000000 0.532946MSFT 0.532946 1.000000
Blue-Chip Stock Portfolios for Quant Traders (13)

Then we can calculate their compounded growth and covariance

n_days = returns.shape[0]compounded_growth = (1+returns).prod()n_periods = returns.shape[0]ann_returns = compounded_growth**(252/n_days)-1ann_returns
AAPL 0.605810MSFT 0.477083dtype: float64
cov = returns.cov()cov
 AAPLMSFTAAPL0.0001790.000120MSFT0.0001200.000284

Let’s turn our attention to the efficient frontier of our 2 assets. In doing so, we need to calculate the portfolio return-volatility

# Calculate the portfolio returndef portfolio_return(w, r): return w.T @ r# Calculate the portfolio volatility returndef portfolio_vol(w, covmat): return (w.T @ covmat @ w)**0.5

We are now ready to plot the efficient frontier curve

#Plot the efficient frontier of two assetsax=plt.figure(figsize=(14,6))n_points = 15weights = [np.array([w, 1-w]) for w in np.linspace(0, 1, n_points)]def plot_ef2(n_points, returns, cov): weights = [np.array([w, 1-w]) for w in np.linspace(0, 1, n_points)] rets = [portfolio_return(w, ann_returns) for w in weights] vols = [portfolio_vol(w, cov) for w in weights] ef = pd.DataFrame({ "Returns": rets, "Volatility": vols }) return ef.plot.line(x="Volatility", y="Returns", style="o-")ax = plot_ef2(n_points, ann_returns, cov)ax.plot([0.013394], [0.605810], 'o',markersize=14)ax.annotate('AAPL', xy=(0.013394, 0.605810), xytext=(0.0137, 0.60), arrowprops=dict(facecolor='black', shrink=0.05))ax.plot([0.016852], [0.477083], 'o',markersize=14)ax.annotate('MSFT', xy=(0.016852, 0.477083), xytext=(0.016, 0.5), arrowprops=dict(facecolor='black', shrink=0.05))
Blue-Chip Stock Portfolios for Quant Traders (14)

Popular 4-Stock Portfolio

Our current objectives are as follows:

  • Build moving average of selected stocks
  • Determine correlations between stock returns
  • Create and validate an optimal stock portfolio
  • Predict the future behavior of selected stocks
#Importimport numpy as np import pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom pandas_datareader import datafrom datetime import datetime# Setting the begining and endingtoday = datetime.now()year_ago = datetime(today.year-1, today.month, today.day)
# Four company for data extractioncompany_list = ['AAPL', 'TSLA', 'MSFT', 'AMZN']

Reading input stock data:

for company in company_list: globals()[company] = pdr.get_data_yahoo(company, year_ago, today)
[*********************100%***********************] 1 of 1 completed[*********************100%***********************] 1 of 1 completed[*********************100%***********************] 1 of 1 completed[*********************100%***********************] 1 of 1 completed
price = yf.download(company_list, startdate, enddate)['Close']price.tail()
[*********************100%***********************] 4 of 4 completed
Blue-Chip Stock Portfolios for Quant Traders (15)

Let’s calculate MA 10-20-30

MA_days = [10, 20, 30]for ma in MA_days: ma_str = "MA AAPL {}".format(ma) price[ma_str] = price.AAPL.rolling(ma).mean() ma_str = "MA AMZN {}".format(ma) price[ma_str] = price.AMZN.rolling(ma).mean() ma_str = "MA MSFT {}".format(ma) price[ma_str] = price.MSFT.rolling(ma).mean() ma_str = "MA TSLA {}".format(ma) price[ma_str] = price.TSLA.rolling(ma).mean()price.tail() 
 AAPLAMZN MSFT TSLAMA AAPL 10 MA AMZN 10MA MSFT 10 MA TSLA 10MA AAPL 20MA AMZN 20MA MSFT 20MA TSLA 20MA AAPL 30MA AMZN 30MA MSFT 30MA TSLA 30Date2023-09-19179.070007137.630005328.649994266.500000177.631001140.334001332.945999264.648001180.4320137.736501329.637001254.881998179.340000137.489334326.883334248.0609992023-09-20175.490005135.289993320.769989262.589996176.889001140.327000331.734998265.715001180.3450137.788500329.552501256.351998179.196334137.334334326.707334248.4906662023-09-21173.929993129.330002319.529999255.699997176.526001139.475000330.696997266.136000179.9855137.479000329.179001257.293998179.054333137.050334326.617334248.9409992023-09-22174.789993129.119995317.010010244.880005176.187001138.564000328.970999265.774001179.9060137.343000329.031001258.035999178.948333136.735667326.420001248.9256662023-09-25176.080002131.270004317.540009246.990005175.859001137.381000326.931000263.115002179.7795137.243501328.759001258.455999178.891334136.497667326.304335249.070333
  • AAPL MA 10-20-30:
import matplotlibplt.figure(figsize=(15, 6))matplotlib.rcParams.update({'font.size': 18})plt.plot(price['AAPL'])plt.plot(price['MA AAPL 10'])plt.plot(price['MA AAPL 20'])plt.plot(price['MA AAPL 30']) plt.title('AAPL')plt.xlabel('Date')plt.ylabel('Price')plt.legend(('Close','MA: 10', 'MA: 20', 'MA:30'))plt.grid()plt.show()
Blue-Chip Stock Portfolios for Quant Traders (16)
  • AMZN MA 10-20-30:
plt.figure(figsize=(15, 6))matplotlib.rcParams.update({'font.size': 18})plt.plot(price['AMZN'])plt.plot(price['MA AMZN 10'])plt.plot(price['MA AMZN 20'])plt.plot(price['MA AMZN 30']) plt.title('AMZN')plt.xlabel('Date')plt.ylabel('Price')plt.legend(('Close','MA: 10', 'MA: 20', 'MA:30'))plt.grid()plt.show()
Blue-Chip Stock Portfolios for Quant Traders (17)
  • MSFT MA 10-20-30:
plt.figure(figsize=(15, 6))matplotlib.rcParams.update({'font.size': 18})plt.plot(price['MSFT'])plt.plot(price['MA MSFT 10'])plt.plot(price['MA MSFT 20'])plt.plot(price['MA MSFT 30']) plt.title('MSFT')plt.xlabel('Date')plt.ylabel('Price')plt.legend(('Close','MA: 10', 'MA: 20', 'MA:30'))plt.grid()plt.show()
Blue-Chip Stock Portfolios for Quant Traders (18)
  • TSLA MA 10-20-30:
plt.figure(figsize=(15, 6))matplotlib.rcParams.update({'font.size': 18})plt.plot(price['TSLA'])plt.plot(price['MA TSLA 10'])plt.plot(price['MA TSLA 20'])plt.plot(price['MA TSLA 30']) plt.title('TSLA')plt.xlabel('Date')plt.ylabel('Price')plt.legend(('Close','MA: 10', 'MA: 20', 'MA:30'))plt.grid()plt.show()
Blue-Chip Stock Portfolios for Quant Traders (19)

Let’s calculate and plot Daily Returns of our 4 stocks

price['Daily Returns AAPL'] = price['AAPL'].pct_change()price['Daily Returns AMZN'] = price['AMZN'].pct_change()price['Daily Returns MSFT'] = price['MSFT'].pct_change()price['Daily Returns TSLA'] = price['TSLA'].pct_change()
  • Daily Returns AAPL
sns.displot(price['Daily Returns AAPL'].dropna(), bins=50, color='blue', kde=True)plt.title("AAPL")plt.show()
Blue-Chip Stock Portfolios for Quant Traders (20)
  • Daily Returns AMZN
sns.displot(price['Daily Returns AMZN'].dropna(), bins=50, color='blue', kde=True)plt.title("AMZN")plt.show()
Blue-Chip Stock Portfolios for Quant Traders (21)
  • Daily Returns MSFT
sns.displot(price['Daily Returns MSFT'].dropna(), bins=50, color='blue', kde=True)plt.title("MSFT")plt.show()
Blue-Chip Stock Portfolios for Quant Traders (22)
  • Daily Returns TSLA
sns.displot(price['Daily Returns TSLA'].dropna(), bins=50, color='blue', kde=True)plt.title("TSLA")plt.show()
Blue-Chip Stock Portfolios for Quant Traders (23)

Let’s prepare the above returns for the stock correlation analysis

stock_returns = pd.DataFrame()stock_returns['AAPL']=price['Daily Returns AAPL'].dropna() stock_returns['AMZN']=price['Daily Returns AMZN'].dropna()stock_returns['MSFT']=price['Daily Returns MSFT'].dropna()stock_returns['TSLA']=price['Daily Returns TSLA'].dropna()stock_returns.tail()
Blue-Chip Stock Portfolios for Quant Traders (24)
  • Pair plot
sns.pairplot(stock_returns)plt.savefig('pairplot_tech.png')
Blue-Chip Stock Portfolios for Quant Traders (25)
  • Correlation matrix
# Build correlation matrixcorr = stock_returns.corr()mask = np.triu(np.ones_like(corr, dtype=bool))plt.figure(figsize=(10, 10))sns.heatmap(corr, mask=mask, square=True, linewidths=.5, annot=True)#plt.show()plt.savefig('corrmatrix_tech.png')
Blue-Chip Stock Portfolios for Quant Traders (26)
  • Joint plot
def draw_jointplot(data): grid = sns.PairGrid(data.dropna()) grid.map_diag(sns.histplot, bins=40, kde=True) grid.map_lower(sns.regplot) grid.map_upper(sns.kdeplot)
draw_jointplot(stock_returns)plt.savefig('stockreturns_tech.png')
Blue-Chip Stock Portfolios for Quant Traders (27)

Here, Row 1: AAPL, Row 2: AMZN, Row 3: MSFT, Row 4: TSLA.

Let’s calculate the mean returns and covariance of our stocks

mean_income = stock_returns.mean() # Mean income for each stockcov_returns = stock_returns.cov() # Covariation count = len(stock_returns.columns)print(mean_income, cov_returns, sep='\n')
AAPL 0.001970AMZN 0.002569MSFT 0.001689TSLA 0.005150dtype: float64
 AAPL AMZN MSFT TSLAAAPL 0.000179 0.000115 0.000120 0.000215AMZN 0.000115 0.000467 0.000218 0.000301MSFT 0.000120 0.000218 0.000284 0.000207TSLA 0.000215 0.000301 0.000207 0.001217

Let’s find the maximum Sharpe ratio of our portfolio by generating random shares while plotting the efficient frontier curve as an envelope

# Function, that generate random sharesdef randomPortfolio(): share = np.exp(np.random.randn(count)) share = share / share.sum() return sharedef IncomePortfolio(Rand): return np.matmul(mean_income.values, Rand)def RiskPortfolio(Rand): return np.sqrt(np.matmul(np.matmul(Rand, cov_returns.values), Rand))
combinations = 4000risk = np.zeros(combinations)income = np.zeros(combinations)portfolio = np.zeros((combinations, count))# Function, which create new combinations of sharesfor i in range(combinations): rand = randomPortfolio() portfolio[i, :] = rand risk[i] = RiskPortfolio(rand) income[i] = IncomePortfolio(rand)
plt.figure(figsize=(15, 8))plt.scatter(risk * 100, income * 100, c="b", marker="o",s=20)plt.xlabel("Risk")plt.ylabel("Income")plt.title("Portfolios")MaxSharpRatio = np.argmax(income / risk)plt.scatter([risk[MaxSharpRatio] * 100], [income[MaxSharpRatio] * 100], s=140,c="r", marker="o", label="Max Sharp ratio")plt.legend()#plt.show()plt.savefig('efficiencycurve_portfolios.png')
Blue-Chip Stock Portfolios for Quant Traders (28)

Finally, we can compare the maximum Sharpe ratios of our stocks

best_port = portfolio[MaxSharpRatio]for i in range(len(company_list)): print("{} : {}".format(company_list[i], best_port[i]))
AAPL : 0.5737824378783145TSLA : 0.1887338094255849MSFT : 0.033839219286878226AMZN : 0.2036445334092224

Monte-Carlo Predictions

We will consider the 1Y forecast with the mean and STD values

days = 365dt = 1 / daysstock_returns.dropna(inplace=True)mu = stock_returns.mean()sigma = stock_returns.std()

We need the following function

def monte_carlo(start_price, days, mu, sigma): price = np.zeros(days) price[0] = start_price shock = np.zeros(days) drift = np.zeros(days) for x in range(1, days): shock[x] = np.random.normal(loc=mu * dt, scale=sigma*np.sqrt(dt)) drift[x] = mu * dt price[x] = price[x-1] + (price[x-1] * (drift[x] + shock[x])) return price
  • AAPL
price['AAPL'].describe()
count 183.000000mean 168.418634std 17.755754min 125.01999725% 153.84000450% 172.69000275% 180.955002max 196.449997Name: AAPL, dtype: float64
start_price = 168.418634sim = np.zeros(1000)plt.figure(figsize=(15, 8))for i in range(1000): result = monte_carlo(start_price, days, mu['AAPL'], sigma['AAPL']) sim[i] = result[days - 1] plt.plot(result) plt.xlabel('Days')plt.ylabel('Price')plt.title('Monte Carlo Analysis for AAPL')plt.savefig('monte_aapl.png')
Blue-Chip Stock Portfolios for Quant Traders (29)
plt.figure(figsize=(10, 7))plt.hist(sim, bins=100)plt.figtext(0.6, 0.7, "Mean: {} \nStd: {} \nStart Price: {}".format(sim.mean(), sim.std(), start_price))#plt.show()plt.savefig('montehist_aapl.png')
Blue-Chip Stock Portfolios for Quant Traders (30)
  • MSFT
price['MSFT'].describe()
count 183.000000mean 299.507268std 36.373372min 222.30999825% 267.14500450% 311.73999075% 330.964996max 359.489990Name: MSFT, dtype: float64
start_price = 299.507268sim = np.zeros(1000)plt.figure(figsize=(15, 8))for i in range(1000): result = monte_carlo(start_price, days, mu['MSFT'], sigma['MSFT']) sim[i] = result[days - 1] plt.plot(result) plt.xlabel('Days')plt.ylabel('Price')plt.title('Monte Carlo Analysis for MSFT')plt.savefig('monte_msft.png')
Blue-Chip Stock Portfolios for Quant Traders (31)
plt.figure(figsize=(10, 7))plt.hist(sim, bins=100)plt.figtext(0.6, 0.7, "Mean: {} \nStd: {} \nStart Price: {}".format(sim.mean(), sim.std(), start_price))#plt.show()plt.savefig('montehist_msft.png')
Blue-Chip Stock Portfolios for Quant Traders (32)
  • AMZN
price['AMZN'].describe()
count 183.000000mean 114.791913std 17.026834min 83.12000325% 99.38000150% 112.91000475% 130.184998max 144.850006Name: AMZN, dtype: float64
start_price = 114.791913sim = np.zeros(1000)plt.figure(figsize=(15, 8))for i in range(1000): result = monte_carlo(start_price, days, mu['AMZN'], sigma['AMZN']) sim[i] = result[days - 1] plt.plot(result) plt.xlabel('Days')plt.ylabel('Price')plt.title('Monte Carlo Analysis for AMZN')plt.savefig('monte_amzn.png')
Blue-Chip Stock Portfolios for Quant Traders (33)
plt.figure(figsize=(10, 7))plt.hist(sim, bins=100)plt.figtext(0.6, 0.7, "Mean: {} \nStd: {} \nStart Price: {}".format(sim.mean(), sim.std(), start_price))#plt.show()plt.savefig('montehist_amzn.png')
Blue-Chip Stock Portfolios for Quant Traders (34)
  • TSLA
price['TSLA'].describe()
count 183.000000mean 209.919180std 45.605744min 108.09999825% 180.29499850% 201.28999375% 254.904999max 293.339996Name: TSLA, dtype: float64
Blue-Chip Stock Portfolios for Quant Traders (35)
plt.figure(figsize=(10, 7))plt.hist(sim, bins=100)plt.figtext(0.6, 0.7, "Mean: {} \nStd: {} \nStart Price: {}".format(sim.mean(), sim.std(), start_price))#plt.show()plt.savefig('montehist_tsla.png')
Blue-Chip Stock Portfolios for Quant Traders (36)

SPY Return/Volatility

Let’s look at the SPY index in 2023

# import modulesfrom datetime import datetimeimport yfinance as yfimport matplotlib.pyplot as plt # initialize parametersstart_date = datetime(2023, 1, 1)end_date = datetime(2023, 9, 25) # get the datadata = yf.download('SPY', start = start_date, end = end_date) # displayplt.figure(figsize = (20,10))plt.title('Opening Prices from {} to {}'.format(start_date, end_date))plt.plot(data['Open'],lw=4)plt.grid(color='k', linestyle='--', linewidth=1)plt.show()
Blue-Chip Stock Portfolios for Quant Traders (37)

Let’s calculate the average annual SPY return and volatility

nifty=data.copy()nifty_returns=(nifty['Close']/nifty['Open'])-1volatility= np.std(nifty_returns)trading_days=len(nifty_returns)mean=nifty_returns.mean()print('Annual Average SPY return',mean)print('Annual volatility',volatility*np.sqrt(trading_days))print('Number of trading days',trading_days)
Annual Average SPY return 0.0006876400629725226Annual volatility 0.09887050147370505Number of trading days 182

The SPY daily returns are given by

daily_returns=np.random.normal(mean/trading_days,volatility,trading_days)+1index_returns=[10980] for x in daily_returns: index_returns.append(index_returns[-1]*x)plt.plot(daily_returns)plt.show()
Blue-Chip Stock Portfolios for Quant Traders (38)

The corresponding 1000 random simulations of daily returns are

for i in range(1000): daily_returns=np.random.normal(mean/trading_days,volatility,trading_days)+1 index_returns=[10980] for x in daily_returns: index_returns.append(index_returns[-1]*x) plt.plot(daily_returns)plt.show()
Blue-Chip Stock Portfolios for Quant Traders (39)

SPY Prophet Forecast

Let’s prepare the SPY stock data for the FB Prophet forecast

nifty.reset_index(inplace=True)nifty['Date']= pd.to_datetime(nifty['Date'])nifty.rename(columns={'Date':'ds','Open':'y'},inplace=True)

The forecast model is expressed as

from prophet import Prophetmodel=Prophet()model.fit(nifty)predict_df=model.make_future_dataframe(periods=252)predict_df.tail()
 ds4292024-05-274302024-05-284312024-05-294322024-05-304332024-05-31

Let’s plot the forecast and its components

forecast=model.predict(predict_df)
fig1=model.plot(forecast)plt.xticks(fontsize = 15)
Blue-Chip Stock Portfolios for Quant Traders (40)
fig2=model.plot_components(forecast,figsize=(14,5))
Blue-Chip Stock Portfolios for Quant Traders (41)

Summary

  • In this post, we have shown how to compute stock volatility in Python and the different measures of risk-adjusted returns based on it.
  • While we continue to rank SPY as a long-term hold position, we focused our discussion on rather short-term trading strategies to see how topblue-chip stocks have now again gained positive momentum.
  • The AAPL example has explained how quant traders can use various SMA and MA crossovers to identify buy and sell signals. These signals have been verified using regression support and resistance lines.
  • The AAPL-MSFT example has illustrated the value of an efficient frontier graph, maximum drawdown curves, correlations of returns, covariance metrics, and the compounded growth.
  • The 4-stock portfolio example has demonstrated the importance of comparing and integrating popular trading indicators, correlation plots, and Monte Carlo simulations.
  • Finally, we have analyzed the SPY index in terms of volatility and average returns using both historical data and the Prophet forecast model.
  • Results produced by this software have been verified by comparison to a number of well known 3rd party trading platforms such as Macroaxis, TradingView, Barchart, etc.

References

Explore More

  • Applying a Risk-Aware Portfolio Rebalancing Strategy to ETF, Energy, Pharma, and Aerospace/Defense Stocks in 2023
  • Risk-Aware Strategies for DCA Investors
  • Joint Analysis of Bitcoin, Gold and Crude Oil Prices with Optimized Risk/Return in 2023
  • Towards Max(ROI/Risk) Trading
  • DJI Market State Analysis using the Cruz Fitting Algorithm
  • Bear vs. Bull Portfolio Risk/Return Optimization QC Analysis
  • A TradeSanta’s Quick Guide to Best Swing Trading Indicators
  • Stock Portfolio Risk/Return Optimization
  • Risk/Return QC via Portfolio Optimization – Current Positions of The Dividend Breeder
  • Portfolio Optimization Risk/Return QC – Positions of Humble Div vs Dividend Glenn
  • The Qullamaggie’s TSLA Breakouts for Swing Traders
  • The Qullamaggie’s OXY Swing Breakouts
  • Algorithmic Testing Stock Portfolios to Optimize the Risk/Reward Ratio
  • Quant Trading using Monte Carlo Predictions and 62 AI-Assisted Trading Technical Indicators (TTI)
  • Are Blue-Chips Perfect for This Bear Market?
  • Track All Markets with TradingView
  • Stock Forecasting with FBProphet
  • Predicting Trend Reversal in Algorithmic Trading using Stochastic Oscillator in Python
  • Inflation-Resistant Stocks to Buy
  • ML/AI Regression for Stock Prediction – AAPL Use Case
  • Macroaxis Wealth Optimization
  • Investment Risk Management Study

One-Time

Monthly

Yearly

Make a one-time donation

Make a monthly donation

Make a yearly donation

Choose an amount

€5.00

€15.00

€100.00

€5.00

€15.00

€100.00

€5.00

€15.00

€100.00

Or enter a custom amount

Your contribution is appreciated.

Your contribution is appreciated.

Your contribution is appreciated.

DonateDonate monthlyDonate yearly

Blue-Chip Stock Portfolios for Quant Traders (2024)
Top Articles
Latest Posts
Article information

Author: Duane Harber

Last Updated:

Views: 5508

Rating: 4 / 5 (71 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Duane Harber

Birthday: 1999-10-17

Address: Apt. 404 9899 Magnolia Roads, Port Royceville, ID 78186

Phone: +186911129794335

Job: Human Hospitality Planner

Hobby: Listening to music, Orienteering, Knapping, Dance, Mountain biking, Fishing, Pottery

Introduction: My name is Duane Harber, I am a modern, clever, handsome, fair, agreeable, inexpensive, beautiful person who loves writing and wants to share my knowledge and understanding with you.