Getting Started with the Interactive Brokers Native API

    Date:

    The article “Getting Started with the Interactive Brokers Native API” first appeared on Robot Wealth blog.

    Here at Robot Wealth, we trade with Interactive Brokers (IB) primarily because they offer access to global markets at a reasonable price.

    In recent times, IB has put some time and effort into upping its tech game, including development of an API for interacting with its desktop trading applications.

    An application that interacts with IB’s desktop trading applications via the API is essentially a message-handling program. So I want to show you a simple but effective architecture for managing the flow of messages and the operations they trigger. If you can understand this framework, then you can basically design any application you can think of.

    Before we get to that, I’ll show you how to get started with the IB API – how it works, how to configure it, and options available for using it.

    Then I’ll show you a Hello World example, and in later articles, I’ll go through some more interesting and complex use cases.

    The IB API is (kind of) different

    The IB API is essentially a message protocol for communicating with the IB desktop trading platforms – Trader Workstation (TWS) and Gateway (GW).

    If you think about this in terms of the normal client-server framework, your trading code is essentially the “client” and TWS is the “server”, and they communicate using the IB API. TWS acts as an intermediary to IB’s actual servers, and the API provides an interface to TWS.

    The most obvious implication is that you need to have TWS or GW running in order to use the API.

    This means that you also need to deal with restarts.

    Dealing with restarts

    TWS and GW were designed to be restarted daily (for example to re-download contract definitions where contracts have been changed or new contracts added). However, they have an auto-restart feature that restarts the application daily without user intervention. With this option enabled, the application can run for up to a week without re-authenticating. However, after the nightly server reset on Saturday night (US), you will have to re-authenticate.

    Of course, if you’re trading, you’ll be checking on the platform constantly, but it’s nice not to have to re-authenticate every time it restarts.

    To set that option in TWS, from the File menu, choose Global Configuration:

    Then, from the Configuration menu, choose “Lock and Exit”. Check the “Auto restart” button, uncheck the “Auto log off” button, and set the time you’d like to have the application restart:

    The restart time is in the time zone you have set for TWS. You can see TWS’ current time in the top right hand corner:

    If you need to change the time zone, you’ll need to log out, and from the log in screen choose “More options”. You can then change your time zone:

    Using the IB API

    You have a few options for working with the IB API. You can either use an existing wrapper such as ib_insync, or work with the native API.

    The advantage of something like ib_insync is that all of the “plumbing” code is done for you – in particular, it’s a fully asynchronous framework which handles messages to and from TWS.

    The native API is a bit more complex to work with, and you’ll have to figure out how to handle messages yourself (async, threading, etc). On the other hand, the native API is officially supported by IB (ib_insync is third-party software, although at the moment is actively maintained), and it removes any limitations on customisation.

    In this series, we’ll use the native API.

    Installing the native IB API

    The first step is installing the native API.

    Grab the software installer for your operating system from IB’s github pages. Run the installer and follow the prompts.

    You’ll also need Python – Miniconda provides a good, minimal installation, but use whatever you normally work with.

    Once the API software is installed, navigate to the installation directory (on Windows, usually C:TWS API). Then drill down to the pythonclient directory and run the setup.py file with the install parameter:

    Once the installation completes, verify that it worked by doing python -m pip show ibapi to show the latest installed version:

    Configuring TWS to use the API

    Next we need to configure TWS.

    Enable logging

    TWS can be configured to write a separate log file that documents communication via the API. This will make debugging a whole lot simpler, so enable it in TWS as follows:

    From the File menu, select “Global Configuration”. Then, select “API” –> “Settings” and check the box for “Create API message file”:

    TWS logs are encrypted. To read them, you’ll need to export them from TWS as follows:

    From the Help menu, select “Troubleshooting” –> “Diagnostics” –> “API Log Files”:

    You can then select the logs you want to export.

    See here for more detailed information about the TWS log files.

    Configuration settings

    You’ll also need to configure the following settings in TWS:

    From the File menu, select “Global Configuration” –> “API” –> “Settings”. Then, make the following changes:

    • Check the box for “Enable ActiveX and Socket Clients”
    • Designate a socket port – 7496 is the default
    • Check the box for “Allow connections from localhost only” – this will allow connections only from applications running on the same machine as TWS.

    If you want to have multiple TWS instances running on the same machine, you can configure each with a different API socket port number.

    You may wish to connect to TWS remotely. In that case, uncheck “Allow connections from localhost only” and add the relevant IP addresses to “Trusted IPs”. If you don’t add these IPs, you’ll have to manually authenticate each connection from a pop-up box in TWS (which kind of defeats the purpose of remote access).

    Understanding the messaging framework

    A Python client application using the IB API requires two threads of execution:

    • One for messages sent from TWS to the client application. This uses the IBAPI.Ewrapper interface, which you can use out of the box or override depending on how you want to handle these messages.
    • One for messages sent from the client application to TWS. This uses the IBAPI.EClientSocket class, which you inherit from, and include your IBApi.EWrapper in the constructor parameters (so that the application can handle all the messages coming from TWS).

    The base class Ewrapper defines and implements functions for handling messages from TWS by simply logging them. You may wish to inherit from this class and override the methods depending on how you want to handle these messages.

    In the Python implementation of EClient, messages are processed using a Queue. This happens in an endless loop in Eclient.run. In other languages, you need a third thread of execution to handle this.

    Let’s make this a bit more real with a Hello World example.

    Hello World

    In this example, we’ll connect to TWS, request our account information, and print it to screen.

    Before writing any code, it’s always worth thinking about the architecture of an IB API application, which is inherently a message-handling program.

    Remember that we handle our messages to and from TWS in separate threads, so ideally we would have some way of signalling between threads when a message has been received or processed.

    To do this, we’ll use threading.Event, which is a simple way to control the flow of a program hat involves asynchronous operations and multiple threads.

    threading.Event manages an internal flag that can be set to True with the set() method and reset to False with the clear() method. Other threads can wait for this flag to be set by calling the wait() method, which blocks until the flag becomes True.

    This mechanism is particularly useful for signaling between threads, allowing one thread to signal another that an event has occurred or a condition has been met – which is exactly what we need to do with our TWS messaging application.

    We’ll use the Eclient.reqAccountSummary method to request our account information. If you look at the documentation for this function, you’ll also find the Ewrapper methods that we need to override in order to handle the messages coming back from TWS.

    We also use the following methods from Eclient:

    • connect – initiates a connection with TWS and triggers the Ewrapper.nextValidId callback once established. We’ll use a threading.Event to signal when this callback is triggered and our connection is established (messages sent while the connection is being established can be lost).
    • disconnect – terminates the connection with TWS (but doesn’t cancel in-flight orders), good practice to include this at the completion of your script.
    • run – processes the message queue in an infinite loop while connected.

    Here’s the script for connecting to TWS, requesting our account information, and printing it to screen. I’ve heavily commented it so that you can follow what’s going on if you’re new to this.

    # %load ibkr-api/account_summary.py
    from threading import Thread, Event
    import time
    from typing import Any
    from ibapi.wrapper import EWrapper
    from ibapi.client import EClient
    from ibapi.common import *
    from ibapi.account_summary_tags import AccountSummaryTags
    
    
    class ibapp(EClient, EWrapper):
        def __init__(self):
            EClient.__init__(self, self)
            self.done = Event()  # use threading.Event to signal between threads
            self.connection_ready = Event()  # to signal the connection has been established
    
        # override Ewrapper.error
        def error(
            self, reqId: TickerId, errorCode: int, errorString: str, contract: Any = None
        ):
            print("Error: ", reqId, " ", errorCode, " ", errorString)
            if errorCode == 502:  # not connected
                # set self.done (a threading.Event) to True
                self.done.set()
    
        # override Ewrapper.accountSummary - method for receiving account summary
        def accountSummary(
            self, reqId: int, account: str, tag: str, value: str, currency: str
        ):
            # just print the account information to screen
            print(
                "AccountSummary. ReqId:",
                reqId,
                "Account:",
                account,
                "Tag: ",
                tag,
                "Value:",
                value,
                "Currency:",
                currency,
            )
    
        # override Ewrapper.accountSummaryEnd - notifies when account summary information has been received
        def accountSummaryEnd(self, reqId: int):
            # print to screen
            print("AccountSummaryEnd. ReqId:", reqId)
            # set self.done (a threading.Event) to True
            self.done.set()
    
        # override Ewrapper.nextValidID - used to signal that the connection between application and TWS is complete
        # returns the next valid orderID (for any future transactions)
        # if we send messages before the connection has been established, they can be lost
        # so wait for this method to be called
        def nextValidId(self, orderId: int):
            print(f"Connection ready, next valid order ID: {orderId}")
            self.connection_ready.set()  # signal that the connection is ready
    
    
    # define our event loop - this will run in its own thread
    def run_loop(app):
        app.run()
    
    
    # instantiate an ibapp
    app = ibapp()
    
    # connect
    app.connect("127.0.0.1", 7496, clientId=0)  # clientID identifies our application
    
    # start the application's event loop in a thread
    api_thread = Thread(target=run_loop, args=(app,), daemon=True)
    api_thread.start()
    
    # wait until the Ewrapper.nextValidId callback is triggered, indicating a successful connection
    app.connection_ready.wait()
    
    # request account summary
    print("Requesting account summary")
    app.reqAccountSummary(0, "All", AccountSummaryTags.AllTags)
    
    # wait for the account summary to finish (ie block until app.done - a threading.Event - becomes true)
    app.done.wait()
    
    # disconnect
    app.disconnect()
    Connection ready, next valid order ID: 1
    Requesting account summary
    Error:  -1   2104   Market data farm connection is OK:usfarm.nj
    Error:  -1   2104   Market data farm connection is OK:hfarm
    Error:  -1   2104   Market data farm connection is OK:jfarm
    Error:  -1   2104   Market data farm connection is OK:cashfarm
    Error:  -1   2104   Market data farm connection is OK:eufarmnj
    Error:  -1   2104   Market data farm connection is OK:usfarm
    Error:  -1   2106   HMDS data farm connection is OK:euhmds
    Error:  -1   2106   HMDS data farm connection is OK:cashhmds
    Error:  -1   2106   HMDS data farm connection is OK:fundfarm
    Error:  -1   2106   HMDS data farm connection is OK:ushmds
    Error:  -1   2158   Sec-def data farm connection is OK:secdefnj
    AccountSummary. ReqId: 0 Account: DU* Tag:  AccountType Value: LLC Currency: 
    AccountSummary. ReqId: 0 Account: DU* Tag:  Cushion Value: 1 Currency: 
    AccountSummary. ReqId: 0 Account: DU* Tag:  LookAheadNextChange Value: 1709821800 Currency: 
    AccountSummary. ReqId: 0 Account: DU* Tag:  AccruedCash Value: 0.00 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  AvailableFunds Value: 94012.52 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  BuyingPower Value: 109205.21 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  EquityWithLoanValue Value: 114919.02 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  ExcessLiquidity Value: 95913.11 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  FullAvailableFunds Value: 94012.52 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  FullExcessLiquidity Value: 95913.11 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  FullInitMarginReq Value: 20906.50 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  FullMaintMarginReq Value: 19005.91 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  GrossPositionValue Value: 38555.06 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  InitMarginReq Value: 20906.50 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  LookAheadAvailableFunds Value: 94012.52 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  LookAheadExcessLiquidity Value: 95913.11 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  LookAheadInitMarginReq Value: 20906.50 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  LookAheadMaintMarginReq Value: 19005.91 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  MaintMarginReq Value: 19005.91 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  NetLiquidation Value: 114919.02 Currency: USD
    AccountSummary. ReqId: 0 Account: DU* Tag:  TotalCashValue Value: 76363.96 Currency: USD
    AccountSummaryEnd. ReqId: 0

    The output shows that after the connection was established, we requested our account summary. We get a few lines with error code 2104. These aren’t actually errors, they’re warning messages. From the list of error codes, we can see that 2104 means “Market data farm connection is OK”.

    We also get some 2106’s (A historical data farm is connected) and a 2158 (Sec-def data farm connection is OK).

    Then, we print out each item in our account summary (this is from a connection to a paper trading account).

    Finally, after our account summary has been processed, we print the account summary end message.

    Conclusion

    In this article, you learned how to set up TWS to use the IB native Python API.

    You also learned that an application that uses the API to interact with TWS is, at its heart, a message-handling program.

    We saw that using threading.Event to signal between threads when a message has been received and/or processed is a simple and effective way to manage the flow of information.

    We started with the simplest possible use case – connecting to TWS and requesting our account information. In future articles, we’ll explore some more complex use cases.

    To consolidate your understanding, consider these next steps:

    • Have a look through the IB API documentation to get an idea of the functionality (essentially, anything you can manually do in TWS, you can do via API).
    • Also have a look at the source code for Eclient and Ewrapper. On Windows, they live in the directory C:TWS APIsourcepythonclientibapi (client.py, wrapper.py).
    Disclosure: Interactive Brokers

    Information posted on IBKR Campus that is provided by third-parties does NOT constitute a recommendation that you should contract for the services of that third party. Third-party participants who contribute to IBKR Campus are independent of Interactive Brokers and Interactive Brokers does not make any representations or warranties concerning the services offered, their past or future performance, or the accuracy of the information provided by the third party. Past performance is no guarantee of future results.

    This material is from Robot Wealth and is being posted with its permission. The views expressed in this material are solely those of the author and/or Robot Wealth and Interactive Brokers is not endorsing or recommending any investment or trading discussed in the material. This material is not and should not be construed as an offer to buy or sell any security. It should not be construed as research or investment advice or a recommendation to buy, sell or hold any security or commodity. This material does not and is not intended to take into account the particular financial conditions, investment objectives or requirements of individual customers. Before acting on this material, you should consider whether it is suitable for your particular circumstances and, as necessary, seek professional advice.

    Disclosure: Order Types / TWS

    The order types available through Interactive Brokers LLC’s Trader Workstation are designed to help you limit your loss and/or lock in a profit. Market conditions and other factors may affect execution. In general, orders guarantee a fill or guarantee a price, but not both. In extreme market conditions, an order may either be executed at a different price than anticipated or may not be filled in the marketplace.

    Disclosure: API Examples Discussed

    Throughout the lesson, please keep in mind that the examples discussed are purely for technical demonstration purposes, and do not constitute trading advice. Also, it is important to remember that placing trades in a paper account is recommended before any live trading.

    Go Source

    Chart

    Sign up for Breaking Alerts

    Share post:

    Popular

    More like this
    Related

    Boeing Production Issues Weigh on Manufacturing Order Trends: Apr. 24, 2024

    Equity bulls are struggling to achieve a third consecutive...

    TSLA – Falling Upward and Trusting Your Gut; Plus META

    Yesterday, we took our customary look at market pricing...

    Adults Are Taking Over The Energy Transition

    Progressives will maintain that the planet is on track...