9 min read

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.
Step-by-Step Guide to Adding the MACD to Your Python Trading Bot
Title Image for Build Your Own Trading Bot. Part of the Medium article, “Step-by-Step Guide to Adding the MACD to Your Python Trading Bot” by AppnologyJames

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.
  • 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:
  1. 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.
  2. 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.
  3. 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:

  1. Go to your requirements.txt
  2. At the bottom, add the text pandas
  3. Save
  4. Run the command pip install -r requirements.txt

Here’s what your requirements.txt should look like now:

Requirements.txt with Pandas added. Part of the Medium article, “Step-by-Step Guide to Adding the MACD to Your Python Trading Bot” by AppnologyJames.

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?

  1. We created a parent routing function
  2. We used the **kwargs python function to allow us to pass specific parameters to the trading bot
  3. 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:

  1. MACD Fast Period. 12
  2. MACD Slow Period. 26
  3. 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:

  1. Overbought. When the MACD line is above the MACD Signal.
  2. 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.