The discount brokerage space is getting very competitive with commissions going to zero recently at many brokerages, including Interactive Brokers. IB has long been a broker with one of the largest breadth of products and service offerings targeting a professional audience. It is also a low cost brokerage making it an excellent option for the amateur investor or those wanting to try their hand at algorithmic or systematic trading. In this post I hope to cover the basics of connecting to Interactive Brokers via Python to get the latest market data for an instrument.
IB offers a set of application programming interfaces (APIs) to their data and services, available for Java, .NET (C#), C++, Python, or DDE, using their Trader Workstation Application Programming Interface (TWS API). This is not a modern web-based REST API, but rather a proprietary API that connects to a local server running on your hardware which then connects to IB servers over your internet connection. You can run either the full Trader Workstation GUI (TWS), or a slightly smaller Gateway that is only used for API access. I’ll focus on using TWS here.
This has a few obvious drawbacks:
- You need to learn a new unique API to get things done. If you’re familiar with REST APIs, this will be a bit different.
- There is an extra piece of software that runs between your code and the market, introducing some latency.
- You have to authenticate to the API using a GUI, so headless environments aren’t explicitly supported (though there are some workarounds available).
Life isn’t all bad though, because the API is fairly well documented and quite complete. The advantage of having a fully built GUI is that you can try things there first and then search through the API to find the corresponding calls needed to perform the transactions. It’s a good way to slowly build up and automate a trade.
Here are the basic steps to get up and running with Interactive Brokers. The example I’ll use is for an individual, non-professional regular account. You could also open an Individual Retirement Account (IRA). At the time of writing, IB offers two main options for individuals: IBKR Pro and IBKR Lite. IBKR Lite offers zero commission stock trades, but no API access is currently allowed, so to complete this tutorial you’ll need the Pro option. It appears IB will be making changes to these programs going forward, and they do allow you to switch your account back and forth between the options so there’s not much harm in choosing Pro to begin with if they decide to offer API access with Lite in the future.
Setup account
First, from the main IB web page, follow the instructions to open an account. You’ll need to fill out a pretty standard brokerage application and then fund your account. IB changes the minimum balance required from time to time, so the amount you need to deposit could change depending on when you get started. Once you have an account, they will give you a unique username and you can set your password.
Download TWS software
After setting up your account on their website, I recommend downloading the phone based IB software and setting up two factor authentication available under User Settings, Secure Login System. This will require you to authenticate via your phone whenever authenticating to the IB servers or web site.
Next, download the current version of the TWS software (this was 978.1 at time of writing). This is available right of the IB home page, under Technology, Platforms. Download the latest software, not the stable version. You can always change the version you are running by selecting a different version in the login screen once you have the software running.
Finally, download the API software from the IB GitHub account. The software package will include the C++, C#, and Python APIs and example code.
Subscribe to market data
Since this example will show you “real time” ticks, you will need to subscribe to market data. IB is willing to show you delayed data (15 minutes for US Stocks, for example) and historical data in the TWS GUI, but if you want to access data using the API, you will require a market data subscription. For the purposes of this tutorial, you could choose to subscribe to only one exchange for US stocks, such as NASDAQ, for $1.50/month at time of writing. IB also offers bundles if you would like to access a wider universe of products.
Configure TWS for API access
There is plenty of detail on how to configure TWS in the IB docs, but I’ll summarize the main points here. Once you have TWS running, you need to configure API access in the settings. This is under File, Global Configuration, API, Settings. You need to check the “Enable ActiveX and Socket Clients” at a minimum, and take note of the Socket Port in the configuration since we’ll need that later. If you are running a local firewall, you need to ensure this socket can be accessed by local software. You can also add “127.0.0.1” to the trusted IPs list if you don’t want to have to approve the API connection manually. For safety, you should not open this socket to the world, keep the “Allow connections from localhost only” box checked.
Setup the python environment
I recommend using pyenv for creating a virtual environment and isolating the Python version you use for development. Note that IB’s API requires Python 3, so make sure you use a modern version. For this example, I used Python 3.7.5. If you have another method you prefer, go ahead and setup the environment to install the IB API.
pyenv virtualenv 3.7.5 ib-example
pyenv activate ib-example
# also install wheel for build step in the following section
pip install wheel
Now navigate to the Python directory where you placed the IB API download from earlier and build and install the package (I placed the unzipped archive in my projects directory). Note that the README.md file distributed with the code has more complete instructions but may not have the correct version listed in the commands, so you may need to peek in the dist directory after building to see the wheel file name. I also did the pip install without the –user option since I want it installed in my virtualenv.
cd ~/projects/twsapi\_macunix/IBJts/source/pythonclient/
python setup.py bdist\_wheel
# note the version may be different for you with later downloads...
python -m pip install --upgrade dist/ibapi-9.76.1-py3-none-any.whl
Write the application
I’ve created a simple command line application that demonstrates how to use the IB APIs. Most of this is taken from the example IBJts/samples/Python/Testbed/Program.py
that is distributed with the IB source code. Any program that interacts with the TWS server needs to implement two interfaces. The first is EWrapper
that implements all the callbacks to handle any data messages sent to your client. The second is EClient
, which allows you to connect and send messages to TWS. I implement both of these in one class.
class MarketDataApp(EClient, wrapper.EWrapper):
def __init__(self, contracts: ContractList, args: argparse.Namespace):
EClient.__init__(self, wrapper=self)
wrapper.EWrapper.__init__(self)
This class also needs to implement a few methods in order to establish a connection and begin processing messages. The documentation states that the API is not ready until the client has received the next valid order number in the nextValidId
callback. You receive messages in methods that are decorated with the @iswrapper
decorator.
@iswrapper
def connectAck(self):
logging.info("Connected")
@iswrapper
def nextValidId(self, orderId: int):
logging.info(f"Next valid order id: {orderId}")
self.start()
You also implement a start
method in the class that you invoke once you know the API is ready. In that method you can invoke any of the IB APIs. In my case I will make requests for market data for a list of Contracts that were provided on the command line.
def start(self):
if self.started:
return
self.started = True
for contract in self.contracts:
rid = self.next_request_id()
self.reqMktData(rid, contract, "233", self.args.snapshot, False, [])
self.pending_ends.add(rid)
self.request_contracts[rid] = contract
Now, in your main method, create an instance of your class and invoke the run
method to get things started.
app = MarketDataApp(contracts, args)
app.connect("127.0.0.1", args.port, clientId=0)
app.run()
I’ve uploaded the full example as a Gist on GitHub. You should be able to complete the above steps and run the application in your virtualenv and see tick data in your console. Since the application has INFO logging enabled, you should also see info about all of the API requests being made by the app, along with some messages logged at ERROR that indicate the status of the IB servers. And if everything worked correctly, you will see individual messages for each market update. To exit, just hit Ctrl-C a few times to break the event loop.
$ python get_ticks.py AAPL
INFO:ibapi.client:sent startApi
INFO:ibapi.client:REQUEST startApi {}
<messages omitted>
ERROR:ibapi.wrapper:ERROR -1 2104 Market data farm connection is OK:usfarm.nj
<messages omitted>
1 LAST price: 317.95 CanAutoExecute: 0, PastLimit: 0, PreOpen: 0
1 LAST_SIZE size: 4
1 BID_SIZE size: 1
1 ASK_SIZE size: 2
1 LAST_SIZE size: 4
One other item of note, the streaming market data requested here is not a tick-by-tick data stream, but a snapshot posted every 250ms. This delay differs by product type. To get tick-by-tick data, you’d use the reqTickByTickData
API.
From here, you can build anything you want that is available in the IB APIs. Take a look at their example code, there are plenty of examples to get you started.
Top comments (0)