Step-by-Step Guide to Adding the MACD to Your Python Trading Bot
Quick and easy way to add the MACD to your Trading Bot to use on any financial asset you choose.
Quick and easy way to add the MACD to your Trading Bot to use on any financial asset you choose.
The Moving Average Convergence / Divergence (MACD) technical indicator is one of the world's most popular technical indicators. Many intraday traders use the MACD to help identify price trends and find entry points for their trades.
Whether you trade in the crypto markets, FOREX markets, or stock markets, the MACD is a useful indicator to have in your trading bot toolbox.
In this story, I’ll show you how to add the MACD to your autotrading bot.
This episode will demonstrate how to add the MACD technical indicator to your trading bot. If you’re using the trading bot from this GitHub repo, you’ll be able to use the MACD on any market you trade.
Great education experiences lead to incredible life outcomes. At least that’s my belief. As I build my team, here’s what we’ve got so far:
It’s almost inevitable that you won't stop with just one indicator. Almost every client I’ve ever built a trading bot for starts with one indicator then quickly expands to others. They can be technical, fundamental, AI driven, sentiment based or whatever…the point is you’re almost certainly going to want to add more indicators to your trading bot at some point.
As a result, I’m going to show you how to build your very own indicator library
This will help you now and in the future in a few ways:
Let’s start by adding our indicators file. If you’ve already used one of my episodes before, you probably already have this.
If not, add a file called indicators.py
to your trading bot.
The Pandas Python Library is a bit of a game changer for data analysis. There’s entire blogs devoted to it, and I’ve come across it over and over again when developing.
Best of all, it’s super easy to add to your trading bot:
requirements.txt
pandas
pip install -r requirements.txt
Here’s what your requirements.txt
should look like now:
P.S. Don’t forget to check out my dev environment episode if you want to set this up.
Now we’re going to add some routing to your indicator file. This will allow you to easily route your analysis to the right indicator, while also making Python simplify a bunch of features for you.
To do this, add this code to the top of your indicators.py
:
import talib
import pandas
def calc_indicator(indicator_name: str, historical_data: pandas.DataFrame, **kwargs) -> dict:
"""
Function to calculate a specified indicator
:param indicator_name: The name of the indicator to calculate
:param historical_data: The historical data to calculate the indicator from
:param kwargs: Any additional arguments to pass to the indicator function
"""
# Create a return dictionary
return_dictionary = {
"outcome": "unsuccessful",
"indicator": indicator_name,
"values": None,
"indicator_outcome": None
}
# Get the name of the indicator from the indicator name
indicator_name = indicator_name.lower()
# Check for MACD
if indicator_name == "macd":
# Set the indicator to macd in the return dictionary
return_dictionary["indicator"] = "macd"
try:
# Check the kwargs for the MACD fast period, MACD slow period and MACD signal period
macd_fast_period = kwargs["macd_fast_period"]
macd_slow_period = kwargs["macd_slow_period"]
macd_signal_period = kwargs["macd_signal_period"]
# Get the MACD values
macd_data = calc_macd(
historical_data=historical_data,
macd_fast_period=macd_fast_period,
macd_slow_period=macd_slow_period,
macd_signal_period=macd_signal_period
)
# Set the values in the return dictionary
return_dictionary["values"] = macd_data["values"]
# Set the indicator outcome in the return dictionary
return_dictionary["indicator_outcome"] = macd_data["indicator_outcome"]
# Set the outcome to successful
return_dictionary["outcome"] = "successful"
except Exception as exception:
print(f"An exception occurred when calculating the MACD: {exception}")
raise exception
# If the indicator name not recognised, raise a ValueError
else:
raise ValueError(f"The indicator {indicator_name} is not recognised.")
# Return the indicator values
return return_dictionary
Pretty cool, but what did we do here?
If you want to see the routing in action, follow the main trading bot repository as I continue to add more and more indicators!
We’re all set to add the MACD!
Before showing you the code, I’ll quickly outline a few of the design decisions I’ve made for the trading bot.
Default Values:
Of course, the magic of trading bots is you can easily adjust these parameters to meet your specific needs.
I’ve also included some very simple analysis on the MACD:
If you want to learn more about the MACD and why I added this analysis, check out my insightful article on the MACD here.
Add this code to the bottom of your indicators.py
:
# Function to calculate the MACD technical indicator
def calc_macd(historical_data: pandas.DataFrame, macd_fast_period: int=12, macd_slow_period: int=26, macd_signal_period: int=9) -> dict:
"""
Function to calculate the MACD technical indicator
:param historical_data: The historical data to calculate the MACD from
:param macd_fast_period: The MACD fast period
:param macd_slow_period: The MACD slow period
:param macd_signal_period: The MACD signal period
"""
# Create a return dictionary
return_dictionary = {
"outcome": "unsuccessful",
"indicator": "macd",
"values": None,
"indicator_outcome": None
}
# Check that the MACD fast period is greater than 0
if macd_fast_period <= 0:
raise ValueError("The MACD fast period must be greater than 0.")
# Check that the MACD slow period is greater than 0
if macd_slow_period <= 0:
raise ValueError("The MACD slow period must be greater than 0.")
# Check that the MACD signal period is greater than 0
if macd_signal_period <= 0:
raise ValueError("The MACD signal period must be greater than 0.")
# Check that the MACD fast period is less than the MACD slow period
if macd_fast_period >= macd_slow_period:
raise ValueError("The MACD fast period must be less than the MACD slow period.")
# Check that the MACD signal period is less than the MACD slow period
if macd_signal_period >= macd_slow_period:
raise ValueError("The MACD signal period must be less than the MACD slow period.")
# Check that the length of the dataframe is greater than the MACD slow period
if len(historical_data) < macd_slow_period:
raise ValueError("The length of the dataframe must be greater than the MACD slow period.")
try:
# Get the MACD values
macd_values, macd_signal_values, macd_histogram_values = talib.MACD(
historical_data["candle_close"],
fastperiod=macd_fast_period,
slowperiod=macd_slow_period,
signalperiod=macd_signal_period
)
except Exception as exception:
print(f"An exception occurred when calculating the MACD: {exception}")
raise exception
# Add the MACD values to the historical data
historical_data["macd"] = macd_values
# Add the MACD signal values to the historical data
historical_data["macd_signal"] = macd_signal_values
# Add the MACD histogram values to the historical data
historical_data["macd_histogram"] = macd_histogram_values
# Create a column called "macd_indication"
historical_data["macd_indication"] = "hold"
# Set the macd_indication to overbought when the MACD is greater than the MACD signal
historical_data.loc[historical_data["macd"] > historical_data["macd_signal"], "macd_indication"] = "overbought"
# Set the macd_indication to oversold when the MACD is less than the MACD signal
historical_data.loc[historical_data["macd"] < historical_data["macd_signal"], "macd_indication"] = "oversold"
# Get the last row of the historical data and get the MACD indication. Set this to value of indicator_outcome in return_dictionary
return_dictionary["indicator_outcome"] = historical_data["macd_indication"].iloc[-1]
# Add the values to the return dictionary
return_dictionary["values"] = historical_data
# Set the outcome to successful
return_dictionary["outcome"] = "successful"
# Return the dictionary
return return_dictionary
Let’s see the MACD in action!
Head over to your app.py
file, and at the top of the file, add a line import indicators
. This will bring your indicator library into your main script directory.
Next, add the code below:
import alpaca_interactions as alpaca
import datetime
import indicators
# List of symbols
symbols = ["AAPL"]
max_number_of_candles = 5000
timeframe = "1hour"
indicator = "macd"
# Function to run the trading bot
def auto_run_trading_bot():
"""
Function to run the trading bot
"""
# Print Welcome to your very own trading bot
print("Welcome to your very own trading bot")
# Set the end date to yesterday
end_date = datetime.datetime.now() - datetime.timedelta(days=1) # Note that if you have a premium subscription you can remove this restriction
# Set the start date to one year ago
start_date = end_date - datetime.timedelta(days=365)
#### Calculate the an indicator ####
for symbol in symbols:
# Save the symbol text
symbol_text = symbol
# Convert symbol to a list
symbol = [symbol]
# Get the historical data for the symbol
symbol_historical_data = alpaca.get_historic_bars(
symbols=symbol,
timeframe=timeframe,
start_date=start_date,
end_date=end_date,
limit=max_number_of_candles
)
# Calculate the specified indicator
print(f"Calculating the {indicator} for {symbol_text}")
indicator_result = indicators.calc_indicator(
indicator_name=indicator,
historical_data=symbol_historical_data,
macd_fast_period=12,
macd_slow_period=26,
macd_signal_period=9
)
# Branch based on indicator_result
if indicator_result["outcome"] == "successful":
# Print succcess
print(f"The {indicator} was successfully calculated for {symbol_text}")
# Extract the values
values_dataframe = indicator_result["values"]
print(values_dataframe)
else:
# Print and error
print(f"An error occurred when calculating the {indicator} for {symbol_text}")
# Print the full message
print(indicator_result)
# Main function for program
if __name__ == "__main__":
auto_run_trading_bot()
Run your code by pressing the Play ▶️ button in your IDE.
Here’s what mine looked like when I ran it:
Of course, you will get different values as you’re running it at a different time.
If you’re here, then your probably interested in trading bots 🚀
And let’s be honest, there’s tons of MACD related content out there. So I thought I’d take a moment to show you how a trading bot can take this simple little indicator and turbocharge your trading.
Let’s say you wanted to analyze a bunch of different stocks quickly. You could go to a chart and flick through them all.
Or you could modify ONE LINE on this trading bot and push play
Like this:
symbols = ["AAPL", "GOOGL", "META"]
You could do the same thing with the timeframe.
We actually use a very similar approach for the platform we’re building at TradeOxy — except we’ve scaled it tens of thousands of assets at once! Of course, we had to solve a bunch of scaling issues, but the concepts are the same.
Hopefully this article was useful and answered any questions you had. Please subscribe to my stories via email if you’d like more content like this, it really helps me keep growing my audience and platform.
I’m always interested in hearing what’s resonating or not with my audience. If you’ve got an idea, drop me a suggestion in my suggestion box.
I’ll see you on my next episode.
I love hearing from my readers, so feel free to reach out. It means a ton to me when you clap for my articles or drop a friendly comment — it helps me know that my content is helping.
❤