How to code your own stock backtester [PART 2: Making the trading indicator, MACD]

Lucas Moyer
The Koi Life
Published in
3 min readNov 12, 2023

In the previous article, we got stock data from yahoo finance. Now to build our trading robotrader, we need to take this data and turn it into a trading indicator that can tell whether or not to buy a stock.

There are many versions of this. One way could be to use the number of mentions a particular stock gets on twitter/X and then purchase a stock, but the way we will be doing this is by comparing the long and short the moving averages of the price of a stock.

Pulling up Microsoft’s stock chart on Yahoo Finance, and adding the MACD indicator would look something like this

MACD (Moving Average Convergence Divergence) is simply watching when the long and short moving averages converge or diverge. Specifically, we will be using exponential moving averages.

In the example above, the purple line is a 12 day moving average of the stock price while the orange line is a 26 day moving average. Since the 26 day is a longer time period, it’s line is a lot smoother and resistant to small changes in the stock price.

What does it mean when the two lines converge or diverge?

There are multiple ways to read the MACD chart, and you can do so here. In this example we will watch when the shorter moving average (purple) crosses above the longer moving average (orange). We will hypothesize that this means we think the stock price is going to go up.

Now we will translate this logic into python code.

From our previous article, we wrote code to get our stock data and put it in a pandas dataframe like so:

What our data looks like

Then we calculate the two moving averages

short = 12
long = 26
df['exp_short']= df['Adj Close'].ewm(span=short, adjust=False).mean()
df['exp_long'] = df['Adj Close'].ewm(span=long, adjust=False).mean()

Since we want to see when the short moving average (MA) crosses above the longer MAs, we will subtract short minus long. That means when the difference is positive, we will buy the stock, when it is negative, we can short or sell the stock.

df['macd'] = df['exp_short']  - df['exp_long'] 
df['macd_norm'] = (df['macd'] - df['macd'].min()) * 2 / (df['macd'].max() - df['macd'].min()) -1

The ‘macd_norm’ is the macd values normalized so the values range from -1 to 1. This is so we know what values to expect and can create other trading indicators with similar outputs. In the future, we can implement multiple strategies at once or see which strategies produce stronger signals.

Plotting the data, we get something similar to the yahoo chart

# Plotting
fig, ax1 = plt.subplots(figsize=(10, 6))

# Plot Close on the first y-axis
ax1.plot(df.index, df['Close'], color='b', label='Close')
ax1.plot(df.index, df['exp_short'], color='g', linestyle='--', label='Exp Short')
ax1.plot(df.index, df['exp_long'], color='orange', linestyle='--', label='Exp Long')

ax1.set_xlabel('Date')
ax1.set_ylabel('Close', color='b')
ax1.tick_params('y', colors='b')

# Create a second y-axis for macd_norm
ax2 = ax1.twinx()
ax2.plot(df.index, df['macd_norm'], color='r', label='MACD Normalized')
ax2.set_ylabel('MACD Normalized', color='r')
ax2.tick_params('y', colors='r')

plt.title('Close and MACD Normalized Over Time')
plt.show()

Now you may be wondering, does this strategy make money? In the next article we will take the “macd_norm” we calculated and use it to perform a backtest which will tell us how our strategy would have performed in a some time period in the past. Stay tuned!

Bali Rice Farm

--

--

Lucas Moyer
The Koi Life

I strive to wake up everyday and pursue what I find most interesting. Writer for The Startup. Owner of The Koi Life medium.com/lucas-moyer