%% Market Data (Level I) clear all; close all; clc; %% 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); pause(1); % create local buffer for market metadata events with size 1000 [metabuf,metalh] = TWS.initBufferForEvent(TWS.Events.MARKETMETADATA,1000); pause(1); %% @(s,e)disp(e.event.data) ,... % create a callback to print error messages to the command window lherr = event.listener( ... TWS.Events.getInstance ,... TWS.Events.ERROR ,... @callback ... ); % connect to TWS session.eClientSocket.eConnect('127.0.0.1',7496,0); %% % 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 % * MarketMetadataEvents % % 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 % % and are communicated through _MarketMetadataEvents_. % % See % % 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'); %contract = com.tws.ContractFactory.GenericStockContract('HSBA'); % create a contract for SPY contract = com.ib.client.Contract(); contract.symbol ('SPY' ); contract.exchange ('ARCA'); contract.primaryExch ('ARCA'); contract.secType ('STK' ); contract.currency ('USD' ); %% % 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 . %% % 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'; %contract.m_exchange = 'SMART'; contract.m_primaryExch = 'SMART'; %contract.m_exchange = 'LSE'; contract.m_primaryExch = 'LSE'; %contract.m_exchange = 'NYSE'; contract.m_primaryExch = 'NYSE'; %% % Specify the (metadata) for subscription. Note that generic ticks cannot be specified if using a _Snapshot_ market data subscription. % list of metadata ticks %% high, low, open, close, volume %genericTickList = ["106,107,114,109,108"]; 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,false,[]); %session.eClientSocket.reqMktData(reqId,contract,"",false,[]); pause(1); 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)) %% % 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)) %% % 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: disp("*** displaying market data events ****"); for i = 1:min(numel(mktDataEvents),10) e = mktDataEvents{i}; %mktDataEvents{i}.data disp(mktDataEvents{i}.data) 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 % wait around while data is collected pause(1); % now that we have data, tell TWS we don't need more data session.eClientSocket.cancelMktData(reqId); % make sure to disposition handles (really important when working with events) %delete(datalh); delete(metalh); delete(lherr); clear datalh ; clear metalh ; clear lherr ; % define nested callback function function callback(~,e); if (e.event.data.reqId == reqId ) buf.add(e.event); end end