How to Build an Algorithmic Trading Bot with Python

Recent trends in the global stock markets due to the current COVID-19 pandemic have been far from stable…and far from certain. The last time the market was this tumultuous, many people in the US and abroad lost a lot of money. But a few were fortunate enough to put themselves in a position to profit. The current situation will be no different. 

Whether you are a seasoned programmer just getting started with financial trading, or an experienced investor interested in discovering the power of Python, this article is for you. In it, I’ll demonstrate how Python can be used to visualize holdings in your current financial portfolio, as well as how to build a trading bot governed by a simple conditional-based algorithm.

Installing Python for Trading Bots

To follow along with the code in this article, you’ll need to have a recent version of Python installed. I’ll be using a custom build of ActivePython that includes a version of Python and just the packages the project requires. You can get a copy for yourself by doing the following:

  • Download and install the “Trading Bot” runtime by doing the following:
    1. Install the State Tool on Windows using Powershell:
      IEX(New-Object Net.WebClient).downloadString('https://platform.activestate.com/dl/cli/install.ps1')

      Or install State Tool on Linux or Mac:
      sh <(curl -q https://platform.activestate.com/dl/cli/install.sh)
    2. Run the following command to download the build and automatically install it into a virtual environment:
      state activate Pizza-Team/Trading-Bot

You can find all of the code used in this article in my GitLab repository

All set? Let’s dive into the details.

Financial Data for Trading Bots

There are many different stock trading platforms out there, some with their own APIs. Robinhood offers a commision-free investing platform that makes trading simple and easy. Additionally, the robinstocks package extends this simplicity over to Python, supporting features like stock trading, buy/sell options, and purchase cryptocurrencies, as well as giving access to real-time portfolio and market performance.

To follow along with this post, you’ll need to create a Robinhood account. Note that if you’re located outside the US, you’ll need to use another trading platform. In this case, the structure of the trading bot will be the same, but how you execute the trades will be different.

To get started, we’ll first import the packages we need and then log in to the Robinhood platform. Replace the username and password strings with your own account information:

import robin_stocks as r
import pandas as pd
import time

username = 'user@mail.com'
password = 'password'

login = r.login(username,password)

Depending on your security settings, you may require two-factor authentication. Once logged in, you can easily access your holdings by running:

r.build_holdings()

The output is a dictionary that looks something like this:

   {‘KMI’ : {‘price’ : ‘13.990000’,
      ‘quantity’ : ‘1.00000000’,
      ‘average_buy_price’ : ‘0.000’,
      ‘equity’ : ‘13.99’,
      ‘percent_change’ :  ‘0.00’,
      ‘equity_change’ : ‘13.990000’,
      ‘type’ : ‘stock’,
      ‘name’ : ‘Kinder Morgan’,
      ‘id’ : ‘346c3dc3-2ef4-470f-aa67-0471cffeb299’,
      ‘pe_ratio’ : ‘13.939700’,
      ‘percentage’ : ‘100.00’}}

Of course, for bigger portfolios the output will be much longer. You can also access any of your profile information through the profiles module:

r.profiles.load_basic_profile()

There are a few more informative functions that can be used to extract information about your profile. They can be found in the documentation here

Before we get to buying and selling, it is useful to build a visualization tool to observe historical changes in a given stock. The first thing I do is build a visualize_price() function that does exactly that. 

The input is a list of tickers to plot, the time period over which to plot them (can be either day, week, month, 3month, year, or 5year), and whether to include extended trading hours or just regular trading hours (can be extended or regular).

def visualize_price(ticker_list, span = 'year', bounds = 'regular'):   
    for t in range(len(ticker_list)):
        name = str(r.get_name_by_symbol(ticker_list[t]))
        hist = r.stocks.get_historicals(ticker_list[t], span=span, bounds=bounds)
        hist_df = pd.DataFrame()
        for i in range(len(hist)):
            df = pd.DataFrame(hist[i], index = [i])
            hist_df = pd.concat([hist_df,df])
        hist_df.begins_at = pd.to_datetime(hist_df.begins_at, infer_datetime_format=True)
        hist_df.open_price = hist_df.open_price.astype('float32')
        hist_df.close_price = hist_df.close_price.astype('float32')
        hist_df.high_price = hist_df.high_price.astype('float32')
        hist_df.low_price = hist_df.low_price.astype('float32')

        ax = hist_df.plot(x = 'begins_at', y = 'open_price', figsize = (16,8))
        ax.fill_between(hist_df.begins_at, hist_df.low_price, hist_df.high_price, alpha=0.5)
        ax.set_xlabel('Date')
        ax.set_ylabel('Price (USD)')
        ax.legend([ticker_list[t]])
        ax.set_title(name)
    return

You can customize the input ticker list, or use the function below to extract them from your holdings:

def extract_list():
    ticker_list = list(r.build_holdings().keys())
    return ticker_list

To run the functions:

ticker_list = extract_list()
visualize_price(ticker_list, span = 'year', bounds = 'regular')

Since I only have one stock in my holdings, only one plot is given. The plot looks like this:

Stock Chart

In addition to plotting the opening price at each time interval (dark blue line), I’ve included the high and low price over the same time interval (light blue).

Trading Bot Buy/Sell Code

Ideally, the trading bot should look at a predefined set of tickers within the portfolio and decide whether to buy, sell, or hold. The information that the bot uses to make this decision can be anything from how the price changes in a given time period to the sentiment analysis of a tweet from the CEO of the company. 

While there are many factors that can be taken into account, resulting in more sophisticated models for determining the bot conditionals, the base functionality of the bot doesn’t change. In our case, I’m simply using the percent_change attribute for each holding to determine whether or not to buy or sell. If the stock price has a drop over a certain percentage the bot will execute a buy. Conversely, if the stock price has a rise over a certain percentage the bot will execute a sell. To implement this behavior, I’ve defined a trading_bot function: 

def trading_bot(trading_dict):
    holdings = r.build_holdings()
    holdings_df = pd.DataFrame()
    for i in range(len(holdings)):
        ticker = list(holdings.items())[i][0]
        holding_df = pd.DataFrame(list(holdings.items())[i][1], index = [i])
        holding_df['ticker'] = ticker
        holdings_df = pd.concat([holdings_df, holding_df])
    holdings_df = holdings_df[['ticker', 'price', 'quantity', 'percent_change','average_buy_price', 'equity', 'equity_change','pe_ratio', 'type', 'name', 'id' ]]

    for j in range(len(trading_dict)):
        holding_df = holdings_df[holdings_df.ticker == list(trading_dict.keys())[j]]
        if holding_df['percent_change'].astype('float32')[0] <= list(trading_dict.values())[j][0]:
            buy_string = 'Buying ' + str(holding_df['ticker'][0]) + ' at ' + time.ctime()
            print(buy_string)
            r.orders.order_buy_market(holding_df['ticker'][0],1,timeInForce= 'gfd')
        else:
            print('Nothing to buy')

        if holding_df['percent_change'].astype('float32')[0] >= list(trading_dict.values())[j][1]:
            sell_string = 'Buying ' + str(holding_df['ticker'][0]) + ' at ' + time.ctime()
            print(sell_string)
            r.orders.order_sell_market(holding_df['ticker'][0],1,timeInForce= 'gfd')
        else:
            print('Nothing to sell')  

First, the bot pulls the holdings from the Robinhood platform and does some restructuring of the data to create a pandas dataframe. Then, it loops through each ticker present in trading_dict and compares the percent_change value to the buy and sell conditional limits. For example, I can set both limits to 0.5%:

trading_dict = {'KMI': [-0.50, 0.50]}
holdings_df = trading_bot(trading_dict)

The bot will then execute a buy or sell if the percent_change value is less than or greater than half a percent, and prints out the transaction for each holding. Pretty cool right?

That’s it! You can now build your own trading bot using Python

In this article, I demonstrated how Python can be used to build a simple trading bot using packages like pandas and robin-stocks. By taking advantage of the Robinhood trading platform, you can easily visualize the performance of individual holdings within your portfolio. 

The buy and sell conditions we set for the bot are relatively simplistic, but this code provides the building blocks for creating a more sophisticated algorithm. The versatility of Python offers the perfect playground for increasing the complexity by, for example, introducing machine learning techniques and other financial metrics. I leave these next steps to those readers interested in creating a more advanced bot. 

Related Blogs:

ActiveState Platform: How to Build a Custom Runtime in 5 minutes?

How to Build a Blockchain in Python (Get Pre-built Runtime)

Top 10 Python Packages for Finance and Financial Modeling

Dante Sblendorio

Dante Sblendorio

Guest blogger: Dante is a physicist currently pursuing a PhD in Physics at École polytechnique fédérale de Lausanne. He has a Masters in Data Science, and continues to experiment with and find novel applications for machine learning algorithms. He lives in Lausanne, Switzerland.