Step-by-Step Guide to Adding the MACD to Your Python Trading Bot
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.
About This Episode
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.
What You’ll Need to Complete this Episode
- 20-minutes. All up, including writing and testing the code, you’ll only need about 20 minutes to complete this episode.
- Basic knowledge of Python. I try to make sure all my content can be used by beginners right through to experts. You do need to have a basic knowledge of Python to complete this episode (or if you’re just starting out, it may take you a bit longer to complete)
- Python development environment. You need somewhere to develop and test your trading bot. I use the AI powered development environment which is completely free (at the time of writing) in this episode, so check it out if you feel that will help.
- Market data. You need data to analyze. I’ve got some great content that shows you how to get this data completely free if you need to implement this.
Learning Experience Excellence
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:
- Complete code repository. All the code I share can be found in a working GitHub.
- Discord help. Got a question not answered in the article? Ask it on our community Discord!
- YouTube. If you prefer YouTube content for learning, you can follow my channel to stay up to date.
Legal Stuff
- DYOR. Note that all trading is at your own risk. My goal is to provide you with the self-developed methods, systems, and tools I use — it is up to you to figure out if this solution works for you AND if I’ve provided credible content. Always DYOR (Do Your Own Research).
- Not Financial Advice. At no point should you consider anything in these articles to be financial advice. Any opinions expressed are about the technical aspects of the topic, not financial suitability.
- Referrals. I receive no commissions for any of the products I mention in this blog. They’re all free (or have a free tier), and I simply provide links to simplify your learning experience.
- AI Use. No AI was harmed in the creation of this blog. Some of the images are partially generated or enhanced through AI tools, we always use a real human to put them together. I do not use AI to generate the text, just spell check.
Create Your Own Indicator Library
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:
- Add indicator once, use forever. You’ll only ever need to add the indicator to your trading bot dev environment once, then you can use it whenever you’re building a trading bot.
- Simplify additive indicator analysis. Once an indicator is built, adding as many indicators as you want to your trading bot will be as simple as a couple of lines of code.
- Make Python work for you. Unleash the power of automated trading on your trading bot.
Create indicators.py
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.
Add the Python Pandas Library
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:
- Go to your
requirements.txt
- At the bottom, add the text
pandas
- Save
- Run the command
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.
Indicator Routing
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?
- We created a parent routing function
- We used the **kwargs python function to allow us to pass specific parameters to the trading bot
- We included some helpful error handling
If you want to see the routing in action, follow the main trading bot repository as I continue to add more and more indicators!
Add the MACD to Your Trading Bot
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:
- MACD Fast Period. 12
- MACD Slow Period. 26
- MACD Signal Period. 9
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:
- Overbought. When the MACD line is above the MACD Signal.
- Oversold. When the MACD is below the MACD signal
If you want to learn more about the MACD and why I added this analysis, check out my insightful article on the MACD here.
MACD Indicator Code
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
See the MACD In Action on Your Trading Bot
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.
How a Trading Bot Turbocharges Your Trading
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.
Quick Plug for TradeOxy
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.
Wrapping Up!
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.
Say Hi!
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.
❤