Market Depth (Level II)

Market depth data, also known as level II, represents an instrument's order book. Via the TWS API it is possible to obtain this information with the LYNXApi.EClient.reqMarketDepth function (Note: it is named reqMktDepth in Java, C++, and Python). Unlike Top Market Data (Level I), market depth data is sent without sampling nor filtering, however we cannot guarantee that every price quoted for a particular security will be displayed when you invoke LYNXApi.EClient.reqMarketDepth . In particular, odd lot orders are not included. Beginning in API v974 and TWS v974 it is possible to Smart-route a LYNXApi.EClient.reqMarketDepth request to receive aggregated data from all available exchanges, similar to the TWS BookTrader display.


The LYNXApi.EClient.reqMarketDepth method receives a request identifier (or ticker Id) with which to identify the incoming data, the LYNXApi.Contract for which we want to pull this information and the number of rows or depth level that is required. In case the market depth is smaller than the requested number of rows, the TWS will simply return the available entries.

** Python **

self.reqMktDepth(2001, ContractSamples.EurGbpFx(), 5, False, [])

** Java **

client.reqMktDepth(2001, ContractSamples.EurGbpFx(), 5, false, null);

Market Maker or Exchange

Market depth will be returned via the LYNXApi.EWrapper.updateMktDepth or the LYNXApi.EWrapper.updateMktDepthL2 callback. The two functions differ in that when there is a market maker or exchange identifier to be returned market depth data will be relayed back through LYNXApi.EWrapper.updateMktDepthL2. Otherwise it is returned to LYNXApi.EWrapper.updateMktDepth . For example, ARCA only has ARCA itself as a Market Maker. Therefore when requesting market depth data from ARCA, the data will be relayed back via LYNXApi.EWrapper.updateMktDepth . On the other hand, with ISLAND (the ECN for NASDAQ) market maker information is provided, so the market maker MPID will be relayed back via LYNXApi.EWrapper.updateMktDepthL2. The market maker MPID is reported in the 'marketMaker' string argument of the callback function. If the isSmartDepth boolean (available with API v974+) is True, the marketMaker field will indicate the exchange from which the quote originates. Otherwise it indicates the MPID of a market maker.

To check which exchanges offer deep book data, the function LYNXApi.EClient.reqMktDepthExchanges can be invoked. It will return a list of exchanges from where market depth is available if the user has the appropriate market data subscription.

** Python **


** Java **


API 'Exchange' fields for which a market depth request would return market maker information and result in a callback to LYNXApi.EWrapper:updateMktDepthL2 will be indicated in the results from the LYNXApi.EWrapper.mktDepthExchanges field by a 'True' value in the 'isL2' field:

** Python **

def mktDepthExchanges(self, depthMktDataDescriptions:ListOfDepthExchanges):

for desc in depthMktDataDescriptions:
    print("DepthMktDataDescription.", desc)

** Java **

public void mktDepthExchanges(DepthMktDataDescription[] depthMktDataDescriptions) {
    for (DepthMktDataDescription depthMktDataDescription : depthMktDataDescriptions) {
        System.out.println("Depth Mkt Data Description. Exchange: " + depthMktDataDescription.exchange() +
        ", ListingExch: " + depthMktDataDescription.listingExch() + 
        ", SecType: " + depthMktDataDescription.secType() +
        ", ServiceDataType: " + depthMktDataDescription.serviceDataType() +
        ", AggGroup: " + depthMktDataDescription.aggGroup()


Initially, all requested/available rows will be delivered to the client application. As market moves however these rows will inevitably change. To keep the client's order book consistent, the TWS will send updates not only informing which row is to be updated but also the operation to perform in the row: insert (0), update (1) or remove (2).

** Python **

 class TestWrapper(wrapper.EWrapper):

def updateMktDepth(self, reqId: TickerId, position: int, operation: int,side: int, price: float, size: int):
    super().updateMktDepth(reqId, position, operation, side, price, size)
    print("UpdateMarketDepth. ReqId:", reqId, "Position:", position, "Operation:",operation, "Side:", side, "Price:", price, "Size:", size)

def updateMktDepthL2(self, reqId: TickerId, position: int, marketMaker: str,operation: int, side: int, price: float, size: int, isSmartDepth: bool):
    super().updateMktDepthL2(reqId, position, marketMaker, operation,         side,price, size, isSmartDepth)

    print("UpdateMarketDepthL2. ReqId:", reqId, "Position:", position,             "MarketMaker:", marketMaker, "Operation:",operation, "Side:",             side, "Price:", price, "Size:", size, "isSmartDepth:",                     isSmartDepth)

** Java **

public class EWrapperImpl implements EWrapper {

public void updateMktDepth(int tickerId, int position, int operation,
        int side, double price, int size) {
    System.out.println("UpdateMarketDepth. "+tickerId+" - Position: "+position+", Operation: "+operation+", Side: "+side+", Price: "+price+", Size: "+size+"");

public void updateMktDepthL2(int tickerId, int position,
        String marketMaker, int operation, int side, double price, int size, boolean isSmartDepth) {
    System.out.println("UpdateMarketDepthL2. "+tickerId+" - Position: "+position+", Operation: "+operation+", Side: "+side+", Price: "+price+", Size: "+size+", isSmartDepth: "+isSmartDepth);


To cancel an active market depth request simply invoke the LYNXApi.EClient.cancelMktDepth passing in the request's identifier.

** Python **

self.cancelMktDepth(2001, False)
self.cancelMktDepth(2002, True)

** Java **

client.cancelMktDepth(2001, false);


Given the potentially high amount of data being sent, market depth request's are much more limited. Just as with historical data requests, the amount of active depth requests is related to the amount of market data lines, with a minimum of three and maximum of 60:

Number of lines Max. Requests
0 - 399 3
400 - 499 4
500 - 599 5
600 - 699 6