Market Data (Level I)

Contents

Initialize session with Trader Workstation

% get TWS session instance
session = TWS.Session.getInstance();

% create local buffer for market data events with size 10,000 (default size is 32)
[databuf,datalh] = TWS.initBufferForEvent(TWS.Events.MARKETDATA,10000);

% create local buffer for market metadata events with size 1000
[metabuf,metalh] = TWS.initBufferForEvent(TWS.Events.MARKETMETADATA,1000);

% create a callback to print error messages to the command window
lherr  = event.listener(                         ...
                        TWS.Events.getInstance  ,...
                        TWS.Events.ERROR        ,...
                        @(s,e)disp(e.event.data) ...
                       );

% connect to TWS
session.eClientSocket.eConnect('127.0.0.1',7496,0);
added interface method: TWSNotification
notification listener has been added
Server Version:71
TWS Time at connection:20150102 16:49:42 EST

A callback to print out error message to the command window is particularly useful here. There are many possible errors associated with requesting Market Depth in general and in particular the specified contract/exchange might not privide the requested data.

Requesting Level 1 Market Data

There is a slight deviation from the native IB Java API here. Namely, level 1 market data callbacks are separated into:

MarketDataEvents are produced when the market data changes. A change in market data corresponds to changes in the size and/or price of the best ask/bid offer avaliable on the subscribed exchange.

Changes in market data (best ask/bid offer) are communicated through MarketDataEvents associated with EWrapper callbacks:

Many axuillary types of market data ticks can be requested as a part of the market data request. These data are refered to as Generic Ticks and are communicated through MarketMetadataEvents.

See Tick Types for additional descriptions of tick types and associated EWrapper callback. The bottom line is that tickValue/field < 10 are MarketDataEvents and everything else is MarketMetadata.

The first step in constructing a market data request is to specify a contract which encapsulates the equity symbol and exchange information.

% create an empty stock contract
contract = com.tws.ContractFactory.GenericStockContract('SPY');

By default the exchange for GenericStockContract is 'SMART' which is only appropriate when placing an order request.

There are many different exchanges to choose from for data subscriptions such as:

and many more.

Operationally, it is advisable to make a Contract Details request for a complete list of valid exchanges.

For additional information of avaliable market data accessable through Interactive Brokers see Market Data Feed Options.

All of the exchanges listed above list 'SPY' so any one of them will work for this example.

% set the exchange for which to obtain market data
contract.m_exchange = 'ARCA';  contract.m_primaryExch = 'ARCA';

Specify the Generic Tick Tags (metadata) for subscription. Note that generic ticks cannot be specified if using a Snapshot market data subscription.

% list of metadata ticks
genericTickList = [                                      ...
                   '100,101,105,106,107,125,165,166,'    ...
                   '225,232,221,233,236,258, 47,291,'    ...
                   '293,294,295,318,370,370,377,377,'    ...
                   '381,384,384,387,388,391,407,411,'    ...
                   '428,439,439,456, 59,459,460,499,'    ...
                   '506,511,512,104,513,514,515,516,517' ...
                  ];

Since multiple market data subscriptions can be active simultaniously it is important to provide a unique request Id for each market data request

reqId = 0;

Having a unique request ID, contract to specify symbol and exchange, and a list of metadata we're ready to make a market data request.

% request market data subscription.  Note that arg4 is read as "snapshot=false"
session.eClientSocket.reqMktData(reqId,contract,genericTickList,false,[]); pause(1);

It is important to keep in mind that a continuous data subscription has been started so that MarketDataEvents will be streamed until disconnected from TWS or the subscription is cancelled. Alternatively, provide true (read 'snapshot=true') to only take an instantanious peak at the market data without spining up a subscription. That is, market data snapshots are one-time thing providing a single instance of top of the book market data for the equity on the specified exchange.

To cancel a market data subscription simply call EClientSocket::cancelMktData method with the associated request Id.

Processing Market Data Events (Part 1)

Depending on the symbol and exchange, market data events can be vary numerous. At the time of current writting, market data rate range from 45 to 5 per second:

Exchangemsg rate
ISLAND45
BATS20
LAVA17
TPLUS25

Market metadata events are generally fewer than data events.

First, have a look at the market data events by printing them out to the Command Window:

% dump market data events to the screen
cellfun(@(e)disp(e.data),collection2cell(databuf))
bidPrice:205.02
 
bidSize:9.0
 
askPrice:205.04
 
askSize:2.0
 
bidSize:9.0
 
askSize:2.0
 

Simillarly, lets have a look at a few metadata events

% print out string representation of market metadata objects
cellfun(@(e)disp(e.data),collection2cell(metabuf))
OptionCallOpenInterest:9821625
 
OptionPutOpenInterest:20603997
 
auctionVolume:-1
 
auctionImbalance:0
 
auctionPrice:-1.0
 
regulatoryImbalance:0
 
OptionImpliedVolatility:0.14244696914930022
 
AvgVolume:1349683
 
13WeekHigh:211.83500671
 
13WeekLow:180.78500366
 
26WeekHigh:211.83500671
 
26WeekLow:180.78500366
 
52WeekHigh:211.83500671
 
52WeekLow:169.88499451
 
OptionCallVolume:947756
 
OptionPutVolume:1600045
 

It is fairly straight forward to process market data events based on tickId. For ease of use, create cell array of market data events from the data buffer

% aggregate market data events in the buffer to cell array
mktDataEvents = collection2cell(databuf);

Rough outline for processing events by tickId:

for i = 1:min(numel(mktDataEvents),10)

    e = mktDataEvents{i};

    switch e.data.tickId

        case 0
            % bid size
        case 1
            % bid price
        case 2
            % ask price
        case 3
            % ask size
        case 4
            % last sale price
        case 5
            % last sale size
        case 8
            % total volume
        otherwise
            % no op
    end
end

Processing Market Data Events (Part 2)

When multiple market data subscriptions are active simultaniously, additional book keeping is required to match/map market data reqId to the exchange associated with the subscription.

This can be accomplished using MATLAB's built-in containers.Map or java.util.HashMap.

A java HashMap can be initialized as

map = java.util.HashMap();

For each market data request/subscription make an entry in the map to keep track of which reqId goes with which exchange

map.put(reqId,contract.m_exchange);

Then when processing events, translate the subscription request Id into a human readable exchange name

map.get(databuf.get().data.reqId)
map.get(metabuf.get().data.reqId)
ans =

ARCA


ans =

ARCA

Using hash map ensure constant time retreival of the exchange string. Solutions involving strcmp can be tedious and do not generally scale well for processing many events quickly.

See Also

TWSMarketDepthExample | TWSContractDetailsExample

References

Interactive Brokers:

Interactive Brokers API:

TWS@Github:

Apache Commons: