IB-Matlab

IB-Matlab is a commercial application that connects Matlab with Interactive-Brokers (IB).

IB-Matlab provides a Matlab wrapper interface to IB’s API Java connector. This enables quantitative traders and algo traders to easily leverage Matlab’s superior analysis and visualization capabilities, with InteractiveBrokers no-nonsense low-cost trading platform for stocks, ETFs, mutual funds, bonds, options, futures, commodities and FOREX (foreign currency exchange).

The need

While IB’s Java connector, which is provided by IB, can be used directly in Matlab, setting up the event callbacks and data conversions between Matlab and the connector is definitely not easy. You need to be familiar with both Matlab AND Java, at least to some degree.

Other applications that solve these problems are either expensive, limited in functionality, or limited in deployment (for example, ActiveX solutions will only work on 32-bit Windows systems). matlab2ib quant2ib

Main features of IB-Matlab

IB-Matlab connectivity (Matlab and TWS may be on separate computers) IB-Matlab is an inexpensive application that solves the connectivity problem by enabling simple Matlab access to the entire IB API functionality. Users can activate IB’s API by simple Matlab commands, without any need to know Java.

Active trading actions (buy, sell, short and cancel) and query actions (market, streaming quotes, open orders, executions, historical, account and portfolio data) are available using simple one-line Matlab code (see usage examples below). Additional trading features (the full range of IB API) can be accessed using internal objects exposed by IB-Matlab.

Users can easily attach Matlab code (callbacks) to IB events. For example, this enables special operations (e.g., adding an entry in an Excel file, sending an email or SMS) whenever an order is fully or partially executed, or a specified price is reached.

IB-Matlab also provides functionality that is not available in the basic IB API: the ability to specify automated trading, automatically changing unfulfilled limits based on the momentary bid/ask prices, and changing order types at a certain time.

IB-Matlab is up-to-date with the latest IB API (9.66, from Nov 2011), and the latest IB clients – both the Trading WorkStation (TWS) and the IB Gateway. It works on Matlab 7.1 and above (support for older versions can be provided upon demand). It is compatible with all platforms on which TWS (or the IB Gateway) and Matlab run: Windows (both 32 and 64 bits), Macs, Linux/Unix.

IB-Matlab enables users to connect to TWS or the IB Gateway, on the Matlab’s computer or on a different computer.

IB-Matlab does not transmit any information externally except to IB, so your portfolio and trades information are as safe as your own computer.

Free trial version

A fully-functional free trial version is available upon request – please email me and I will be happy to send you a no-obligations copy and to help you install it on your system.

Documentation

Pricing and support

The license for a single computer for the first year costs $349. This includes installation support, fixing bugs, and any fixes that may be required due to IB API changes.
Annual renewal (including license, support and maintenance) for each following year costs $99.

To purchase the software license ($349), click here.
To purchase the annual renewal ($99), click here.

Please email me if you require volume license pricing or custom development.

A fully-functional free trial version is available upon request – please email me.

I pride myself on providing top-quality software and support. Customer satisfaction is a top priority for me.

Usage syntax

General syntax (quick help reference; detailed user guide):

[orderId,ibConnectionObject] = IBMatlab(varargin)

Possible inputs parameters:

  • varargin = Matlab struct or fieldname/value pairs with the following optional fields:
  • General: LogFileName, MsgDisplayLevel
  • Connection: ClientId, Host, Port
  • Action: (one of Buy, Sell, SShort, Query, Cancel, Account_Data, History_Data, Portfolio_Data or License)
  • Query type: (one of OPEN [for the list of open orders], EXECUTIONS [for the list of today's executions])
  • Order type: (one of MKT, MKTCLS, LMT, LMTCLS, PEGMKT, STP, STPLMT, MIT, TRAIL, REL, TWAP, VWAP, GuarranteedVWAP, TRAILLIMIT, etc. – see full list here and detailed explanations here; note that IB does not allow some combinations of orders and securities)
  • Order data: Action, Quantity, TIF, LimitPrice, AuxPrice, OCAGroup, ParentId, TrailStopPrice, GoodAfterTime, GoodTillDate, BracketDelta, BracketTypes, AccountName, FAProfile, TriggerMethod, OutsideRTH, OrderId, Hold
  • TWAP/VWAP order data: StrategyType, MaxPctVol, StartTime, EndTime, AllowPastEndTime, NoTakeLiq
  • Automated order data: LimitBasis, LimitDelta, LimitRepeatEvery, LimitChangeTime, LimitChangeType, Tick
  • Contract data: Symbol, SecType, Exchange, Currency, LocalSymbol, Expiry, Strike, Right
  • Historical data: EndDateTime, DurationValue, DurationUnits, BarSize, WhatToShow, UseRTH, FormatDate (note IB’s pace limitations)
  • Streaming quotes data: QuotesNumber, QuotesBufferSize, GenericTickList
  • Event callbacks: CallbackFunction, CallbackAccountDownloadEnd, CallbackBondContractDetails, CallbackConnectionClosed, CallbackContractDetails, CallbackContractDetailsEnd, CallbackCurrentTime, CallbackDeltaNeutralValidation, CallbackExecDetails, CallbackExecDetailsEnd, CallbackFundamentalData, CallbackHistoricalData, CallbackManagedAccounts, CallbackMessage, CallbackNextValidId, CallbackOpenOrder, CallbackOpenOrderEnd, CallbackOrderStatus, CallbackTickPrice, CallbackTickSize, CallbackTickString, CallbackTickGeneric, CallbackTickEFP, CallbackTickOptionComputation, CallbackTickSnapshotEnd, CallbackRealtimeBar, CallbackReceiveFA, CallbackScannerData, CallbackScannerDataEnd, CallbackScannerParameters, CallbackUpdateAccountTime, CallbackUpdateAccountValue, CallbackUpdateMktDepth, CallbackUpdateMktDepthL2, CallbackUpdateNewsBulletin, CallbackUpdatePortfolio

Outputs:

  • orderId = -1 if unsuccessful, otherwise the ID of the placed order, or data for ‘QUERY’ actions
  • ibConnectionObject = reference of Java object that interfaces with IB
  • contract = object that holds contract info for Buy/Sell actions when Hold=1 (see example 10 below)
  • order = object that holds order info for Buy/Sell actions when Hold=1 (see example 10 below)

Usage examples

  1) Buy stock

Note the two alternative manners in which the parameters can be specified (you can use whichever is more convenient to you):

% Matlab struct alternative:
paramsStruct = [];
paramsStruct.action     = 'BUY';
paramsStruct.symbol     = 'GOOG';
paramsStruct.quantity   = 100;
paramsStruct.limitPrice = 600;
orderId = IBMatlab(paramsStruct);
 
% Name/value pairs alternative:
orderId = IBMatlab('action','BUY', 'symbol','GOOG', 'quantity',100, 'limitPrice',600);

  2) Sell stock

orderId = IBMatlab('action','SELL', 'symbol','GOOG', 'quantity',100, 'limitPrice',600);

  3) Get market data for a particular stock

>> data = IBMatlab('action','QUERY', 'symbol','GOOG')
data = 
            reqId: 22209874
          reqTime: '02-Dec-2010 00:47:23'
         dataTime: '02-Dec-2010 00:47:23'
    dataTimestamp: 734474.032914491
           ticker: 'GOOG'
         bidPrice: 563.68
         askPrice: 564.47
             open: 562.82
            close: 555.71
              low: 562.4
             high: 571.57
        lastPrice: -1
           volume: 36891
             tick: 0.01
          bidSize: 3
          askSize: 3
         lastSize: 0

  4) Get portfolio data

>> data = IBMatlab('action','PORTFOLIO_DATA')
data =
     1x12 struct array with fields:
        symbol
        localSymbol
        exchange
        secType
        currency
        right
        expiry
        strike
        position
        marketValue
        marketPrice
        averageCost
 
>> data(1)
ans = 
             symbol: 'AMZN'
        localSymbol: 'AMZN'
           exchange: 'NASDAQ'
            secType: 'STK'
           currency: 'USD'
              right: '0'
             expiry: ''
             strike: 0
           position: 9200
        marketValue: 1715800
        marketPrice: 186.5
        averageCost: 169.03183335

  5) Get historical data

Supported Historical data parameters (explanations here): EndDateTime, DurationValue, DurationUnits, BarSize, WhatToShow, UseRTH, FormatDate. Note IB’s pace limitations for historical data.

>> data = IBMatlab('action','HISTORY_DATA', 'symbol','IBM', 'barSize','1 hour', 'useRTH',1)
data =
           dateTime: {1x7 cell}
               open: [161.08 160.95 161.66 161.17 161.57 161.75 162.07]
               high: [161.35 161.65 161.70 161.60 161.98 162.09 162.34]
                low: [160.86 160.89 161.00 161.13 161.53 161.61 161.89]
              close: [160.93 161.65 161.18 161.60 161.74 162.07 162.29]
             volume: [5384 6332 4580 2963 4728 4465 10173]
              count: [2776 4387 2990 1921 2949 2981 6187]
                WAP: [161.07 161.25 161.35 161.31 161.79 161.92 162.14]
            hasGaps: [0 0 0 0 0 0 0]
 
>> data.dateTime
ans = 
        '20110225  16:30:00'   '20110225  17:00:00'   '20110225  18:00:00'   '20110225  19:00:00'
        '20110225  20:00:00'   '20110225  21:00:00'   '20110225  22:00:00'

  6) Get account data

>> data = IBMatlab('action','ACCOUNT_DATA')
data =
                   AccountCode: 'DU12345'
                      currency: []
                   accountName: 'DU12345'
                  AccountReady: 'true'
                   AccountType: 'INDIVIDUAL'
                   AccruedCash: -456.4
               AccruedDividend: 0
                AvailableFunds: 261700.68
                      Billable: 0
                   BuyingPower: 779656.96
                   CashBalance: -825400.37
            CorporateBondValue: 0
                      Currency: 'USD'
                       Cushion: 0.361508
            DayTradesRemaining: -1
    DayTradesRemainingT_plus_1: -1
    DayTradesRemainingT_plus_2: -1
    DayTradesRemainingT_plus_3: -1
    DayTradesRemainingT_plus_4: -1
           EquityWithLoanValue: 723913.41
               ExcessLiquidity: 261700.68
                  ExchangeRate: 1
            FullAvailableFunds: 261700.68
           FullExcessLiquidity: 261700.68
             FullInitMarginReq: 462212.73
            FullMaintMarginReq: 462212.73
                     FundValue: 0
             FutureOptionValue: 0
                    FuturesPNL: 0
                 FxCashBalance: 0
            GrossPositionValue: 1540709.11
            IndianStockHaircut: 0
                 InitMarginReq: 462212.73
                      Leverage: 2.13
       LookAheadAvailableFunds: 261700.68
      LookAheadExcessLiquidity: 261700.68
        LookAheadInitMarginReq: 462212.73
       LookAheadMaintMarginReq: 462212.73
           LookAheadNextChange: 0
                MaintMarginReq: 462212.73
          MoneyMarketFundValue: 0
               MutualFundValue: 0
                   NetDividend: 0
                NetLiquidation: 723913.41
      NetLiquidationByCurrency: 714852.34
             OptionMarketValue: 0
                 PASharesValue: 0
                           PNL: 'true'
PreviousDayEquityWithLoanValue: 696109.82
                   RealizedPnL: 0
                    RegTEquity: 723913.41
                    RegTMargin: 770354.56
                           SMA: 78512.41
              StockMarketValue: 1540709.11
                    TBillValue: 0
                    TBondValue: 0
              TotalCashBalance: -825400.37
                TotalCashValue: -816339.3
                   TradingType: 'STKNOPT'
        UnalteredInitMarginReq: -1
       UnalteredMaintMarginReq: -1
                 UnrealizedPnL: -40731.17
                  WarrantValue: 0
               WhatIfPMEnabled: 'true'

  7) Get streaming quotes data

The initial request to send streaming quotes:

>> reqId = IBMatlab('action','QUERY', 'symbol','EUR', 'localsymbol','EUR.USD', ...
                    'currency','USD', 'sectype','cash', 'exchange','idealpro', 'QuotesNumber',100)
reqId = 
   147898050

Subsequent requests to retrieve the latest accumulated QuotesBuffer data return a dataStruct that looks like this:

>> dataStruct = IBMatlab('action','QUERY', 'symbol','EUR', 'localsymbol','EUR.USD', 'QuotesNumber',-1)
dataStruct = 
               reqId: 147898050
              symbol: 'EUR'
         localSymbol: 'EUR.USD'
            isActive: 1
      quotesReceived: 6
     quotesToReceive: 10
    quotesBufferSize: 1
     genericTickList: ''
                data: [1x1 struct]
            contract: [1x1 com.ib.client.Contract]

Note that you only need to specify the Symbol/LocalSymbol and the QuotesNumber in the subsequent requests, all other parameters are unnecessary since the system already knows about this symbol’s parameters from the initial streaming request.

To get the actual data, simply read the data field of this dataStruct:

>> dataStruct.data
ans =
        dataTimestamp: 734892.764653854
                 high: 1.3061
        highTimestamp: 734892.762143183
                  low: 1.29545
         lowTimestamp: 734892.762143183
                close: 1.30155
       closeTimestamp: 734892.762143183
             bidPrice: 1.2986
    bidPriceTimestamp: 734892.764653854
              bidSize: 1000000
     bidSizeTimestamp: 734892.764653854
             askPrice: 1.29865
    askPriceTimestamp: 734892.764499421
              askSize: 18533000
     askSizeTimestamp: 734892.764653854

Note that each data item has an associated timestamp, because different data items are sent separately from the IB server. You can convert the timestamps into human-readable string by using Matlab’s datestr function, as follows:

>> datestr(dataStruct.data.dataTimestamp)
ans =
24-Jan-2012 23:56:32

If instead of using QuotesBufferSize=1 (which is the default value), I had used QuotesBufferSize=4, then I would see not the latest quote but the latest 4 quotes:

>> reqId = IBMatlab('action','QUERY', 'symbol','EUR', 'localsymbol', 'EUR.USD', 'currency','USD', ...
                    'sectype','cash', 'exchange','idealpro', 'QuotesNumber',10, 'QuotesBufferSize',4);
 
% now at any following point in time run the following command to get the latest 4 quotes:
>> dataStruct = IBMatlab('action','QUERY', 'localsymbol','EUR.USD', 'QuotesNumber',-1);
>> dataStruct.data
ans = 
        dataTimestamp: [734892.99760235 734892.99760235 734892.99760235 734892.997756076]
                 high: 1.3061
        highTimestamp: 734892.99740162
                  low: 1.29545
         lowTimestamp: 734892.99740162
             bidPrice: [1.3035 1.30355 1.3035 1.30345]
    bidPriceTimestamp: [734892.99760235 734892.99760235 734892.99760235 734892.997756076]
              bidSize: [3000000 2000000 4000000 4000000]
     bidSizeTimestamp: [734892.997743958 734892.997756076 734892.997756076 734892.997756076]
             askPrice: [1.3036 1.30355 1.3036 1.30355]
    askPriceTimestamp: [734892.997523681 734892.997667824 734892.997667824 734892.997756076]
              askSize: [2153000 3153000 2153000 4153000]
     askSizeTimestamp: [734892.997756076 734892.997756076 734892.997756076 734892.997756076]
                close: 1.30155
       closeTimestamp: 734892.997407037

Note that the high, low and close fields are only sent once by the IB server, as we would expect. Only the bid and ask information is sent as a continuous stream of data from the IB server.

  8) Specify event callback – ExecDetails

Attach a user callback function to ExecDetails events (that occur upon any order execution – more details here):

orderId = IBMatlab('action','BUY', 'symbol','GOOG', 'quantity',1, 'limitPrice',600, ...
                   'CallbackExecDetails',@IBMatlab_CallbackExecDetails);

where the function IBMatlab_CallbackExecDetails is defined as follows (for example, in a file called IBMatlab_CallbackExecDetails.m):

% See: http://www.interactivebrokers.com/php/apiUsersGuide/apiguide/java/execdetails.htm
%      http://www.interactivebrokers.com/php/apiguide/interoperability/activex_other/activexevents.htm#execDetails
function IBMatlab_CallbackExecDetails(hObject, eventData, varargin)
 
   % Extract the basic event data components
   contractData  = eventData.contract;
   executionData = eventData.execution;
 
   % Example of extracting data from the contract object:
   % See: http://www.interactivebrokers.com/php/apiUsersGuide/apiguide/java/contract.htm
   symbol  = char(eventData.contract.m_symbol);
   secType = char(eventData.contract.m_secType);
   % ... and several other contract data available - see the above webpage
 
   % Example of extracting data from the execution object:
   % http://www.interactivebrokers.com/php/apiUsersGuide/apiguide/java/execution.htm
   orderId     = eventData.execution.m_orderId;
   execId      = char(eventData.execution.m_execId);
   time        = char(eventData.execution.m_time);
   exchange    = char(eventData.execution.m_exchange);
   side        = char(eventData.execution.m_side);
   shares      = eventData.execution.m_shares;
   price       = eventData.execution.m_price;
   permId      = eventData.execution.m_permId;
   liquidation = eventData.execution.m_liquidation;
   cumQty      = eventData.execution.m_cumQty;
   avgPrice    = eventData.execution.m_avgPrice;
   % ... and several other contract data available - see the above webpage
 
   % Now do something useful with all this information...
 
end  % IBMatlab_CallbackExecDetails

  9) Specify event callback – TickGeneric

Attach a user callback function to TickGeneric events in order to check whether a security is shortable

Note: according to IB, “Generic Tick Tags cannot be specified if you elect to use the Snapshot market data subscription“, and therefore we need to use the streaming-quotes mechanism, so QuotesNumber>1:

orderId = IBMatlab('action','Query', 'symbol','GOOG', 'GenericTicklist','236', 'QuotesNumber',2, ...
                   'CallbackTickGeneric',@IBMatlab_CallbackTickGeneric);

where the function IBMatlab_CallbackTickGeneric is defined as follows:

% See: http://www.interactivebrokers.com/php/apiUsersGuide/apiguide/java/tickgeneric.htm
%      http://www.interactivebrokers.com/php/apiguide/interoperability/activex_other/activexevents.htm#tickGeneric
function IBMatlab_CallbackTickGeneric(hObject,eventData,varargin)
 
    % Only check the shortable tick type =46, according to 
    % http://www.interactivebrokers.com/php/apiUsersGuide/apiguide.htm#apiguide/api/tick_values.htm%23XREF_tick_values_generic_tick
    if eventData.field == 46  % 46=Shortable
 
        % Get this event's tickerId (=orderId as returned from the original IBMatlab command)
        tickerId = eventData.tickerId;
 
        % Get the corresponding shortable value
        shortableValue = eventData.generic;
 
        % Now check whether the security is shortable or not
        title = sprintf('Shortable info for request %d', tickerId);
        if (shortableValue > 2.5)      % 3.0
            msgbox('There are at least 1000 shares available for a short sale', title, 'help');
        elseif (shortableValue > 1.5)  % 2.0
            msgbox('This contract will be available for short sale if shares can be located', title, 'warn');
        elseif (shortableValue > 0.5)  % 1.0
            msgbox('Not available for short sale', title, 'warn');
        else
            msgbox(sprintf('Unknown shortable value: %g',shortableValue), title, 'error');
        end
    end  % if shortable tickType
 
end  % IBMatlab_CallbackTickGeneric

  10) Using the underlying Java connection object

Cancel an open order (one example of the many possible actions that can be done via ibConnectionObject):

% Place an order, return the orderId and the Java connector object
[orderId, ibConnectionObject] = IBMatlab('action','BUY', ...);
 
% Cancel the order using the underlying Java connector object:
ibConnectionObject.cancelOrder(orderId);
 
% Alternatively, cancel the order using the Matlab wrapper:
IBMatlab('action','CANCEL', 'orderId',orderId);

Holding and modifying a Buy/Sell trade order before submitting:

% Prepare the order
[orderId, ibConnectionObject, contract, order] = IBMatlab('action','BUY', 'Hold',1, ...);
 
% Modify some contract and/or order parameters
contract.m_secIdType = 'ISIN';
contract.m_secId = 'US0378331005';  % =Apple Inc.
order.m_clearingIntent = 'Away';
order.m_settlingFirm = 'CSBLO';
order.m_allOrNone = true;
 
% Send the modified order to IB
ibConnectionObject.placeOrder(orderId, contract, order);

Legal disclaimer:

THIS SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments are closed.