Buy And Hold Vs SMA Crossover: Big Profits With Simple Strategy

Sanela I.
CodeX
Published in
11 min readMar 8, 2022

--

The stock market is booming, and everyone wants to hop on this train to generate wealth. And I bet this is what brought you here as well, “best trading/investing strategy”, but a simple google search with this quote can give you a bottomless pit of complex trading strategies claiming to be the best out of all. And we’ll like to explain this in the words of legendary investor Warren Buffet, “There seems to be some perverse human characteristic that likes to make easy things difficult.”

Photo by Kelly Sikkema on Unsplash

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — Disclosure: Nothing in this post should be regarded investment advice. Past results are not always predictive of future results. These are some typical examples of how to use Pandas to import data for a small sample of stocks across various time intervals and compare their individual performance. All investment-related queries should be directed to your financial advisor.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Making money in the stock market is easy if you are disciplined and keep your objective clear. Saying this is easy, but when we put our money on the line, our emotional intent often budges with our discipline; hence we have to lose our hard-earned cash in this money-making machine, aka stock markets.

Algorithmic trading (also known as black-box trading or Algo-trading) is becoming popular among modern retailers to remove the impediments of emotion management. In Algo trading, a computer program executes buy or sell orders based on the set of rules/instruction you provide.

What Is Algo Trading?

Algo trading is a systematic approach to active trading that identifies the opportunity based on a mathematical model. Mathematical models are usually based on indicators derived from the stock price, volume, institutional buying/selling, bulk or block deals, etc. There are four types of technical indicators — Momentum indicators, Volatility indicators, & Volume indicators and are used to predict the future movement of price.

Advantages of algo trading:

1) Execution at best possible price

2) Instant order placement

3) Reduced manual errors

4) Reduced possibility of mistakes caused by emotional and psychological factors.

5) Code can be easily backtested and refined according to the backtest result.

We bet you are already baffled keeping an account of all these indicators, but as Albert Einstein said, “the genius is in making the complex simple” we’ll stick with 2 of the most influential and profitable strategies and compare the results of both.

STRATEGY 1- SIMPLE MOVING AVERAGE (SMA) CROSSOVER

Moving averages or rolling averages is one of the most common methods of analyzing time-series data. It involves generating a series of averages from various subsets of the whole dataset and is used to eliminate ‘noise’ in stocks performance.

SMA is calculated by adding the close price of the previous “n” number of days and dividing it by the number of days.

Source: Investopedia

SMA crossover strategy is usually practiced with moving averages of 2 lengths:

  1. Short moving average-faster moving average which is more reactive to daily price changes
  2. Long moving average-slower moving average which indicates prices over a longer period and is more inert.

In this example we will be using 50 days for short moving average and 200 days for long moving average. Other popular short and long moving averages are: 9 and 21 days.

When crossover between short and long moving averages happens, two signals are generated:

Buy (purchase) signal- when the shorter moving average exceeds, the longer moving average, i.e., short moving average crosses long moving average from below — also known as Golden crossover.

Sell (short) signal- when the longer moving average exceeds the shorter moving average, i.e., short moving average crosses long moving average from above — also known as Dead crossover.

STRATEGY 2- Buy and Hold

It is a passive investment strategy where an investor buys an asset and holds it for a prolonged time. Traders/investors following this strategy aren’t concerned with short-term price fluctuations in the market and technical indicators. Investors like Warren Buffet and Jack Bogle are advocates of the buy-and-hold approach.

It is one of the most accessible types of investment strategy where our loyalty and commitment for an extended period of time is rewarded.

Another option is to utilize time-series that correlate to changes in the asset’s monetary value rather than actual values. These time-series may and do take on negative traits, and their statistical features are often more stable than price period. The most common kind of returns are relative returns, which are defined as

Source: Investopedia

and log-return

Source: Investopedia

To mathematically execute this strategy, we can use log return which is calculated by taking a natural log of ending value divided by starting value.

Advantages of using log-returns are:

1) Log returns can be added across different time periods. (On other hands, adding simple returns can mislead the outcomes)

2) Log returns follow the normal distribution.

3) Log returns can be converted into simple returns.

Since log returns are additive, you can create the time series of cumulative log returns.

A Close Analysis Of Both Strategies — BUY AND HOLD Vs SMA CROSSOVER

To backtest or run a strategy in live markets, we have to follow the following structure:

1) Select the stocks/mutual funds/ETFs/cryptocurrency

2) Extract their information (closing price, volume, etc.) for the selected stocks for a defined time frame

3) Visualize the data for better understanding

4) Run and compare mathematical models

To conclude a winner between the 2 strategies we mentioned above, we’ll start with making a portfolio of stocks.

Stocks that are used in this portfolio are:(AMD)Advanced Micro Devices, (GOOGLE)Google,(WST)West Pharmaceutical Services,(DXCM)Dexcom INC. (Glucose monitoring), (NVDA)NVIDIA Corporation, (AAPL)Apple, (AMZN)Amazon, (MSFT)Microsoft, (NFLX)Netflix, (TSLA)Tesla

Importing libraries:

import numpy as np
import pandas as pd
from datetime import date
!pip install yfinance
import matplotlib.pyplot as plt
import yfinance as yf
%matplotlib inline

We are going to use Yahoo Finance! API and we will extract closing price for time-period 2020–2022

#choose starting date
start_date = '2020-01-01'
end_date= '2022-01-01'
#if using a current date as end date
#end_date=date.today().strftime("%Y-%m-%d")
symbol =['AMD','GOOGL','WST','DXCM','NVDA','AAPL','AMZN','NFLX','TSLA','MSFT']#stock portfolio
df = yf.download(symbol, start=start_date, end = end_date)['Close'] #getting only Closing price values
df.head()

Here we will display first five rows of closing prices for entire portfolio

Closing Prices

Visualizing the data:

When we have a time-series data we can plot the data on a chart, making price patterns and trends visually identifiable.

Here we are using the Matplotlib library to show closing price movements from where we can get immediate insight if particular stock performed well or not with a time.

#Charting the stock prices for multiple stocks
fig = plt.figure(figsize=(16,12))
ax1 = fig.add_subplot(4,3,1)
ax2 = fig.add_subplot(4,3,2)
ax3 = fig.add_subplot(4,3,3)
ax4 = fig.add_subplot(4,3,4)
ax5 = fig.add_subplot(4,3,5)
ax6 = fig.add_subplot(4,3,6)
ax7 = fig.add_subplot(4,3,7)
ax8 = fig.add_subplot(4,3,8)
ax9 = fig.add_subplot(4,3,9)
ax10 = fig.add_subplot(4,3,10)
ax1.plot(df['AMZN'])
ax1.set_title("Amazon")
ax2.plot(df['AMD'])
ax2.set_title("AMD")
ax3.plot(df['GOOGL'])
ax3.set_title("Google")
ax4.plot(df['NFLX'])
ax4.set_title("Netflix")
ax5.plot(df['WST'])
ax5.set_title("WST")
ax6.plot(df['DXCM'])
ax6.set_title("DXCM")
ax7.plot(df['NVDA'])
ax7.set_title("NVDA")
ax8.plot(df['TSLA'])
ax8.set_title("Tesla")
ax9.plot(df['AAPL'])
ax9.set_title("AAPL")
ax10.plot(df['MSFT'])
ax10.set_title("MSFT")
plt.tight_layout()
# save the figure
plt.savefig('Stock Price Movement.png')#format="png")
plt.show()
Stock prices movement (photo by author)

1.Analyzing the AMD stock

To keep things easy, we’ll test our strategies only on one stock: Advanced Micro Devices (ticker:AMD), before applying to the entire portfolio.

We are going to define values for simple moving averages: for short moving averages we will be using 50 days and for long moving averages will using 200 days.

To calculate moving average, we use Pandas a build in function rolling(window=’n’).mean (We can replace “n” with the number of days.)

# Get the AMD timeseries.
AMD = df.loc[:, 'AMD']
# Calculate the 50 and 200 days moving averages of the closing prices
short_rolling_AMD= AMD.rolling(window=50, min_periods=1).mean()#min_periods calculate the arithmetic average starting from 1st numb
long_rolling_AMD = AMD.rolling(window=200, min_periods=1).mean()

Next, we are creating data frame for AMD stock with additional information: signal and position, calculating rate of return using daily log return and calculating total trading system return for buy and hold strategy.

Signal’ column is generated following: value 1 is set if 50 day SMA is greater than 200 day SMA, value 0 is set when 200 day SMA is grater that 50 day SMA.

Position’ column is day to day difference of ‘Signal’ column

Trade’ column is generated same as signal with exception of setting value -1 instead of 0 when 200 day SMA is > than 50 day SMA.

Return’ column is generated using log return where firs the logarithm of the price is taken and then the difference of consecutive log observations.

Treturn’ column is total return which is calculating by multiplying ‘Return’ and ‘Trade’ columns.

#creating df for AMD stock
AMD=pd.DataFrame ({'Close':df['AMD'],'50_MA':short_rolling_AMD,'200_MA':long_rolling_AMD})
#generate signals
AMD['Signal']=np.where(AMD['50_MA']> AMD['200_MA'], 1, 0)
#generate trading orders
AMD['Position']=AMD['Signal'].diff()
#calculating trading
AMD['Trade'] = np.where(AMD['50_MA']> AMD['200_MA'], 1, -1)
#to calculate instantaneous rate of return (daily log returns)
AMD['Return'] = np.log(AMD.Close).diff()
#calculating trading system return
AMD['Treturn']=AMD.Return*AMD.Trade
AMD.head(100)
AMD DataFrame (photo by author)

Next, we can visualize buying and selling points for trading strategy. Buying signal are a green color and selling signal are a red color.

# Plot moving averages 
# plot closing price, short term moving averages and long term moving averages
plt.figure(figsize=(20,10))
AMD['Close'].plot(color = 'k', label= 'Closing Price')
AMD['50_MA'].plot(color = 'm',label = '50 days rolling mean')
AMD['200_MA'].plot(color = 'g', label = '200 days rolling mean')
# plot ‘buy’ signals
plt.scatter(AMD.loc[AMD['Position'] == 1].index,
AMD['50_MA'][AMD['Position'] == 1],
marker='^', s=250,color = 'g', label = 'BUY signal')
# plot ‘sell’ signals
plt.scatter(AMD.loc[AMD['Position'] == -1].index,
AMD['50_MA'][AMD['Position'] == -1],
marker='v',s=250, color = 'r', label = 'SELL signal')
plt.title('AMD Buy and Sell signals')
plt.xlabel('Date')
plt.ylabel(' Closing price ($)')
plt.savefig('AMD buying and selling signals.png')
#plt.show()
plt.legend();
AMD Buy and Sell signals (photo by author)

Now we are going to sum returns for both strategies:

#trading system return
total_treturn=np.exp(AMD.Treturn.sum())#total return of moving averages trading system
#Buy and hold return
hold_return=np.exp(AMD.Return.sum())#total return of buy and hold strategy
print("AMD Trading System total return: {:>10.2%}".format(total_treturn))
print("AMD Hold strategy return: {:>10.2%}".format(hold_return))

As the result we can see that Hold strategy had 293.08% return versus trading strategy with 141.76% return.

AMD trading system vs Buy and Hold returns (Photo by author)

2.Analyzing portfolio return

In this part we are going to analyze returns for entire portfolio. Starting with calculating short and long moving averages and creating trading column

# Calculating the short-window moving average for entire portfolio
short_rolling= df.rolling(window=50,min_periods=1).mean()
df_short = short_rolling.add_suffix('_short')
# Calculating the long-window moving average for entire portfolio
long_rolling = df.rolling(window=200,min_periods=1).mean()
df_long = long_rolling.add_suffix('_long')
#to join two tables into one df
new_df=pd.concat([df_short,df_long],axis=1)
#calculating trading for entire portfolio
new_df['AMD_Trade'] = np.where(new_df['AMD_short']> new_df['AMD_long'], 1, -1)
new_df['AMZN_Trade'] = np.where(new_df['AMZN_short']> new_df['AMZN_long'], 1, -1)
new_df['AAPL_Trade'] = np.where(new_df['AAPL_short']> new_df['AAPL_long'], 1, -1)
new_df['DXCM_Trade'] = np.where(new_df['DXCM_short']> new_df['DXCM_long'], 1, -1)
new_df['MSFT_Trade'] = np.where(new_df['MSFT_short']> new_df['MSFT_long'], 1, -1)
new_df['NFLX_Trade'] = np.where(new_df['NFLX_short']> new_df['NFLX_long'], 1, -1)
new_df['NVDA_Trade'] = np.where(new_df['NVDA_short']> new_df['NVDA_long'], 1, -1)
new_df['TSLA_Trade'] = np.where(new_df['TSLA_short']> new_df['TSLA_long'], 1, -1)
new_df['WST_Trade'] = np.where(new_df['WST_short']> new_df['WST_long'], 1, -1)
new_df['GOOGL_Trade'] = np.where(new_df['GOOGL_short']> new_df['GOOGL_long'], 1, -1)
# creating return column
log_returns = np.log(df).diff()
df_return= log_returns.add_suffix('_Return')
new_df=pd.concat([df_return,new_df],axis=1)
#remove NA values
new_df.dropna(inplace=True)
#calculating instatenious rate of return
new_df['AMD_Treturn']=new_df.AMD_Return*new_df.AMD_Trade
AMD_total_treturn=np.exp(new_df.AMD_Treturn.sum())
print('AMD_total_treturn is:',AMD_total_treturn)
new_df['AMZN_Treturn']=new_df.AMZN_Return*new_df.AMZN_Trade
AMZN_total_treturn=np.exp(new_df.AMZN_Treturn.sum())
print('AMZN_total_treturn is:',AMZN_total_treturn)
new_df['AAPL_Treturn']=new_df.AAPL_Return*new_df.AAPL_Trade
AAPL_total_treturn=np.exp(new_df.AAPL_Treturn.sum())
print('AAPL_total_treturn is:',AAPL_total_treturn)
new_df['DXCM_Treturn']=new_df.DXCM_Return*new_df.DXCM_Trade
DXCM_total_treturn=np.exp(new_df.DXCM_Treturn.sum())
print('DXCM_total_treturn is:',DXCM_total_treturn)
new_df['MSFT_Treturn']=new_df.MSFT_Return*new_df.MSFT_Trade
MSFT_total_treturn=np.exp(new_df.MSFT_Treturn.sum())
print('MSFT_total_treturn is:',MSFT_total_treturn)
new_df['NFLX_Treturn']=new_df.NFLX_Return*new_df.NFLX_Trade
NFLX_total_treturn=np.exp(new_df.NFLX_Treturn.sum())
print('NFLX_total_treturn is:',NFLX_total_treturn)
new_df['NVDA_Treturn']=new_df.NVDA_Return*new_df.NVDA_Trade
NVDA_total_treturn=np.exp(new_df.NVDA_Treturn.sum())
print('NVDA_total_treturn is:',NVDA_total_treturn)
new_df['TSLA_Treturn']=new_df.TSLA_Return*new_df.TSLA_Trade
TSLA_total_treturn=np.exp(new_df.TSLA_Treturn.sum())
print('TSLA_total_treturn is:',TSLA_total_treturn)
new_df['WST_Treturn']=new_df.WST_Return*new_df.WST_Trade
WST_total_treturn=np.exp(new_df.WST_Treturn.sum())
print('WST_total_treturn is:',WST_total_treturn)
new_df['GOOGL_Treturn']=new_df.GOOGL_Return*new_df.GOOGL_Trade
GOOGL_total_treturn=np.exp(new_df.GOOGL_Treturn.sum())
print('GOOGL_total_treturn is;',GOOGL_total_treturn)
Trade strategy returns (photo by author)
treturns_total = [AMD_total_treturn,AMZN_total_treturn,AAPL_total_treturn,DXCM_total_treturn,MSFT_total_treturn,NFLX_total_treturn,NVDA_total_treturn,TSLA_total_treturn,WST_total_treturn,GOOGL_total_treturn]potrfolio_trade_strategy = sum(treturns_total) / len(treturns_total)
print("Portfolio return using trade strategy: {:>10.2%}".format(potrfolio_trade_strategy))

Calculating return for buy and hold strategy:

#calculating stock return hold strategy  
log_returns_stock=np.exp(log_returns.sum())#total return of hold strategy
log_returns_stock
Buy and Hold returns
portfolio_return=log_returns_stock.mean(axis=0)
print("Portfolio return using hold strategy: {:>10.2%}".format(portfolio_return))
Portfolio return using trade strategy: 241.10%

We can see that buy and hold strategy performed better with 358% yearly return while trading strategy had 241% return.

We can visualize return of each stock with buy and hold strategy.

fig, ax= plt.subplots(figsize=(20,10))
for c in log_returns:
ax.plot(log_returns.index, 100*(np.exp(log_returns[c].cumsum()) - 1), label=str(c))
ax.set_ylabel('Total relative returns (%)')
ax.set_xlabel('Time period')
ax.set_title('Portfolio return using hold strategy')
ax.legend(loc='best')
plt.show()
Portfolio return with buy and hold strategy (photo by author)

Furthermore, the information gathered on returns was used for Risk Analysis which was calculated from expected return (average/ mean return of the stock) and standard deviation( measurement of risk->greater SD greater is the risk and vice versa).

returns = log_returns #using log_return 
plt.figure(figsize=(20,10))
plt.scatter(returns.mean(), returns.std())
plt.xlabel('Expected returns')
plt.ylabel('Risk')
plt.title('Risk vs.Expected Return')
for label, x, y in zip(returns.columns, returns.mean(), returns.std()):
plt.annotate(
label,
xy = (x, y), xytext = (50, 30),
textcoords = 'offset points', ha = 'right', va = 'bottom',
arrowprops = dict(arrowstyle = '-', connectionstyle = 'arc3,rad=0.5'))

A scatter plot was created for comparing the Expected return of stock to its risk. This helps us to visualize the risk factor of various stocks.

Risk vs. Expected return (photo by author)

From this scatterplot we can conclude that TSLA has highest expected return and highest risk. On the other hand, AMZN has smallest expected return and smallest risk.

Which Strategy Is More Profitable?

After testing both strategies, we can conclude that the Buy and Hold outperforms the trading strategy on AMD stock and on entire portfolio.

But remember, “like no one size t-shirt fits everybody, similarly no single strategy is best for all asset class.” The results shared above are for the stock AMD, and it might not coincide with the stock AAPL (or any other stock of your portfolio).

We need to test the performance of each portfolio stock under both strategies and then pick the strategy that yields the best return for each.

References:

  1. Yahoo Finance!
  2. Investopedia
  3. M. Heydt, Learning pandas-second edition (2017)

Jupyter Notebook with detailed code can be found here:

You can check my other writings at: https://medium.com/@eellaaivo

Thanks for reading!

--

--