Using Python, IBPy and the Interactive Brokers API to Automate Trades

A while back we discussed how to set up an Interactive Brokers demo account. Interactive Brokers is one of the main brokerages used by retail algorithmic traders due to its relatively low minimal account balance requirements (10,000 USD) and (relatively) straightforward API. In this article we will make use of a demo account to automate trades against the Interactive Brokers API, via Python and the IBPy plugin.

Disclosure: I have no affiliation with Interactive Brokers. I have used them before in a professional fund context and as such am familiar with their software.

The Interactive Brokers API

Interactive Brokers is a large enterprise and as such caters to a wide-range of traders, ranging from discretionary retail to automated institutional. This has led their GUI interface, Trader Workstation (TWS), to possess a significant quantity of "bells and whistles".

In addition to TWS there is also a lightweight component called the IB Gateway, which provides the same access to the IB servers, albeit without the extra functionality of the GUI. For our automated trading purposes we won't actually need the TWS GUI, but I think for this tutorial it is demonstrative to make use of it.

The underlying architecture is based on a client/server model which offers both execution and market data feeds (historical and real-time) via an API. It is this API that we will utilise in this tutorial to send automated orders, via IBPy.

IBPy has been written to "wrap" the native Java API and make it straightforward to call from Python. The two main libraries we are interested in within IBPy are ib.ext and ib.opt. The latter is higher level and makes use of functionality in the former.

In the following implementation we are going to create an extremely simple example, which will simply send a single market order to buy 100 units of Google stock, using smart order routing. The latter is designed to achieve the best price in practice, although in certain situations it can be suboptimal. However for the purposes of this tutorial it will suffice.

Implementation in Python

Before we begin it is necessary to have followed the steps in the prior tutorial on setting up an Interactive Brokers account. In addition it is necessary to have a prior Python workspace so that we can install IBPy, which will allow you to tie other aspects of your code together. The tutorial on installing a Python research environment will create the necessary workspace.

Installing IBPy

IBPy is a Python wrapper written around the Java-based Interactive Brokers API. It makes development of algorithmic trading systems in Python somewhat less problematic. It will be used as the basis for all subsequent communication with Interactive Brokers until we consider the FIX protocol at a later date.

Since IBPy is maintained on GitHub as a git repository we will need to install git. On a Ubuntu system this is handled by:

sudo apt-get install git-core

Once you have git installed you can create a subdirectory to store IBPy. On my system I have simply placed it underneath my home directory:

mkdir ~/ibapi

The next step is to download IBPy via git clone:

cd ~/ibapi
git clone https://github.com/blampe/IbPy

Make sure to enter the IbPy directory and install with the preferred Python virtual environment:

cd ~/ibapi/IbPy
python setup.py.in install

That completes the installation of IBPy. The next step is to open up TWS (as described in the prior tutorial).

TWS Portfolio View (Prior to Google Trade)
TWS Portfolio View (Prior to Google Trade)

Automated Trading

The following code will demonstrate an extremely simple API-based order mechanism. The code is far from production-ready but it does demonstrate the essential functionality of the Interactive Brokers API and how to use it for order execution.

All of the following code should reside in the ib_api_demo.py file. The first step is to import the Contract and Order objects from the lower level ib.ext library. In addition we import the Connection and message objects from the ib.opt higher level library:

# ib_api_demo.py

from ib.ext.Contract import Contract
from ib.ext.Order import Order
from ib.opt import Connection, message

IB provides us with the capability of handling errors and server responses by a callback mechanism. The following two functions do nothing more than print out the contents of the messages returned from the server. A more sophisticated production system would have to implement logic to ensure continual running of the system in the event of exceptional behaviour:

# ib_api_demo.py

def error_handler(msg):
    """Handles the capturing of error messages"""
    print "Server Error: %s" % msg

def reply_handler(msg):
    """Handles of server replies"""
    print "Server Response: %s, %s" % (msg.typeName, msg)

The following two functions wrap the creation of the Contract and Order objects, setting their respective parameters. The function docs describe each parameter individually:

# ib_api_demo.py

def create_contract(symbol, sec_type, exch, prim_exch, curr):
    """Create a Contract object defining what will
    be purchased, at which exchange and in which currency.

    symbol - The ticker symbol for the contract
    sec_type - The security type for the contract ('STK' is 'stock')
    exch - The exchange to carry out the contract on
    prim_exch - The primary exchange to carry out the contract on
    curr - The currency in which to purchase the contract"""
    contract = Contract()
    contract.m_symbol = symbol
    contract.m_secType = sec_type
    contract.m_exchange = exch
    contract.m_primaryExch = prim_exch
    contract.m_currency = curr
    return contract

def create_order(order_type, quantity, action):
    """Create an Order object (Market/Limit) to go long/short.

    order_type - 'MKT', 'LMT' for Market or Limit orders
    quantity - Integral number of assets to order
    action - 'BUY' or 'SELL'"""
    order = Order()
    order.m_orderType = order_type
    order.m_totalQuantity = quantity
    order.m_action = action
    return order

The __main__ function initially creates a Connection object to Trader Workstation, which must be running for the code to function. The error and reply handler functions are then registered with the connection object. Subsequently an order_id variable is defined. In a production system this must be incremented for each trade order.

The next steps are to create a Contract and an Order representing a market order to buy 100 units of Google stock. The final task is to actually place that order via the placeOrder method of the Connection object. We then disconnect from TWS:

# ib_api_demo.py

if __name__ == "__main__":
    # Connect to the Trader Workstation (TWS) running on the
    # usual port of 7496, with a clientId of 100
    # (The clientId is chosen by us and we will need 
    # separate IDs for both the execution connection and
    # market data connection)
    tws_conn = Connection.create(port=7496, clientId=100)
    tws_conn.connect()

    # Assign the error handling function defined above
    # to the TWS connection
    tws_conn.register(error_handler, 'Error')

    # Assign all of the server reply messages to the
    # reply_handler function defined above
    tws_conn.registerAll(reply_handler)

    # Create an order ID which is 'global' for this session. This
    # will need incrementing once new orders are submitted.
    order_id = 1

    # Create a contract in GOOG stock via SMART order routing
    goog_contract = create_contract('GOOG', 'STK', 'SMART', 'SMART', 'USD')

    # Go long 100 shares of Google
    goog_order = create_order('MKT', 100, 'BUY')

    # Use the connection to the send the order to IB
    tws_conn.placeOrder(order_id, goog_contract, goog_order)

    # Disconnect from TWS
    tws_conn.disconnect()

The final step is to run the code:

python ib_api_demo.py

Immediately it can be seen that the API tab opens up in Trader Workstation, showing the market order to go long 100 shares of Google:

TWS API Tab view after Google order
TWS API Tab view after Google order

If we now look at the Portfolio tab we can see the Google position. You will also note a forex position in the list, which was not generated by myself! I can only assume that either the IB demo account is "shared" in some fashion (due to the identical login information) or IB places arbitrary orders into the account to make it appear more "realistic". If anybody has any insight into this behaviour I would be intrigued to learn more:

TWS API Portfolio view subsequent to Google order
TWS API Portfolio view subsequent to Google order

This is the most basic form of automated execution that we could consider. In subsequent articles we are going to construct a more robust event-driven architecture that can handle realistic trading strategies.

comments powered by Disqus

Just Getting Started with Quantitative Trading?

3 Reasons to Subscribe to the QuantStart Email List:

No Thanks, I'll Pass For Now

1. Quant Trading Lessons

You'll get instant access to a free 10-part email course packed with hints and tips to help you get started in quantitative trading!

2. All The Latest Content

Every week I'll send you a wrap of all activity on QuantStart so you'll never miss a post again.

3. No Spam

Real, actionable quant trading tips with no nonsense.