Jarloo

Menu

Get Real-Time Stock data using the Interactive Brokers API

Interactive Brokers has an API for customers that you can use to get real-time tick by tick stock data, submit orders and more. The API works by making a socket connection to their Traders Workstation software on your desktop.
Just to ensure this is clear, this API will ONLY work if you are a current member of Interactive Brokers.

 

The API supports C#, Java, C++ and Excel.

This tutorial will show how to get started and write a simple client that gets prices and order size changes and will not cover submitting orders back to the market.

 

Creating a Simple C# Client for the IB API

Download the IB API Software

The first step is you need to get the software you need to integrate your app with the Traders Workstation (TWS). IB API Software

This will give you the TWSLib.dll file you will need to integrate your program, and will also give you a good example in C# that shows how much the API can do. Unfortunately depending on your needs the example can be a bit on the complicated side since it attempts to show off all the features of the API.

Allow API connections in TWS

Before you can connect your project to TWS you must first allow access. Goto the Configure menu and select API and you should end up with a window that looks like the following:

tws-settings

The settings I’m using are shown above. You really just need the “Enable ActiveX and Socket Clients” checked. DDE is only used from the Excel client and the rest are all personal preference.

 

Creating the Project

Create a new Console Application in Visual Studio and then add a reference to the TWSLib included in the install package you just downloaded.

All the action with the API occurs through an interface you must implement called EWrapper. You need to implement the interface and then you can add your code in the various  methods.

Creating the EWrapper Implemention

Here is the code for a class that implements the EWrapper interface. For our purposes we will leave the vast majority of the methods empty as they will not be needed. We will only be interested in two of them: tickPrice and tickSize.

using System;
using IBApi;

namespace IbTest
{
    internal class EWrapperImpl : EWrapper
    {
        private enum FieldTypes
        {
            Bid=1,
            Ask=2,
            AskSize=3,
            Last=4,
            LastSize=5,
            High=6,
            Low=7,
            Volume=8,
            Close=9
        }

        public EClientSocket ClientSocket { get; set; }

        public EWrapperImpl()
        {
            ClientSocket = new EClientSocket(this);
        }

        public void error(Exception e)
        {
            Console.WriteLine(e.ToString());
        }

        public void error(string str)
        {
            Console.WriteLine(str);
        }

        public void error(int id, int errorCode, string errorMsg)
        {
            Console.WriteLine(errorMsg);
        }

        public void currentTime(long time)
        {
        }

        public void tickPrice(int tickerId, int field, double price, int canAutoExecute)
        {
            var name = Enum.GetName(typeof(FieldTypes), field);

            Console.WriteLine("Price Change Ticker: " + tickerId + ", Field: "
                + name + ", Price: " + price);
        }

        public void tickSize(int tickerId, int field, int size)
        {
            var name = Enum.GetName(typeof(FieldTypes), field);

            Console.WriteLine("Size Change TickerId: " + tickerId + ", Field: "
                + name + ", Size: " + size);
        }

        public void tickString(int tickerId, int field, string value)
        {
        }

        public void tickGeneric(int tickerId, int field, double value)
        {
        }

        public void tickEFP(int tickerId, int tickType, double basisPoints, string formattedBasisPoints,
            double impliedFuture,
            int holdDays, string futureExpiry, double dividendImpact, double dividendsToExpiry)
        {
        }

        public void deltaNeutralValidation(int reqId, UnderComp underComp)
        {
        }

        public void tickOptionComputation(int tickerId, int field, double impliedVolatility, double delta,
            double optPrice,
            double pvDividend, double gamma, double vega, double theta, double undPrice)
        {
        }

        public void tickSnapshotEnd(int tickerId)
        {
        }

        public void nextValidId(int orderId)
        {
        }

        public void managedAccounts(string accountsList)
        {
        }

        public void connectionClosed()
        {
        }

        public void accountSummary(int reqId, string account, string tag, string value, string currency)
        {
        }

        public void accountSummaryEnd(int reqId)
        {
        }

        public void bondContractDetails(int reqId, ContractDetails contract)
        {
        }

        public void updateAccountValue(string key, string value, string currency, string accountName)
        {
        }

        public void updatePortfolio(Contract contract, int position, double marketPrice, double marketValue,
            double averageCost,
            double unrealisedPNL, double realisedPNL, string accountName)
        {
        }

        public void updateAccountTime(string timestamp)
        {
        }

        public void accountDownloadEnd(string account)
        {
        }

        public void orderStatus(int orderId, string status, int filled, int remaining, double avgFillPrice, int permId,
            int parentId,
            double lastFillPrice, int clientId, string whyHeld)
        {
        }

        public void openOrder(int orderId, Contract contract, Order order, OrderState orderState)
        {
        }

        public void openOrderEnd()
        {
        }

        public void contractDetails(int reqId, ContractDetails contractDetails)
        {
        }

        public void contractDetailsEnd(int reqId)
        {
        }

        public void execDetails(int reqId, Contract contract, Execution execution)
        {
        }

        public void execDetailsEnd(int reqId)
        {
        }

        public void commissionReport(CommissionReport commissionReport)
        {
        }

        public void fundamentalData(int reqId, string data)
        {
        }

        public void historicalData(int reqId, string date, double open, double high, double low, double close,
            int volume, int count,
            double WAP, bool hasGaps)
        {
        }

        public void historicalDataEnd(int reqId, string start, string end)
        {
        }

        public void marketDataType(int reqId, int marketDataType)
        {
        }

        public void updateMktDepth(int tickerId, int position, int operation, int side, double price, int size)
        {
        }

        public void updateMktDepthL2(int tickerId, int position, string marketMaker, int operation, int side,
            double price, int size)
        {
        }

        public void updateNewsBulletin(int msgId, int msgType, string message, string origExchange)
        {
        }

        public void position(string account, Contract contract, int pos, double avgCost)
        {
        }

        public void positionEnd()
        {
        }

        public void realtimeBar(int reqId, long time, double open, double high, double low, double close, long volume,
            double WAP,
            int count)
        {
        }

        public void scannerParameters(string xml)
        {
        }

        public void scannerData(int reqId, int rank, ContractDetails contractDetails, string distance, string benchmark,
            string projection, string legsStr)
        {
        }

        public void scannerDataEnd(int reqId)
        {
        }

        public void receiveFA(int faDataType, string faXmlData)
        {
        }

        public void verifyMessageAPI(string apiData)
        {
        }

        public void verifyCompleted(bool isSuccessful, string errorText)
        {
        }

        public void displayGroupList(int reqId, string groups)
        {
        }

        public void displayGroupUpdated(int reqId, string contractInfo)
        {
        }
    }
}

So there isn’t much to explain here. I created an Enum to hold the field types and then when a message comes in I get the name of the field and send the output to the console.

The tickPrice method will fire when there is a change to the bid, ask or last.

The tickSize method will fire when there is a change in the bid or ask size.

Making the connection and getting the data

In the Main() method in your Program.cs add the following:

using System;
using IBApi;

namespace IbTest
{
    internal class Program
    {
        private static void Main()
        {
            var ibClient = new EWrapperImpl();

            Console.WriteLine("Connecting...");

            ibClient.ClientSocket.eConnect("127.0.0.1", 7496, 0);

            var contract = new Contract
            {
                Symbol = "AAPL",
                SecType = "STK",
                Currency = "USD",
                Exchange = "Smart"
            };

            Console.WriteLine("Requesting Data...");

            ibClient.ClientSocket.reqMktData(1, contract, "", false, null);

            Console.WriteLine("Press any key to exit");
            Console.Read();

            ibClient.ClientSocket.eDisconnect();
        }
    }
}

So first we make an instance of our class EWrapperImpl, then we connect to TWS. (I’m using mine on the same machine, but that doesn’t have to be the case.)

Then we create a new Contract class for the symbol AAPL and pass that in using ClientSocket.reqMktData. The first parameter the number 1 is an ID we pass to TWS to identify this Contract (ticker) in the future. So when a price comes in TWS will tell us the bid changed for #1, instead of for AAPL. So you will need to keep a map of the ticker to id around in a dictionary or some other store.

Also note that the fourth parameter is false. This specifies if you want a snapshot of the data or to be plugged in real-time. By specifying false we are telling it we want the real-time data and not the snapshot.

Thats it, if you run your code it should connect up and you should be good.

Options

The Contract passed in does not have to be a stock, you can get futures, options, foreign exchange etc… The possible values are:

  • STK
  • OPT
  • FUT
  • IND
  • FOP
  • CASH
  • BAG
  • NEWS

For options you will need to fill out the Strike, Expiry and Right fields like so:

var contract = new Contract
{
    Symbol = "INTC",
    SecType = "OPT",
    Currency = "USD",
    Exchange = "Smart",
    Strike=27.5,
    Expiry = "20150508",
    Right = "C"
};

This makes sense because on the exchange this would be listed as INTC150508C00027500.

If your option has weekly’s and monthlies then you need to include the DAY on the Expiry, otherwise YYYYMM is fine. If you get an error telling you to include the tradeclass or multiplier then you know you need to specify the DAY as above.

The API also supports combo’s so you could give it a vertical spread, horizontal spread, butterfly, straddle or whatever type of combo your looking for.

 

Additional Information

IB API

API Documentation

Categories:   Code, Finance

Comments

  • Posted: July 28, 2015 03:26

    Alex

    Thanks Kelly: this is so much more straightforward than the IB documentation. Excellent stuff. Just to make my life complicated for myself again I ported this to Mac using Xcode and C++ (because an analytics tool I have to use does not talk C#). I don't know C# well enough and get stuck with your line: >> public EClientSocket ClientSocket { get; set; } Any suggestions on how would you construct the { get; set; } with the posix variant of EClientSocket? (EPosixClientSocket) in C++ ? Thanks!
    • Posted: July 28, 2015 10:23

      Kelly Elias

      Sorry I haven't used C++ for quite a few years now and don't have a good answer for you.