9 Specialized trade orders
Several specialized order types are supported by IBMatlab, each of which has dedicated parameters for configuration. These order types include VWAP (best effort), TWAP, bracket orders, automated orders, combo orders, and options exercise/lapse.
9.1 VWAP (best-effort) orders
When the order Type is ‘VWAP’ (the best-effort type, since the guaranteed type has Type='GuaranteedVWAP'), IB treats the order as a Market order with a VWAP algo strategy.94 IBMatlab enables specifying the algo strategy’s properties, as follows:
Parameter | Data type | Default | Description |
Type | String | 'LMT' | Set to 'VWAP' for this IBAlgo type |
MaxPctVol | number | 0.1=10% | Percent of participation of average daily volume up to 0.5 (=50%). |
StartTime | String | '9:00:00 EST' | Format: 'YYYYMMDD hh:mm:ss TMZ' (TMZ is optional) |
EndTime | String | '16:00:00 EST' | (same as StartTime above) |
AllowPastEndTime | integer or logical flag | 1=true | If true, allow the algo to continue to work past the specified EndTime if the full quantity has not been filled. |
NoTakeLiq | integer or logical flag | 0=false | If true, discourage the VWAP algo from hitting the bid or lifting the offer if possible. |
SpeedUp | integer or logical flag | 0=false | If true, compensates for the decreased fill rate due to presence of limit price. |
MonetaryValue | number | 0 | Cash quantity |
Here is an example for specifying a best-effort VWAP trade order:
orderId = IBMatlab('action','SELL','symbol','GOOG','quantity',10,...
'type','VWAP','limitPrice',600,'MaxPctVol',0.3,...
'StartTime','20120215 10:30:00 EST', ...
'EndTime', '10:45:00 EST', ...
'AllowPastEndTime',false, ...
'NoTakeLiq',true);
When we run the command above in Matlab, we see the following in IB’s TWS:
Note that IB automatically routes the trade to its internal servers (IBALGO) rather than directly to the relevant exchange as it would do in most other cases. Also note that the VWAP order is NOT guaranteed to execute. Best-effort VWAP algo orders result in lower commissions than the Guaranteed VWAP, but the order may not fully execute and is not guaranteed, so if you need to ensure this, use Guaranteed VWAP.
StartTime and EndTime dictate when the VWAP algo will begin/end working, regardless of whether or not the entire quantity has been filled. EndTime supersedes the TIF (time in force) parameter. Note that the order will automatically be cancelled at the designated EndTime regardless of whether the entire quantity has filled unless AllowPastEndTime=1. If an EndTime is specified, then set AllowPastEndTime=1 (or true) to allow the VWAP algo to continue to work past the specified EndTime if the full quantity has not been filled.
Note: If you specify and StartTime and EndTime, TWS confirms the validity of the time period using yesterday’s trading volume. If the time period you define is too short, you will receive a message with recommended time adjustments.
In the example above, note the optional date (20120215) in StartTime. In the EndTime parameter no date was specified so today’s date will be used, at 10:45 EST.
The time-zone part is also optional, but we strongly recommend specifying it, to prevent ambiguities. Only a few major time zones are accepted; you can always convert a time to one of these time zones. The list of IB-supported time-zones is given below:95
Time zone supported by IB | Description |
GMT | Greenwich Mean Time |
EST | Eastern Standard Time |
MST | Mountain Standard Time |
PST | Pacific Standard Time |
AST | Atlantic Standard Time |
JST | Japan Standard Time |
AET | Australian Eastern Standard Time |
Setting the NoTakeLiq parameter value to true (or 1) may help to avoid liquidity-taker fees, and could result in liquidity-adding rebates. But it may also result in greater deviations from the benchmark and partial fills, since the posted bid/offer may not always get hit as the price moves up/down. IB will use best efforts not to take liquidity, however, there will be times that it cannot be avoided.
VWAP orders are treated as LMT orders so the LimitPrice parameter is mandatory.96
Note: IB only enables VWAP algo orders for US equities on live accounts (i.e., not on paper-trading accounts97).
9.2 TWAP (best-effort) orders
When the order Type is ‘TWAP’, IB treats the order as a Limit order with a TWAP algo strategy.98 IBMatlab enables specifying the algo strategy’s properties, as follows:
Parameter | Data type | Default | Description |
Type | string | 'LMT' | Set to 'TWAP' for this IBAlgo type |
StrategyType | string | 'Marketable' | One of: 'Marketable' (default) 'Matching Midpoint' 'Matching Same Side' 'Matching Last' |
StartTime | string | '9:00:00 EST' | Format: 'YYYYMMDD hh:mm:ss TMZ' (TMZ is optional) |
EndTime | string | '16:00:00 EST' | (same as StartTime above) |
AllowPastEndTime | integer or logical flag | 1=true | If true, allow the algo to continue to work past the specified EndTime if the full quantity has not been filled. |
Note: StartTime, EndTime and AllowPastEndTime were described in §9.1.
Here is an example for specifying a TWAP trade order:
orderId = IBMatlab('action','SELL', 'symbol','GOOG', 'quantity',10,...
'type','TWAP', 'limitPrice',600, ...
'StrategyType','Matching Last', ...
'StartTime','20120215 10:30:00 EST', ...
'EndTime', '10:45:00 EST', ...
'AllowPastEndTime',false);
Note that, as with VWAP, IB automatically routes the trade to its internal servers (IBALGO) rather than directly to the relevant exchange as it would do in most other cases. Also note that the TWAP order is NOT guaranteed to execute. The order will trade if and when the StrategyType criterion is met.
Note: IB only enables TWAP algo orders for US equities.
9.3 Bracket (child) orders
Bracket orders are trades which aim to limit losses while locking-in profits, by sending two opposite-side child orders to offset a parent order.99 This mechanism ensures that the child orders are made active only when the parent order executes.
Both of the bracket child orders have the same amount as the parent order, and belong to the same OCA (One-Cancels-All) group, so that if one of the child orders is triggered and gets executed, the opposing order is automatically cancelled. Similarly, canceling the parent order will automatically cancel all its child orders.
Buy orders are bracketed by a high-side sell Limit (Type='LMT') order and a low-side sell Stop (Type='STP') order; Sell orders are bracketed by a high-side buy Stop order and a low side buy Limit order.
In IB-Matlab, brackets can only be assigned to parent Buy or Sell orders having Type='LMT' or 'STPLMT'. Specifying bracket orders is very simple, using the BracketDelta parameter. This parameter (default=[] = empty) accepts a single number value or an array of two numeric values, which specify the offset from the parent order’s LimitPrice:
If BracketDelta is a 2-value array [lowerDelta,upperDelta], then lowerDelta is used as the offset for the lower child, and upperDelta is used for the upper child. The corresponding child order limits will be set to LimitPrice-lowerDelta and LimitPrice+upperDelta, respectively.
If BracketDelta is a single (scalar) value, then this value is used as offset for both child orders: LimitPrice-offset and LimitPrice+offset, respectively.
IBMatlab returns the orderId of the parent order; the child orders have order IDs that are orderId+1 and orderId+2, respectively.
For example, the following trade order:
parentOrderId = IBMatlab('action','BUY', 'symbol','GOOG', ...
'quantity',100, 'type','LMT', ...
'limitPrice',600, 'BracketDelta',[20,50]);
Will result in the following situation in IB:
In this screenshot, notice that the parent order is shown as active (blue; IB status: “Order is being held and monitored”) at the bottom. This order has a Last-Key value of “4” and is a simple Buy at Limit 600 order.
The child orders are shown above their parent as inactive (red; IB status: “Waiting for parent order to fill”). These orders have type=LMT (for the 650 take-profit order) and STP (for the 580 stop-loss order). Note that the child orders have a Last-Key value that derives from their parent (4.2, 4.1 respectively) and the same OCA group name, which is automatically generated based on the order timestamp.
It is possible to specify child bracket orders of different types than the default LMT and STP. This can be done using the BracketTypes parameter. For example, to set an upper bracket of type MIT (Market-If-Touched) rather than LMT for the preceding example, we could do as follows:
parentOrderId = IBMatlab('action','BUY', 'symbol','GOOG', ...
'quantity',100, 'type','LMT', ...
'limitPrice',600, 'BracketDelta',[20,50], ...
'BracketTypes',{'STP','MIT'});
Another method to achieve this modification would be to use the relevant child order ID (which is parentOrderId+2 for the upper child) and modify its type from LMT to MIT (see §10.2 below for details).
The following parameters specifically affect bracket orders:
Parameter | Data type | Default | Description |
BracketDelta | number | []=empty | Price offset for stop-loss and take-profit bracket child orders. Note: BracketDelta may be a single value or a [lowerDelta,upperDelta] pair of values Note: value(s) must be positive: |
BracketTypes | cell array of 2 strings | Buy: {'STP', 'LMT'} Sell: {'LMT', 'STP'} | Types of child bracket orders. The first string in the cell array defines the order type for the lower bracket; the second string defines the order type for the upper bracket. See related BracketDelta parameter above. |
As an alternative to using IBMatlab’s BracketDelta and BracketTypes, users can also create child orders directly, thereby creating non-standard bracket setups, using the ParentId, OCAType and OCAGroup parameters. The Transmit parameter (§9.6) is also typically used, to ensure that the parent order is not transmitted before the child orders are attached.
For example, the following code snippet creates a parent order with 3 child orders: a take-profit order, a stop-loss order, and an end-of-day exit order:100
% First create (but do not transmit) the parent order
parentId = IBMatlab('action','BUY', 'symbol','GOOG', ...
'quantity',100, 'type','LMT', ...
'LimitPrice',600, 'transmit',false);
% Attach a take-profit child order
takeProfitId = IBMatlab('action','SELL', 'symbol','GOOG', ...
'quantity',100, 'type','MIT', 'AuxPrice',650,...
'ParentId', parentId, ...
'OCAType',3 ,'OCAGroup','abc #123');
% Attach a stop-loss child order
stopLossId = IBMatlab('action','SELL', 'symbol','GOOG', ...
'quantity',100, 'type','STP', 'AuxPrice',580,...
'ParentId', parentId, ...
'OCAType',3 ,'OCAGroup','abc #123');
% Attach an end-of-day exit child order
eodExitId = IBMatlab('action','SELL', 'symbol','GOOG', ...
'quantity',100, 'type','MOC', ...
'ParentId', parentId, ...
'OCAType',3 ,'OCAGroup','abc #123');
% Pause a bit to enable IB time to process the orders
pause(0.5);
% Transmit the modified parent order
IBMatlab('action','BUY', 'orderId',parentId, 'transmit',true, ...
'symbol','GOOG', 'quantity',100, ...
'type','LMT', 'LimitPrice',600);
9.4 Automated orders
Automated orders are similar to orders of types REL and TRAIL. The idea is to modify a Limit order’s LimitPrice based on instantaneous market bid and ask quotes plus (or minus) a certain number of security tick value. At a certain point in time, the order, if not fulfilled or cancelled by then, can automatically be transformed from LMT to some other type (e.g., MKT).
IBMatlab implements automated orders using a timer that periodically checks the latest bid/ask quotes for the specified security and modifies the order’s LimitPrice (and possibly the order Type) accordingly.
Unlike IB’s REL and TRAIL order types (and their variants, e.g., TRAIL MIT etc.), which update the LimitPrice continuously, IBMatlab’s automated orders are only updated periodically. This could be problematic for highly-volatile securities: in such cases users should use IB’s standard REL and TRAIL. However, for low-volatility securities, the flexibility offered by IBMatlab’s automated orders could be useful.
The following parameters affect automated orders in IBMatlab:
Parameter | Data type | Default | Description |
LimitBasis | string | (none) | Either 'BID' or 'ASK'. LimitBasis cannot be used together with LimitPrice. |
LimitDelta | integer | 0 | Units of the security’s minimal tick value |
LimitBounds | [number, number] | [0,inf] | The LimitPrice will only fluctuate between the specified lower & upper bounds |
LimitRepeatEvery | number | 0 | Update timer period in seconds |
LimitPause | number | 0 | Update timer suspend time in seconds |
LimitUpdateMode | number | 0 | Mode of the periodic LimitPrice update: 0: LimitPrice increases or decreases based on the latest market bid/ask price 1: LimitPrice only increases; if market price decreases, LimitPrice remains as-is -1: LimitPrice only decreases; if the price increases, LimitPrice remains as-is |
LimitChangeTime | string | (now+ | Time at which to change the order Type automatically, if it was not fulfilled or cancelled by then. Format: 'YYYYMMDD hh:mm:ss' local time |
LimitChangeType | string | 'MKT' | The new order type to be used at LimitChangeTime |
Tick | number | 0 | Override the security’s reported tick value, used by LimitDelta. This is useful for securities/exchanges that do not report a valid tick value in market queries (see §5.1). |
IBMatlab uses Matlab timers for the implementation of automated orders having LimitRepeatEvery > 0. These timers invoke their callback function once every LimitRepeatEvery seconds. In each invocation, the current market data for the security is checked against the specifications (LimitUpdateMode, LimitBounds etc.). If it is determined that the trade order should be modified, then an update command is sent to the IB server with the new LimitPrice (see §10.2 below). This process could take some time and therefore it is strongly suggested to use a LimitRepeatEvery value larger than 5 or 10 [secs], otherwise Matlab might use a large percent of its CPU time in these timer callbacks. Each automated order uses an independent timer, so having multiple concurrent automated orders would only exasperate the situation. Therefore, the more such concurrent orders you have, the longer LimitRepeatEvery should be.
Note: using IBMatlab’s automated orders, implied by setting a non-empty LimitBasis parameter value, automatically sets the order type to LMT, regardless of the order Type requested by the user. LimitPrice cannot be used together with LimitBasis.
For example, the tick value for GOOG is 0.01. To send a Limit BUY order, which is updated to BID – 2 ticks (i.e., BID – 0.02) every 15 seconds, run the following:
orderId=IBMatlab('action','BUY', 'symbol','GOOG', 'quantity',100,...
'type','LMT', 'LimitBasis','BID',...
'LimitDelta',-2, 'LimitRepeatEvery',15);
When trying to use the automated orders feature, you may discover that the limit price is not updated although the market price moves up or down. In most likelihood, this is due to the tick price not being available for some reason, and the simple solution is to specify it directly using the Tick parameter:
orderId=IBMatlab('action','BUY', 'symbol','GOOG', 'quantity',100,...
'type','LMT', 'LimitBasis','BID', 'tick',0.01,...
'LimitDelta',-2, 'LimitRepeatEvery',15);
The LimitPause parameter enables a suspension of the order for the specified duration between each timer invocation. At the beginning of each suspension, the order is cancelled. At the end of each suspension, the order is resubmitted with updated LimitPrice and Quantity (depending on the number of executed Quantity until that time). For example, if LimitRepeatEvery=15 and LimitPause=3, then the order will be active between t=0 and t=15, then again between t=18 and t=33, then again between t=36 and t=51, and so on.
High frequency traders often game REL and various types of pegged orders, e.g., by temporarily causing price to move up or down such that these orders trigger at less than optimal prices. Order delays reduce this possibility, as temporary price movements may revert before the order is re-released. The regular periodic update feature (LimitRepeatEvery) helps in this regard, but using LimitPause would increase the possibility of price improvement (e.g., for a buy order the price could drop below the original bid).
9.5 Combo orders
IB enables traders to trade a spread of securities as a single atomic combination (combo) order. For example, a trader might trade a calendar spread of some security options or futures, e.g. Sell November, Buy December. Each of these securities (legs) is treated separately, but the combination is treated as a single entity. Combo-orders typically improve trading certainty, reduce risk of partial or mis-executions, and reduce the trading costs significantly compared to trading the securities separately.
To use combo-trades in IBMatlab, specify the leg parameters (Symbol, LocalSymbol, SecType, Exchange, Currency, Multiplier, Expiry, Strike, and Right) in a cell array wherever the different legs have different values. In addition, you must specify the ComboActions parameter:
orderId = IBMatlab('action','buy', 'exchange','CFE', 'quantity',1, ...
'SecType','FUT', 'LocalSymbol',{'VXZ2','VXX2'}, ...
'ComboActions',{'Buy','Sell'})
Alternatively, you could use cell arrays also for the fields that are the same for all legs. The following is equivalent to the command above:
orderId = IBMatlab('action','buy', 'exchange',{'CFE','CFE'}, ...
'quantity',1, 'SecType',{'FUT','FUT'}, ...
'LocalSymbol',{'VXZ2','VXX2'}, ...
'ComboActions',{'Buy','Sell'})
The same syntax can be used for querying the market data of a specific combo:
data = IBMatlab('action','query', 'exchange','GLOBEX', ...
'secType','FUT', 'localSymbol',{'ESZ2','ESH3'}, ...
'ComboActions',{'Sell','Buy'}
Note that querying market data for a combo might well return negative prices. For example, in the specific query example above, the following data was received:
data =
reqId: 230455081
reqTime: '26-Oct-2012 04:24:22'
dataTime: '26-Oct-2012 04:24:23'
dataTimestamp: 7.3517e+05
ticker: ''
bidPrice: -6.8500
askPrice: -6.7500
bidSize: 748
askSize: 287
open: -1
close: -1
low: -1
high: -1
lastPrice: -1
volume: -1
tick: 0.2500
contract: [1x1 struct]
contractDetails: [1x2 struct]
Only instantaneous market bid/ask data is reliably returned for combo queries – the open, close, low, high, lastPrice and volume fields are often returned empty (-1).
IB may rejects combo requests (query/trade), due to a variety of possible reasons:
IB only supports combos for a small subset of securities – generally speaking, US options and futures. For example, Forex is NOT supported as of 2016.
IB will reject a combo that has been incorrectly configured (see details below)
IB will reject a combo if you are not subscribed for real-time quotes for any of its legs.
IB does not support combos on the demo account, only on live and paper-trade accounts.101 The availability of combo functionality may depend on your IB account’s subscription plan and the specific combo that you try to use.
Some combo queries can only be received using streaming quotes (§7.1), but not snapshot quotes (§5.1), due to an IB server bug/limitation. A workaround for this limitation is included in IB-Matlab since version 1.97.
In all such cases, query requests will return -1 data in all data fields, including bidPrice/askPrice; trade order commands will simply be ignored by IB.
Unfortunately, IB does not report an informative error message when a combo trade order or market query is rejected. We are left guessing as to the reason: perhaps one or more legs is incorrectly configured or not supported or not subscribed for real-time data; perhaps the market is closed; etc. Contact IB to check your specific case.
When specifying combo legs, you can specify the optional ComboRatios parameter, as an array of positive values that shall be used to determine the relative weights of the legs. IBMatlab uses default ratios of [1,1], i.e. the same ratio for all legs.102
When specifying combo legs, we need to be aware of exchange limitations. In general combos use the default ratio of 1:1, but in some cases some other ratio is needed. For example, the ComboRatios for the ZN/ZT spread (10-vs-2-year US Treasury-Notes) must be set to 1:2 since the ECBOT exchange does not currently (1/1/2016) support any other ratio. This ratio changes over time: the ratio was 1:2 in early 2013, then changed to 3:5, then 1:2 again.103 If you specify an incorrect ratio, or when the market is closed, IB will send an ICS (Inter-Commodity Spread) error message. For example:
[API.msg2] Invalid ICS spread {360280114, 318}
In cases where you cannot figure out the exact set of parameters for a combo, it might help to try to create the combo directly in TWS: If the combo is supported by TWS then it might also be available to the API (and IBMatlab). But if the combo is not supported by TWS then it will also certainly not work in IBMatlab.
The combo legs must all use the same exchange and generally also the same currency. However, combo legs do not need to have the same underlying security Symbol. If you wish to use a combo spread of two securities with a different symbol, you could use the internal symbol for the spread using the ComboBagSymbol parameter. For example, the ZN/ZT spread has the internal symbol ‘TUT’:104
IBMatlab('action','query', 'SecType','FUT', 'exchange','ECBOT', ...
'ComboBagSymbol','TUT', ... % the spread's symbol is TUT
'LocalSymbol',{'ZN MAR 16','ZT MAR 16'}, ...
'ComboActions',{'Sell','Buy'}, 'ComboRatios',[1,2])
ans =
reqId: 576662704
reqTime: '24-Dec-2015 05:18:49'
dataTime: '24-Dec-2015 05:18:53'
dataTimestamp: 7.3632e+05
lastEventTime: 7.3632e+05
ticker: ''
bidPrice: -0.0078
askPrice: 0.0078
open: -1
close: 0
low: 0.0078
high: 0.0078
lastPrice: 0.0078
volume: -1
halted: 0
tick: 0.0078
contract: [1x1 struct] <= Note: legs info in comboLegs field
contractDetails: [1x2 struct] <= Note: contractDetails for 2 legs
bidSize: 592
askSize: 25
lastSize: 2
lastTimestamp: '1450947638'
Sometimes IB fails to return snapshot query data for combos (as for TUT above), due to IB server limitations/bugs. In such cases, using streaming quotes (see Chapter 7) may be a good workaround:
IBMatlab('action','query', 'SecType','FUT', 'exchange','ECBOT', ...
'ComboBagSymbol','TUT', ... % the spread's symbol is TUT
'LocalSymbol',{'ZN MAR 13','ZT MAR 13'}, ...
'ComboActions',{'Sell','Buy'}, 'ComboRatios',[1,2], ...
'QuotesNumber',2);
pause(1.5); % wait a bit for data to be received from IB server
data = IBMatlab('action','query', 'QuotesNumber',-1, ...
'LocalSymbol',{'ZN MAR 13','ZT MAR 13'});
When specifying the spread’s LocalSymbol, be careful to enter all the spaces. For example, the ZN LocalSymbol has 4 spaces between “ZN” and “MAR”. IB is very sensitive about this: if you specify a LocalSymbol that is even slightly incorrect, IB will complain that it cannot find the specified contract. See §14.2 for additional details.
To complete the picture, here’s an example order to purchase a bear spread for 9/2018 E-mini S&P 500 Future Options (SecType='FOP'; note the negative LimitPrice):
orderId = IBMatlab('action','buy', 'exchange','GLOBEX', 'quantity',1,...
'SecType','FOP', 'type','LMT', 'limitPrice',-4, ...
'symbol','ES', 'expiry',201809, 'right','Call', ...
'strike',[2720,2730], 'ComboActions',{'Sell','Buy'})
or alternatively:
orderId = IBMatlab('action','buy', 'exchange','GLOBEX', 'quantity',1,...
'SecType','FOP', 'type','LMT', 'limitPrice',-4, ...
'localSymbol', {'ESU8 C2720', 'ESU8 C2730'}, ...
'ComboActions',{'Sell','Buy'})
The following parameters affect combo orders in IBMatlab:
Parameter | Data type | Default | Description |
Symbol | string or cell-array of strings | (none) | The symbol(s) of the underlying leg assets. |
LocalSymbol | string or cell-array of strings | '' | The local exchange symbol of the underlying leg asset. If left empty, IB tries to infer it from the other parameters. |
SecType | string or cell-array of strings | 'STK' | One of: 'STK', 'OPT', 'FUT', 'IND', 'FOP' (but not 'CASH' or 'BAG') for the legs. |
Exchange | string or cell-array of strings | 'SMART' | The exchange that should process the request for the corresponding legs. |
Currency | string or cell-array of strings | 'USD' | The currency for the corresponding legs. |
Multiplier | number | [] | The contract multiplier (for options) |
Expiry | string or cell-array of strings | '' | 'YYYYMM' or 'YYYYMMDD' format, for each of the combo legs. |
Strike | number or numeric array | 0.0 | The strike price (for options) of the corresponding legs. |
Right | string or cell-array of strings | '' | One of: ‘P’, ‘PUT’, ‘C’, ‘CALL’ for each of the combo legs. |
ComboActions | cell-array of strings | {} | Array of corresponding leg actions. For example: {'Sell', 'Buy'} |
ComboRatios | numeric array of positive numbers | [1,1] | Array of corresponding leg weights. Any number is accepted – only the relative values matter, so [1,1.5]=[2,3]=[4,6]. |
ComboBag | string | '' | The exchange symbol of the combo-bag spread. When left empty, IBMatlab will use the last leg’s LocalSymbol and Symbol for the parent bag contract. |
9.6 Setting special order attributes
Most of the important order parameters that are supported by IB are also supported as IBMatlab parameters. However, IB also supports additional properties that in some cases may be important.
For example, we may wish to specify the security identifier (via the contract object’s secIDType and secId properties105), or to specify the All-or-None flag (via the order object’s allOrNone property106).
These properties are not available as IBMatlab parameters, but they can still be specified using the ibConnector Java object returned by IBMatlab as a second output value, as explained in §15 below. The contract and order objects can be created and updated in two alternative ways:
We can use ibConnector to create the initial contract and order Java objects, modify their requested properties, then use ibConnector again to send the order to IB. §15.3 shows a usage example of this.
We can use IBMatlab’s Hold parameter (see §8.1) to prepare the contract and order Java objects, modify their properties, then use ibConnector to send the order to IB. The difference vs. the previous method is that we don’t need to create the contract/order objects – IBMatlab takes care of this for us.
In all cases, we would use the ibConnector.placeOrder function to send the updated contract and order objects to IB for execution. Here is a usage example:107
% Prepare initial contract and order objects using the Hold mechanism
[orderId, ibConnector, contract, order] = ...
IBMatlab('action','BUY', 'Hold',true, ...);
% Modify some contract properties
contract.m_secIdType = 'ISIN';
contract.m_secId = 'US0378331005'; % =Apple Inc.
contract.m_multiplier = '100'; % only relevant for option/future
% Modify some order properties
order.m_clearingIntent = 'Away'; % Possible values: IB, Away, PTA
order.m_settlingFirm = 'CSBLO'; % =Credit Suisse Securities Europe
order.m_allOrNone = true; % set the order to be All-or-None
order.m_sweepToFill = true; % set the order to be Sweep-to-Fill
order.m_orderRef = 'my trading algo'; % user-specified trading note
% Send the modified order to IB
ibConnector.placeOrder(orderId, contract, order);
Note: the order object is only returned from IBMatlab for trading orders (i.e., Action = 'Buy', 'Sell', 'SShort' or 'SLong'), but not other IBMatlab actions.
Some additional order fields that can be set in this manner include:
m_hidden – true for a hidden order routed via the INet (Island) exchange108
m_displaySize –integer >0 for an Iceberg order109
m_volatility – value >0 for specifying option limit price in terms of volatility [percent], typically used together with m_volatilityType [1=daily, 2=annual]
additional contract and order fields are listed in IB’s API documentation110
Note: field names of IB’s Java objects (e.g. contract, order) have a m_ prefix (e.g. contract.m_secId, order.m_orderRef). IB-Matlab v2.19 onward reports such objects as Matlab structs without the m_ prefix (e.g. contract.secId, order.orderRef) when returning data (see §5), but whenever we use the Java objects we need to add the m_ prefix to the field names. In the example above, contract and order are Java objects, so we must use the m_ prefix of field names to modify the Java field values.
When changing an order immediately following creation, IB might reject the request. In such cases, adding a short pause(0.5) normally solves the problem:
[API.msg2] Unable to modify this order as it is still being processed
The Hold and Transmit parameters should not be confused: Hold delays the order in IB-Matlab (you will not see it in TWS); Transmit delays the order within TWS:
Using Transmit, orders can be sent to TWS and delayed (not sent for execution), until the user clicks the <Transmit> (or <Cancel>) button. Prepare such orders as follows:
IBMatlab('action','BUY', 'Transmit',false, ...);
This will create the order in TWS without transmitting it. You will see the order in TWS’s API tab with a button to transmit:
Right-clicking anywhere in the row will present a menu with additional options:
While the order is waiting in TWS for transmission, its attributes can be modified, either directly in TWS, or programmatically (see §10).
9.7 Exercising and lapsing options
To exercise or lapse an option, use Action='exercise' or 'lapse' (respectively). You must specify the quantity of contracts and the exchange (IB’s SMART exchange cannot be used).111 You can also indicate whether to override IB’s default handling action (exercise in-the-money options only). For example:
orderId = IBMatlab('action','exercise', 'symbol','GOOG', ...
'secType','OPT', 'expiry','201509', ...
'multiplier',100, 'strike',600, 'right','C', ...
'quantity',5, 'exchange','AMEX', 'override',true)
Assuming that the information is correct and that I have 5 unlapsed GOOG 9/2015 Call-600 options in my portfolio, then these 5 options will be exercised and turn into 500 shares (5 options * 100 multiplier) of the underlying GOOG, at USD 600 each.
At the time of this writing, GOOG trades at USD 542.34, so the exercise is not in the money and would be rejected if I had not stated Override=true. Because of the override the exercise order is executed at a nominal loss of USD 57.66 (=600-542.34) per share (excluding commissions).
If the option is not in-the-money and you try to exercise without specifying the Override parameter (or if you set the Override value to the default=false), you will receive an error from IB:
[API.msg2] Error processing request: Exercise ignored because option is not in-the-money. {498825899, 322}
If the options do not exist in your portfolio you will receive a different error message:
[API.msg2] Error processing request: No unlapsed position exists in this option in account DU123456. {498752361, 322}
If you have several IB accounts, then the AccountName parameter must be specified, otherwise you will receive yet a different error message:
[API.msg2] Error validating request:-'kd': cause - The account code is required for this operation. {498752362, 321}
You can only lapse an option on its last trading day. If you try to lapse it on a different date, you will receive two separate error messages from IB:
[API.msg2] Order rejected - reason: trade date must match last trade date of the contract {498825901, 201}
[API.msg2] Error processing request: Exercise/Lapse failed due to server rejection {498825901, 322}
Finally, as of the time of this writing, IB only supports exercising/lapsing options, not FOP (future-on-option) or warrants. Customers wishing to exercise or lapse such contracts must submit a manual request ticket to IB.
The following parameters affect exercising/lapsing options in IBMatlab:
Parameter | Data type | Default | Description |
Action | string | (none) | Either 'exercise' or 'lapse'. |
Symbol | string | (none) | The symbol of the underlying asset. |
LocalSymbol | string | '' | The local exchange symbol of the option contract. When left empty, IB infers it from Symbol and the other properties. |
SecType | string | (none) | Needs to be 'OPT'. IB does not currently allow exercising any other SecType. |
Exchange | string | (none) | The exchange that should process the request – cannot be set to 'SMART'. |
Currency | string | 'USD' | The currency for the option contract. |
Multiplier | number | [] | The option contract multiplier. |
Expiry | string | '' | 'YYYYMM' or 'YYYYMMDD' format. |
Strike | number | 0.0 | The strike price of the option contract. |
Right | string | '' | One of: ‘P’, ‘PUT’, ‘C’, ‘CALL’. |
Quantity | integer | 0 | Number of contracts to exercise or lapse. |
Override | integer or logical flag | 0=false | 0 or false: use default action (exercise in-the-money options only) 1 or true: override the default action |
AccountName | string | '' | The specific IB account ID to use. |
9.8 Algorithmic trading orders
In addition to VWAP (§9.1) and TWAP (§9.2), IB-Matlab supports multiple algo-trading strategies, provided by both IB (“IBAlgo”) and 3rd-parties. Some important IBAlgos (Arrival Price,112 Close Price,113 Dark Ice,114 Percentage of Volume,115 Balance Impact/Risk,116 Minimize Impact117) have dedicated IBMatlab convenience parameters; numerous other algos can be specified using a pair of generic parameters.
Algo properties are specified in IBMatlab as follows (Kind: D=dedicated; G=generic):
Parameter | Kind | Data type | Default | Description |
Type | D | string | 'LMT' | Set to one of the following: 'VWAP' (see §9.1) 'TWAP' (see §9.2) 'ArrivalPx' 'ClosePx' 'DarkIce' 'PctVol' 'BalanceImpactRisk' 'MinImpact' |
MaxPctVol | D | number | 0.1=10% | Max % participation of average daily volume up to 0.5 (=50%). |
PctVol | D | number | 0.1=10% | Target % participation of avg daily volume up to 0.5 (=50%). |
StartTime | D | string | '9:00:00 EST' | Format: 'YYYYMMDD hh:mm:ss TMZ' (TMZ optional) |
EndTime | D | string | '16:00:00 EST' | (same as StartTime above) |
AllowPastEndTime | D | integer or logical flag | 1=true | If true, allow the algo to continue to work past the specified EndTime if the full quantity has not been filled. |
NoTakeLiq | D | integer or logical flag | 0=false | If true, avoid hitting the bid or lifting the offer, if possible. |
SpeedUp | D | integer or logical flag | 0=false | If true, compensate for decreased fill rate due to a limit price. |
RiskAversion | D | string | ‘Neutral’ | One of: 'Neutral' (default) 'Get Done' 'Aggressive' 'Passive' |
ForceCompletion | D | integer or logical flag | 0=false | If true, attempt completion by end of day. |
DisplaySize | D | integer | 1 | The order quantity (size) you want to display to the market. The algo will randomize the size by 50% on either side. Only relevant for DarkIce algo. |
MonetaryValue | D | number | 0 | Cash quantity |
AlgoStrategy | G | string | '' | Any algo name listed in https://interactivebrokers.github.io/tws-api/algos.html |
AlgoParams | G | cell-array | {} | Cell array of name,value pairs. Example: {'MaxPctVol',0.25, 'RiskAversion','Aggressive'} |
Note: StartTime, EndTime, AllowPastEndTime, NoTakeLiq, SpeedUp and MonetaryValue were described in §9.1.
Only a few important IBAlgos have dedicated IB-Matlab parameters, listed above. All other strategies/algos are supported by using the AlgoStrategy and AlgoParams parameters, which cover the dedicated convenience parameters as well as many others.
Here is an example for an Arrival Price order using dedicated convenience parameters:
orderId = IBMatlab('action','BUY', 'symbol','GOOG', 'quantity',10, ...
'TIF','Day', 'limitPrice',600, 'type','ArrivalPx',...
'MaxPctVol',0.01, 'RiskAversion','Passive', ...
'StartTime','20120215 10:30:00 EST', ...
'EndTime', '10:45:00 EST', ...
'ForceCompletion',true, 'AllowPastEndTime',false);
And the same Arrival Price order using the generic AlgoStrategy and AlgoParams:
algoParams = {'maxPctVol',0.01, 'riskAversion','Passive', ...
'startTime','20120215 10:30:00 EST', ...
'endTime', '10:45:00 EST', ...
'forceCompletion',true, 'allowPastEndTime',false};
orderId = IBMatlab('action','BUY', 'symbol','GOOG', 'quantity',10,...
'TIF','Day', 'limitPrice',600, ...
'algoStrategy','ArrivalPx', 'algoParams',algoParams);
IB regularly adds/modifies algo strategies and their corresponding parameters. Some algo properties (parameters) are only relevant to some algos but not others, and this list is also dynamic. For an up to date listing of the available algos and parameters, visit https://interactivebrokers.github.io/tws-api/algos.html.
IB only enables algo strategy orders for a subset of security types and exchanges. For example, as of December 2019 IBAlgos are limited to US stocks, while QBAlgos are limited to futures. Refer to the specific algo’s documentation for details.
IB supports some algos only in TWS, not via the API. For example, as of December 2019, IB officially supports Fox River algos only in TWS, not the API.118 If you specify such algos in IBMatlab, IB may possibly reject the requested order. When IB adds any new algo provider, algo strategy and/or algo parameter, you can immediately use them in IBMatlab via the AlgoStrategy, AlgoParams parameters.
As with VWAP and TWAP, IB automatically routes all IBAlgo trades to its internal servers (IBALGO), ignoring the specified Exchange. In contrast, all 3rd-party (non-IB) algos require routing the order through the corresponding 3rd-party algo servers: CSFB (Credit-Suisse First Boston) algos119 require setting Exchange='CSFBALGO'; Jefferies algos120 require Exchange='JEFFALGO'; and QB (Quantitative Brokers)121 algos require Exchange='QBALGO'. Here is an example of a CSFB 'Inline' algo order:
algoParams = {'StartTime','20120215 10:30:00 EST', ...
'EndTime', '10:45:00 EST', ...
'ExecStyle','Patient', 'Auction','Default',...
'MinPercent',10, 'MaxPercent',20, 'DisplaySize',100,...
'BlockFinder',false, 'BlockPrice',40,
'MinBlockSize',100, 'MaxBlockSize',100, 'IWouldPrice',35};
orderId = IBMatlab('action','BUY', 'symbol','GOOG', 'quantity',10,...
'Exchange','CSFBALGO', ... % note the Exchange
'algoStrategy','Inline', 'algoParams',algoParams);
Additional notes:
As with standard LMT orders, some algo orders are not guaranteed to execute.
Many algos are only available in the live account, and cannot be tested in a paper-trading account. None of the algos are available in IB’s Demo account.
IBAlgo orders cannot use the default TIF value of 'GTC' – use 'Day' instead.
IBAlgo orders are treated as LMT orders, so you must specify the LimitPrice parameter in all IBAlgo orders.122 For better control over the order, avoid using the dedicated convenience algo parameters; use AlgoStrategy and AlgoParams instead. These do not override any order or contract parameter, so you can set (for example) Type='MKT' if you wish.
94 http://interactivebrokers.github.io/tws-api/ibalgos.html#vwap, http://interactivebrokers.com/en/software/tws/usersguidebook/algos/vwap.htm
95 Some additional timezones are also supported, e.g. HKT for Hong-Kong Time. Such timezones are not officially supported and IB may possibly stop accepting them at some point. Also note that the timezone must be specified using a 3-letter acronym, not other notations such as US/Eastern or America/New_York etc. as may be reported by the contract details query (§5.4).
96 IB-Matlab versions prior to 1.92 (July 14, 2017) used MKT orders for the VWAP algo
98 http://interactivebrokers.github.io/tws-api/ibalgos.html#twap, http://interactivebrokers.com/en/software/tws/usersguidebook/algos/twap.htm
99 http://interactivebrokers.com/en/trading/orders/bracket.php, http://ibkb.interactivebrokers.com/node/1043
100 In this example, OCAType=3 because this is the only OCA type that IB permits with a MOC child order (without the MOC child, you can also use OCA types 1 or 2).
101 https://quant.stackexchange.com/questions/8744/what-is-the-difference-between-the-interactive-brokers-demo-account-and-a-personal-paper-trader-account; https://ibkrguides.com/clientportal/aboutpapertradingaccounts.htm
102 Discussion of combo ratios and limit prices: https://groups.io/g/twsapi/topic/77368761#45604
103 The latest spread ratios on CME can be found here: http://cmegroup.com/trading/interest-rates/intercommodity-spread.html
104 Other similar predefined CME spreads can be found in http://cmegroup.com/trading/interest-rates/intercommodity-spread.html and http://cmegroup.com/trading/interest-rates/files/TreasurySwap_SpreadOverview.pdf
107 Note that many properties can also be set via direct IBMatlab parameters e.g. SecId, SecIdType, Multiplier, OrderRef.
110 http://interactivebrokers.com/php/whiteLabel/Interoperability/Socket_Client_Java/java_properties.htm
112 http://interactivebrokers.github.io/tws-api/ibalgos.html#arrivalprice, http://interactivebrokers.com/en/index.php?f=1122, http://interactivebrokers.com/en/software/tws/usersguidebook/algos/arrival_price.htm
113 http://interactivebrokers.github.io/tws-api/ibalgos.html#closepx, http://interactivebrokers.com/en/software/tws/usersguidebook/algos/closeprice.htm
114 http://interactivebrokers.github.io/tws-api/ibalgos.html#darkice, http://interactivebrokers.com/en/software/tws/usersguidebook/algos/dark_ice.htm
115 http://interactivebrokers.github.io/tws-api/ibalgos.html#pctvol, http://interactivebrokers.com/en/software/tws/usersguidebook/algos/percentage_of_volume_strategy.htm
116 http://interactivebrokers.github.io/tws-api/ibalgos.html#balanceimpact, http://interactivebrokers.com/en/software/tws/usersguidebook/algos/balance_impact_and_risk.htm
117 http://interactivebrokers.github.io/tws-api/ibalgos.html#minimpact, http://interactivebrokers.com/en/software/tws/usersguidebook/algos/minimize_impact.htm
118 https://interactivebrokers.com/en/software/tws/twsguide.htm#algostop.htm%3FTocPath%3DAlgos%7C_____0; https://interactivebrokers.com/en/index.php?f=4985#thirdy-party-algos
122 IB-Matlab versions prior to 1.92 (July 14, 2017) used MKT orders for the VWAP algo