undefined

Receiving Watchlist Data

Receiving Market Data

Real time data is accessed in the API using a subscribe-and-publish model that is also used with other functionality such as retrieving position or account values. After a streaming market data subscription request for a particular contract in LYNX's database is made, a continuous stream of market data is returned by TWS and separated to different functions in EWrapper depending on the data type (integer vs decimal vs string). Since the subscribe-and-publish model is inherently asynchronous, the returned data is linked to the initial request using a numerical label specified in the request called the request ID (reqID).

After subscribing to the ticker stream, your API client will receive the data supplied by the TWS API server via several methods. In your API client code, you will need to implement these methods to manipulate the data relayed back to the client. Notice how market data callbacks such as LYNXApi.EWrapper.tickPrice and LYNXApi.EWrapper.tickSize methods contain the request id with which the response can be mapped to its originating request. By default, there are certain 'default tick types' that are always returned. These include fields such as the bid price, ask price, bid size, ask size, etc. There are additional types of data available with the real time data that are requested by specifying certain "generic tick types" in the market data request. For more information see also Generic Tick Types.

When LYNXApi.EWrapper.tickPrice and LYNXApi.EWrapper.tickSize are reported as -1, this indicates that there is no data currently available. Most commonly this occurs when requesting data from markets that are closed. It can also occur for infrequently trading instruments which do not have open bids or offers at that time of the request. To receive frozen quotes (the last available bid/ask recorded by the system) invoke the function LYNXApi.EClient.reqMarketDataType with argument 2. Alternatively, to receive "delayed frozen" data from tickers without holding market data subscriptions, specify a market data type of 4. Frozen data is exclusive to default tick types- Generic Tick Types are not available- and requires market data subscriptions.

For bid, ask, and last data, there will always be a LYNXApi.EWrapper.tickSize callback following each LYNXApi.EWrapper.tickPrice . This is important because with combo contracts, an actively trading contract can have a price of zero. In this case it will have a positive LYNXApi.EWrapper.tickSize value. LYNXApi.EWrapper.tickSize is also invoked every time there is a change in the size of the last traded price. For that reason, there will be duplicate tickSize events when both the price and size of a trade changes.

** Python **

class TestWrapper(wrapper.EWrapper):

def tickPrice(self, reqId: TickerId, tickType: TickType, price: float,
              attrib: TickAttrib):
    super().tickPrice(reqId, tickType, price, attrib)
    print("TickPrice. TickerId:", reqId, "tickType:", tickType,
          "Price:", price, "CanAutoExecute:", attrib.canAutoExecute,
          "PastLimit:", attrib.pastLimit, end=' ')

    if tickType == TickTypeEnum.BID or tickType == TickTypeEnum.ASK:
        print("PreOpen:", attrib.preOpen)
    else:
        print()

def tickSize(self, reqId: TickerId, tickType: TickType, size: int):
    super().tickSize(reqId, tickType, size)
    print("TickSize. TickerId:", reqId, "TickType:", tickType,
          "Size:", size)

def tickString(self, reqId: TickerId, tickType: TickType, value: str):
    super().tickString(reqId, tickType, value)

    print("TickString. TickerId:", reqId, "Type:", tickType, "Value:",
          value)

def tickGeneric(self, reqId: TickerId, tickType: TickType, value: float):
    super().tickGeneric(reqId, tickType, value)
    print("TickGeneric. TickerId:", reqId, "TickType:", tickType,
          "Value:", value)

** Java **

public class EWrapperImpl implements EWrapper {

@Override
public void tickPrice(int tickerId, int field, double price, TickAttrib attribs) {
    System.out.println("Tick Price. Ticker Id:"+tickerId+", Field: "+field+", Price: "+price+", CanAutoExecute: "+ attribs.canAutoExecute()
    + ", pastLimit: " + attribs.pastLimit() + ", pre-open: " + attribs.preOpen());
}
Beginning in API v973.04 the pre-open attribute is available in the API. This attribute indicates that bid/ask quotes released by futures exchanges are in the pre-open period.
@Override
public void tickSize(int tickerId, int field, int size) {
    System.out.println("Tick Size. Ticker Id:" + tickerId + ", Field: " + field + ", Size: " + size);
}

@Override
public void tickString(int tickerId, int tickType, String value) {
    System.out.println("Tick string. Ticker Id:" + tickerId + ", Type: " + tickType + ", Value: " + value);
}

@Override
public void tickGeneric(int tickerId, int tickType, double value) {
    System.out.println("Tick Generic. Ticker Id:" + tickerId + ", Field: " + TickType.getField(tickType) + ", Value: " + value);
}

Exchange Component Mapping

A market data request is able to return data from multiple exchanges. Beginning in TWS/LYNXG v963 and API v973.02, after a market data request is made for an instrument covered by market data subscriptions, a message will be sent to function LYNXApi.EWrapper.tickReqParams with information about 'minTick', BBO exchange mapping, and available snapshot permissions.

** Python **

def tickReqParams(self, tickerId:int, minTick:float,
                  bboExchange:str, snapshotPermissions:int):
    super().tickReqParams(tickerId, minTick, bboExchange,
                          snapshotPermissions)
    print("TickReqParams. TickerId:", tickerId, "MinTick:", minTick,
          "BboExchange:", bboExchange, "SnapshotPermissions:",
          snapshotPermissions)

** Java **

@Override
public void tickReqParams(int tickerId, double minTick, String bboExchange, int snapshotPermissions) {
    System.out.println("Tick req params. Ticker Id:" + tickerId + ", Min tick: " + minTick + ", bbo exchange: " + bboExchange + ", Snapshot permissions: " + snapshotPermissions);
}

The exchange mapping identifier bboExchange will be a symbol such as "a6" which can be used to decode the single letter exchange abbreviations returned to the bidExch, askExch, and lastExch fields by invoking the function LYNXApi.EClient.reqSmartComponents . More information about Component Exchanges.

The minTick returned to tickReqParams indicates the minimum increment in market data values returned to the API. It can differ from the minTick value in the ContractDetails class. For instance, combos will often have a minimum increment of 0.01 for market data and a minTick of 0.05 for order placement.

Re-Routing CFDs

LYNX does not provide market data for certain types of instruments, such as stock CFDs and forex CFDs. If a stock CFD or forex CFD is entered into a TWS watchlist, TWS will automatically display market data for the underlying ticker and show a 'U' icon next to the instrument name to indicate that the data is for the underlying instrument.

From the API, when level 1 or level 2 market data is requested for a stock CFD or a forex CFD, a callback is made to the functions LYNXApi.EWrapper.rerouteMktDataReq or LYNXApi.EWrapper.rerouteMktDepthReq respectively with details about the underlying instrument in LYNX's database which does have market data.

** Python **

def rerouteMktDataReq(self, reqId: int, conId: int, exchange: str):
    super().rerouteMktDataReq(reqId, conId, exchange)
    print("Re-route market data request. ReqId:", reqId, "ConId:",
          conId, "Exchange:", exchange)


def rerouteMktDepthReq(self, reqId: int, conId: int, exchange: str):
    super().rerouteMktDataReq(reqId, conId, exchange)
    print("Re-route market depth request. ReqId:", reqId, "ConId:",
          conId, "Exchange:", exchange)

** Java **

@Override
public void rerouteMktDataReq(int reqId, int conId, String exchange) {
    System.out.println(EWrapperMsgGenerator.rerouteMktDataReq(reqId, conId, exchange));
}

@Override
public void rerouteMktDepthReq(int reqId, int conId, String exchange) {
    System.out.println(EWrapperMsgGenerator.rerouteMktDepthReq(reqId, conId, exchange));
}