Duration: 11:37
Level: Intermediate

This lesson will explore how to request market and historical data using the TWS Python API. Code examples will be presented which show the minimum Python code necessary to request streaming and historical data and display market data in the console. Finally, we will discuss limitations on requesting data, and the types of data which are included in IBKR’s real time feed as compared to the historical database.

Study Notes:

Hello, and welcome to a short video discussing how to request market data using the TWS Python API.

There are several calls for market data.

The most popular of these include:

  • reqMktData
  • reqHistoricalData
  • reqTickByTickData

However, we offer several other market data requests, that you may wish to explore.

  • reqRealTimeBars
  • reqMktDepth
  • reqHistoricalTicks
  • reqHistogramData

reqMktData is used to request aggregate real time data that is streamed several times per second. This is the most common method of requesting Live market data.

User Guide: https://interactivebrokers.github.io/tws-api/md_request.html

reqTickByTickData – Unlike reqMktData, this will provide every individual tick on the request. This is a mirror of Trader Workstation’s ‘Time & Sales’ window.

User Guide: https://interactivebrokers.github.io/tws-api/tick_data.html

reqHistoricalData – This is a means to request historical data bars through the API. reqHistoricalData is identical to TWS’s bar charts. This is the most common method of requesting historical market data.

User Guide: https://interactivebrokers.github.io/tws-api/historical_bars.html

With reqMktData, we can use reqMktDataType to change the exact data that is streamed to us.

  • This allows us to request a value, like 1, or Live market data. This will provide the live, top of book market data.
  • We can also request 2, which is Frozen Data. In the event we want to request the market data from close, this would be an optimal way to do so.
  • We can request 3, or Delayed Data. Like TWS, if we do not have any market data subscriptions, we are able to use this request to receive delayed data.
  • Lastly we can use 4, or Frozen Delayed data, which will work as a combination of the two so that you can request market data outside of regular trading hours even without a subscription.

It is important to note that for both live and historical market data, your account must have an active market data subscription for the relevant account. You can subscribe to these market data subscriptions in client portal. One way to reach directly to this page is to open Trader Workstation, then select “Account” in the top left corner, followed by “Subscribe to Market Data/Research” near the bottom. This will take you directly to the relevant market data subscriptions page.

In today’s video, we will be primarily focusing on reqMktData and reqHistoricalData. As we move forward, I would like to specify that the Interactive Brokers TWS API has a pacing limitation of 50 messages per second. As such, a total of 50 messages may be sent AND received within each one second span. Please keep this in mind as you move forward with your coding.

It is important to note that there are several unique historical data limitations which should be reviewed and adhered to as you are writing your programs. These limitations are not unique to the API, as these will also take effect in TWS as well. We would advise reviewing our full historical data limitations page for further details { https://interactivebrokers.github.io/tws-api/historical_limitations.html }.

Some notable historic data limitations include:

  • Not all duration, or the scope of your request, can be used with ever bar size. For example, Interactive Brokers’ largest duration for a 1 second bar is 30 minutes.
  • Interactive Brokers does not provide historical data for expired options.
  • Interactive Brokers does not provide historical data for Futures that expired more than two years ago.

Before moving forward, I would acknowledge that we will be using a different style to code these requests than our previous lesson. There are numerous ways to code the TWS API, and we encourage you to try as many styles as you would like, to see what suits your program best.

Here, I am also introducing a new EWrapper method, nextValidId. This will provide a new order ID for each of my requests, so I avoid duplicating values moving forward. This can be helpful for distinguishing your market data requests, and also your orders, once we reach that step.

Now to begin with our code, we will define the market data type (we’ll request 4). All we need to type for this is simply self.reqMktDataType(4).

Now we’ll start our market data request. Just like before, we include a reqId, and contract. I will be using our orderID variable for the nextValidId method with our request argument.  A new addition will be for the genericTickList. By default, we will receive values like the bid price and size, Ask price and size, along with the closing price, and the days total traded volume. However, we have the option to request more unique values, such as shortable status, or we can request only the amount of shortable shares available.

You can read the full list of these values in our documentation.

Next, you have the option to request a single snapshot of data by setting the snapshot value to 1 or receive an ongoing stream of market data by setting this value to 0.

I have chosen to set this value to 0 for streaming market data.  This is intended for use by individuals who have an active Market data subscription for a given contract.  You may also set an integer variable for requesting regulatory snapshots.  This is intended for accounts that do not have a relevant Market data subscription for a U.S stock.

This will incur a one-time fee of $0.01 to the account per snapshot. In my case, I will set this value to 0.

Finally, we will end with an empty list as this is used for internal use only.  Now that we have all of our EClient requests we will define our EWrapper methods. This will start with tick price which is used for Price values from your market data requests. In this case we will just be printing the return values from tick price.

I would note I am using TickTypeEnum.to_str so I can receive the human readable value of the tick instead of just the tick value. Then we will create tick size. Similar to tick price this will return the size values. This will indicate values like bid size, ask size, last size, or daily volume.

There are several other methods you may wish to include here, such as tick string and tick generic which are needed for some of those generic ticks we had mentioned earlier. Now if you run this request, we could see a variety of values returned. Like we mentioned before, we could see the bid price the ask size, volume and so on.

Request Historical Data

 Now that we’ve received data for our live streaming data request let’s go ahead and request historical data.

Requesting historical data will be very similar. The difference is we will use the EClient method, reqHistoricalData and use the EWrapper method, historicalData.

For reqHistoricalData, we will start by entering a request ID and a contract. Then, we can enter our endDateTime. We can leave this as an empty string, which will then automatically use the current time.

I will specify a request for October 10, 2022 at 3:00 PM US/Central time zone. Then, we can specify the duration, which will be one day in our case. Then we can specify the bar size, and I will specify as one hour.

After specifying our dates, I will specify the whatToShow value.  I will set this to trades to see the trades

value however there are several other options that you may want to review in our documentation.

Finally, we can specify our Booleans. This will be use RTH which I will set to 0, so we include trades outside of regular trading hours. Next ‘formatDate’ is used to display the returned datetime values in epoch time or standard datetime. I will set this to 1, for standard datetime. Then the “keep up to date” flag can be used if we want streaming updates; however, I will leave this as 0. Finally, we will end with an empty list, as this field is for internal use only.

Let’s create our EWrapper method, historicalData. Here, we will include arguments for self, request ID, and ‘bar’. Just like contractDetails in our previous video, our bar object has many attributes, such as the high, low, open, and close. Which you may wish to uniquely specify in your requests.

And again, just like in our contract details request, I will be including the historicalDataEnd method from EWrapper, to safely disconnect from my socket.   This also displays the start and end time of my request.

And so, if we run this request, we can see our historical market data with the datetime for the given market data.

These are just a few simple examples for requesting market data. As we had mentioned before, there are many ways to request your historical and live market data, and we suggest exploring them further in our documentation. However, that concludes our video on requesting market data using the TWS API. Thank you for watching, and we look forward to having you join us for more TWS Python API lessons.

Historical Market Data

Level 1 Market Data

Code Snippet – Request Market Data

from ibapi.client import *
from ibapi.wrapper import *

class TestApp(EClient, EWrapper):
    def __init__(self):
        EClient.__init__(self, self)

    def nextValidId(self, orderId: int):
        mycontract = Contract()
        mycontract.symbol = "AAPL"
        mycontract.secType = "STK"
        mycontract.exchange = "SMART"
        mycontract.currency = "USD"

        self.reqMktData(orderId, mycontract, "", 0, 0, [])

    def tickPrice(self, reqId, tickType, price, attrib):
        print(f"tickPrice. reqId: {reqId}, tickType: {TickTypeEnum.to_str(tickType)}, price: {price}, attribs: {attrib}")

    def tickSize(self, reqId, tickType, size):
        print(f"tickSize. reqId: {reqId}, tickType: {TickTypeEnum.to_str(tickType)}, size: {size}")


app = TestApp()
app.connect("", 7497, 1000)

Code Snippet – Request Historical Market Data

from ibapi.client import *
from ibapi.wrapper import *

class TestApp(EClient, EWrapper):
    def __init__(self):
        EClient.__init__(self, self)

    def nextValidId(self, orderId: int):
        mycontract = Contract()
        mycontract.symbol = "AAPL"
        mycontract.secType = "STK"
        mycontract.exchange = "SMART"
        mycontract.currency = "USD"

        self.reqHistoricalData(orderId, mycontract, "20221010 15:00 US/Central", "1 D", "1 hour", "TRADES", 0, 1, 0, [])

    def historicalData(self, reqId, bar):
        print(f"Historical Data: {bar}")

    def historicalDataEnd(self, reqId, start, end):
        print(f"End of HistoricalData")
        print(f"Start: {start}, End: {end}")

app = TestApp()
app.connect("", 7497, 1000)

Disclosure: Interactive Brokers

The analysis in this material is provided for information only and is not and should not be construed as an offer to sell or the solicitation of an offer to buy any security. To the extent that this material discusses general market activity, industry or sector trends or other broad-based economic or political conditions, it should not be construed as research or investment advice. To the extent that it includes references to specific securities, commodities, currencies, or other instruments, those references do not constitute a recommendation by IBKR to buy, sell or hold such investments. 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.

The views and opinions expressed herein are those of the author and do not necessarily reflect the views of Interactive Brokers LLC, its affiliates, or its employees.

Any trading symbols displayed are for illustrative purposes only and are not intended to portray recommendations.

In accordance with EU regulation: The statements in this document shall not be considered as an objective or independent explanation of the matters. Please note that this document (a) has not been prepared in accordance with legal requirements designed to promote the independence of investment research, and (b) is not subject to any prohibition on dealing ahead of the dissemination or publication of investment research.

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.