img

Step-by-Step Guide to Adding the RSI to Your Stock Trading Bot using Python and Alpaca Markets

img
valuezone 13 March 2024

Step-by-Step Guide to Adding the RSI to Your Stock Trading Bot using Python and Alpaca Markets

The Relative Strength Index (RSI) is one of the world's most popular technical indicators. Most trading platforms offer the RSI and various strategies connected to it.

Adding the RSI to your trading bot allows your autotrading bot to integrate this powerful indicator into your trading strategies.

In this episode, I’m going to show you how to do it.

Set Up for Indicators

As part of my development environment setup story, I showed you the easiest way to setup TA Lib. Now we’re going to start building an indicator library for you to use in your trading bots.

Create indicators.py

In your trading bot dev environment, create a file called indicators.py

This little file is a bit of a game changer for trading bot development. Moving forward, every time you want to add a new indicator to your trading bot, you’ll be able to drop it here. Before long, you’ll be adding 3, 4, or more indicators to your trading bot. You might even add some custom ones!

This is the exact same approach we use to build trading bots for our customers at TradeOxy.

Add the Pandas Library

The Pandas Python Library has entered legend status in the Python Programming Language. It’s an incredibly powerful-yet-simple library to use, with a plug in to interface with just about any system you’ve ever imagined.

If you’re thinking, “Oh no, I bet this is really hard to install🥲” then cheer up. Panda’s is super simple to install and use.

To do so, head to your requirements.txt and add the following line:

pandas

That’s it.

If you’ve been following my blog series, your requirements.txt should now look like this:


Requirements.txt with the addition of Pandas. Part of the AppnologyJames Blog Post: Step-by-Step Guide to Adding the RSI to Your Stock Trading Bot using Python and Alpaca Markets.

Quickly run the command pip install -r requirements.txt to update your development environment.

Done.

Add Indicator Routing

Let’s add some routing to the indicator library. This will make it easy for you to keep adding indicators, while leveraging some of the features of Python to make the function dynamic.

Add this code to your indicators.py file.

# Part of the article: "Step-by-step Guide to Adding the RSI to Your Stock Trading Bot using Python and Alpaca Markets" on Medium by AppnologyJames
# URL to access article: https://appnologyjames.medium.com/step-by-step-guide-to-adding-the-rsi-to-your-stock-trading-bot-using-python-and-alpaca-markets-72473d052dff
# Main GitHub Repo: https://github.com/jimtin/something-cool/blob/main/README.md
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 RSI
if indicator_name == "rsi":
# Set the indicator to rsi in the return dictionary
return_dictionary["indicator"] = "rsi"
try:
# Check the kwargs for the RSI period, rsi high and rsi low
rsi_period = kwargs["rsi_period"]
rsi_high = kwargs["rsi_high"]
rsi_low = kwargs["rsi_low"]
# Get the RSI values
rsi_data = calc_rsi(
historical_data=historical_data,
rsi_period=rsi_period,
rsi_high=rsi_high,
rsi_low=rsi_low
)
# Set the values in the return dictionary
return_dictionary["values"] = rsi_data["values"]
# Set the indicator outcome in the return dictionary
return_dictionary["indicator_outcome"] = rsi_data["indicator_outcome"]
# Set the outcome to successful
return_dictionary["outcome"] = "calculated"
except Exception as exception:
print(f"An exception occurred when calculating the RSI: {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
view rawindicators.py hosted with ❤ by GitHub

There’s a few pretty cool things happening here:

  1. We can route the indicator selection just by using the name of the indicator
  2. We can define the historic data we’ll be passing to our indicator
  3. We can add additional arguments. For instance, on the RSI, we want to be able to define the RSI period, RSI High value, and RSI Low value

By the way, if you’d like to learn more about the RSI and why we might want to define those values, check out this article.

For the more advanced programmers out there, you’ll also notice that I’ve typed the inputs to the function and clearly defined a dictionary return. This will drastically simplify your development life moving forward!

Add RSI to Indicators Library

Now we need to add the RSI calculation to the indicator library. There’s a few things we need to consider to do this:

  1. Define default values for the RSI
  2. Catch any obvious issues with the RSI

The default values I’ll be using for the RSI are:

  • RSI High: 70
  • RSI Low: 30
  • RSI Period: 14

You can of course change them to whatever you’d like!

Add this code to the bottom of your indicators.py

# Part of the article: "Step-by-step Guide to Adding the RSI to Your Stock Trading Bot using Python and Alpaca Markets" on Medium by AppnologyJames
# URL to access article: https://appnologyjames.medium.com/step-by-step-guide-to-adding-the-rsi-to-your-stock-trading-bot-using-python-and-alpaca-markets-72473d052dff
# Main GitHub Repo: https://github.com/jimtin/something-cool/blob/main/README.md
# Function to calculate the RSI
def calc_rsi(historical_data: pandas.DataFrame, rsi_period: int=14, rsi_high: int=70, rsi_low: int=30) -> dict:
"""
Function to calculate the RSI
:param historical_data: The historical data to calculate the RSI from
:param kwargs: Any additional arguments to pass to the RSI function
"""
# Create a return dictionary
return_dictionary = {
"outcome": "unsuccessful",
"indicator": "rsi",
"values": None,
"indicator_outcome": None
}
# Check that the RSI period is greater than 0
if rsi_period <= 0:
raise ValueError("The RSI period must be greater than 0.")
# Check that the length of the dataframe is greater than the RSI period
if len(historical_data) < rsi_period:
raise ValueError("The length of the dataframe must be greater than the RSI period.")
try:
# Get the RSI values
rsi_values = talib.RSI(historical_data["close"], timeperiod=rsi_period)
except Exception as exception:
print(f"An exception occurred when calculating the RSI: {exception}")
raise exception
# Add the RSI values to the historical data
historical_data["rsi"] = rsi_values
# Set the outcome to successful
return_dictionary["outcome"] = "calculated"
# Create a new column called rsi_signal and set the value to hold
historical_data["rsi_signal"] = "hold"
# Set the rsi_signal to oversold when the RSI is less than 30
historical_data.loc[historical_data["rsi"] < rsi_low, "rsi_signal"] = "oversold"
# Set the rsi_signal to overbought when the RSI is greater than 70
historical_data.loc[historical_data["rsi"] > rsi_high, "rsi_signal"] = "overbought"
# Get the last row of the historical data and get the RSI signal. Set this to value of indicator_outcome in return_dictionary
return_dictionary["indicator_outcome"] = historical_data["rsi_signal"].iloc[-1]
# Return the dictionary
return return_dictionary

view rawindicators.py hosted with ❤ by GitHub

Nice work. You’ve just added the RSI!

See The RSI In Action on Your Trading Bot!

Let’s update your app.py file so you can see the RSI in action on the stock(s) of your choice.

Start by adding a new import to the top of your file: import indicators

This tells your main program to use the indicators library we’ve just created in the trading bot.

Next, update your auto_run_trading_bot function so that it looks like this:

# Part of the article: "Step-by-step Guide to Adding the RSI to Your Stock Trading Bot using Python and Alpaca Markets" on Medium by AppnologyJames
# URL to access article: https://appnologyjames.medium.com/step-by-step-guide-to-adding-the-rsi-to-your-stock-trading-bot-using-python-and-alpaca-markets-72473d052dff
# Main GitHub Repo: https://github.com/jimtin/something-cool/blob/main/README.md
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 RSI ####
for symbol in symbols:
# 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 RSI for the symbol
rsi_data = indicators.calc_indicator(
indicator_name="rsi",
historical_data=symbol_historical_data,
rsi_period=14,
rsi_high=70,
rsi_low=30
)
# Print the RSI data
print(rsi_data)
view rawapp.py hosted with ❤ by GitHub

Now, if you hit ▶️ you should see something similar to the following:


Output when I run the trading bot with the current setup. Part of the AppnologyJames Blog Post: Step-by-Step Guide to Adding the RSI to Your Stock Trading Bot using Python and Alpaca Markets.

Your values will be different than mine as you are doing this at a different time to me.

See the True Power of A Trading Bot at Work!

It’s here we can see the true power of a trading bot at work. Using the variables for symbols and timeframe from previous episodes, you can analyze huge swathes of the market all at once.

For instance, keen on looking at Apple, Google, and Meta? Change the following line and rerun:

symbols = ["AAPL", "GOOGL", "META"]

What if you want to change the timeframe? Change the following line and rerun:

timeframe = "1hour"

Boom.