Interactive Brokers
Connects through the TWS API (socket protocol) to "IB Gateway" or "TWS (Trader Workstation)" running on the docker's machine and trades the stocks, futures, options and so on of an Interactive Brokers account. With TWS: after logging in, click the configuration button at the top right, open "Configure" → "API" → "Settings", uncheck "Read-Only API", check "Enable ActiveX and Socket Clients", and note the "Socket port" (TWS defaults to 7496 for live and 7497 for paper; IB Gateway to 4001 for live and 4002 for paper), then enter it as the server address in the exchange configuration. Authentication happens through the TWS or IB Gateway login, so the exchange configuration needs no keys.
Names and Configuration
exchange.GetName(): Futures_IB (Securities and futures); aliases: IB.
| Field | Required | Default | Description |
|---|---|---|---|
| Server Address | Yes | localhost:7496 | The API address and port of TWS or IB Gateway, for example localhost:7496. |
| Market Data Type | Yes | 1 | Realtime, frozen, delayed or delayed frozen. Accounts without a realtime market data subscription can choose delayed data. It can be switched at run time with exchange.IO("marketDataType", n). Options: realtime market data, frozen market data, delayed market data, delayed frozen market data |
Trading Pairs and Contract Codes
Pair examples: AAPL.US, TSLA.US
Set with exchange.SetContractType() (or exchange.SetCurrency()); the trading pair configured on the exchange object is the initial instrument. The form is symbol.currency[.type[.exchange]]; the type defaults to stock STK and the exchange to SMART, and the whole code is one instrument:
- US stocks:
AAPL.US,TSLA.US(USmeans priced in USD,HKin HKD; other currencies are written as their currency code). - Futures (
FUT):symbol-expiry[-multiplier].currency.FUT.exchange, with the expiry month written asYYYYMMand the exchange as IB's exchange code. - Options (
OPT) and futures options (FOP):symbol-expiry-C or P-strike×100[-multiplier].currency.OPT or FOP.exchange, with the strike multiplied by 100 and written as an integer. - A plain number: used directly as the IB contract ID (conId).
Symbol in positions and orders is the short form (e.g. Z74.SGD); exchange.GetPositions() and exchange.GetOrders() accept either the short form or the full code used when ordering (e.g. Z74.SGD.STK.SGX).
exchange.SetContractType() queries the gateway for the contract details and returns them, including InstrumentID, PriceTick, VolumeMultiple (the multiplier, 1 for stocks), TradingHours, LiquidHours and IsTrading; IsTrading tells from the trading hours whether the contract is trading now, and passing liquid as the second argument uses the liquid hours instead.
Exchange-specific IO Commands
| Command | Arguments | Description |
|---|---|---|
status | — | Whether the session with TWS/IB Gateway is established (does not connect by itself). |
time | — | Get the IB server time (millisecond timestamp). |
accounts | — | Get the list of managed accounts (account IDs). |
reqId | — | Allocate a new request ID (incremented on every call). |
orderId | — | Take the next available order ID and reserve it, so the docker's own orders no longer use it; useful for placing orders directly with the api command. |
ignore | codes | Set the TWS error codes ignored by synchronous requests (replacing the whole list; an empty array clears it); the argument is an array of codes or its JSON string. Notices in the 2100–2200 range and 10167 and 399 never abort a request anyway. Returns: The error code list after the change (sorted, without duplicates). |
scan | object | Run the market scanner; the argument holds the scanner subscription fields (an object or a JSON string, keyed as in the legacy ScannerSubscription, such as Instrument, LocationCode, ScanCode, NumberOfRows and AbovePrice) and must contain Instrument, for example STK with LocationCode STK.US.MAJOR; ScanCode defaults to HOT_BY_VOLUME. (more below the table) |
wait | [number] | Wait for and return the next complete message from TWS/IB Gateway; the argument is the timeout in milliseconds (at most 600 seconds), negative means no waiting, 0 or omitted waits up to 30 seconds, and null is returned on timeout. Returns: {id, fields}: id is the TWS message ID and fields the remaining fields as an array of strings. |
debug | [bool] | Query or set debug mode; when on, every frame sent to or received from TWS/IB Gateway is written in the TWS API log format (at most 512 bytes per frame) to the docker's standard output log, not to the robot log. Returns: The current debug mode (true/false). |
marketDataType | number | Switch the market data type (1 realtime, 2 frozen, 3 delayed, 4 delayed frozen). Returns: true |
api | msgId, ...fields | name[, params[, filterMsgId[, timeout]]] | Send a raw TWS message: exchange.IO("api", msgId, fields...) returns true once sent. (more below the table) |
The rest of the longer descriptions in the table:
scan: Returns: An array of scan results, each{rank, symbol, conId, secType, exchange, currency, localSymbol, tradingClass, marketName, ...};symbolis an instrument code that can be passed toexchange.SetContractType()as is (e.g.AAPL.US).api: The legacy formexchange.IO("api", requestName or msgId, paramArray, waitMsgId, timeoutSeconds)also works (request names such asPlaceOrderorCancelOrder; the parameter array may be a JSON string): without a message ID to wait for it returnstrueonce sent; with one it returns every message received from sending until that message ID arrives, each as an array of its field strings without the message ID.
For the common commands base and currency see exchange.IO.
Common Usage
Check the gateway session and read the server time and managed accounts
javascript
function main() {
// status does not connect by itself: false before the first request
Log("Session up:", exchange.IO("status"))
var t = exchange.IO("time") // milliseconds; this request opens the session
Log("IB server time:", _D(t), "offset from local (ms):", t - Date.now())
Log("Managed accounts:", exchange.IO("accounts")) // orders use the first by default
Log("Session up:", exchange.IO("status"))
}
Pick top gainers with the market scanner and fetch their tickers
javascript
function main() {
var rows = exchange.IO("scan", {
Instrument: "STK",
LocationCode: "STK.US.MAJOR",
ScanCode: "TOP_PERC_GAIN",
NumberOfRows: 10,
AbovePrice: 5
})
if (!rows) {
Log("Scan failed:", GetLastError())
return
}
rows.forEach(function (r) {
Log(r.rank, r.symbol, "conId:", r.conId, r.exchange, r.currency)
})
// symbol can be used as the instrument code directly
exchange.SetContractType(rows[0].symbol)
Log(rows[0].symbol, exchange.GetTicker())
}
Switch to delayed market data without a realtime subscription and ignore partial-subscription errors
javascript
function main() {
exchange.IO("marketDataType", 3) // 1 realtime, 2 frozen, 3 delayed, 4 delayed frozen
// 10090 (part of the market data not subscribed) no longer aborts a request;
// the whole list is replaced and returned
Log("Ignored error codes:", exchange.IO("ignore", [10090]))
exchange.SetContractType("AAPL.US")
Log(exchange.GetTicker())
exchange.IO("ignore", []) // clear the list
}
Send raw TWS requests and collect the replies, or read messages one by one with wait
javascript
function main() {
exchange.IO("debug", true) // every frame goes to the docker's standard output log
// Legacy named call: a ReqMktData snapshot request, collecting messages until
// tickSnapshotEnd (message ID 57), for at most 10 seconds
var id = exchange.IO("reqId")
var msgs = exchange.IO("api", "ReqMktData", [id, "AAPL.US", "", true, false], 57, 10)
if (msgs) {
Log("Received", msgs.length, "messages (without message IDs):", msgs)
}
// Raw frame: message ID 49 (reqCurrentTime, version 1); returns true once sent
exchange.IO("api", 49, 1)
while (true) {
var m = exchange.IO("wait", 5000)
if (!m) {
Log("No message within 5 seconds")
break
}
if (m.id == 49) {
Log("Server time (s):", m.fields[1]) // fields[0] is the message version
break
}
Log("Other message:", m.id, m.fields)
}
exchange.IO("debug", false)
}
Function Support
Not supported (the call fails with an error and returns null): exchange.GetTrades, exchange.GetHistoryOrders, exchange.GetFundings, exchange.SetMarginLevel, exchange.ModifyOrder, exchange.CreateConditionOrder, exchange.ModifyConditionOrder, exchange.CancelConditionOrder, exchange.GetConditionOrder, exchange.GetConditionOrders, exchange.GetHistoryConditionOrders.
Served through a fallback:
exchange.GetRecords: Native periods are 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 1d, 1w; other periods that are a multiple of 60 seconds are synthesized by the docker from native bars, and the rest (such as second-level periods) are not available (this exchange object does not supportexchange.GetTrades()).
Margin, Account and Simulation
Account: The first managed account logged in to TWS/IB Gateway is used. exchange.GetAssets() returns each currency's net liquidation value (NetLiquidationByCurrency, or the currency's cash balance when it is absent) with a frozen amount of 0; Balance and Equity of exchange.GetAccount() are the total net liquidation value in the account's base currency, and Info holds all account values sent by TWS. Price of exchange.GetPositions() is the average price per unit (for futures and options the average cost is divided by the contract multiplier; the original is AvgCost in Info), and Profit is 0 (the IB position query has no unrealized profit).
Notes
- The docker connects to TWS with the live trading ID as its client ID (clientId), so the client ID stays the same across restarts and orders placed earlier can still be canceled. TWS only lets the client ID that placed an order (or the master client) cancel it.
exchange.GetOrders()returns all open orders on the gateway (every contract when no instrument is given);exchange.GetOrder()only finds open orders and orders seen during this run, not orders finished earlier.Timeof orders is 0 (TWS order reports carry no order time). - Market data are snapshots:
exchange.GetDepth()has only the best bid and ask and reports an error when there is no valid bid/ask;exchange.GetTickers()returns the tickers of the contracts already used in this run, leaving out contracts with neither a last price nor a previous close. For US stocks,Volumeofexchange.GetTicker()is converted from TWS lots (100 shares) to shares. exchange.GetMarkets()gets the contract list through the market scanner (STK,STK.US.MAJOR, ranked by volume withHOT_BY_VOLUME) and then queries each contract's details for precision; it contains only the contracts in the scan results.- Order quantities are numbers of shares (contracts for futures and options), not amounts of money; a price of
-1or0submits a market order (MKT). Orders areGTCby default; the options object at the end of the order functions may pass{tif: "ioc"}or{tif: "fok"}, andpostOnlyis not supported. In the options object,outsideRth: trueallows fills outside regular trading hours (not allowed by default) andaccountchooses the account to order in. closebuyandclosesellonly place an order in the opposite direction (sell, buy) with no reduce-only guarantee: without a matching position they open a position in the opposite direction.- When the gateway rejects an order, the
Rejectfield in the order'sInfoholds the reason.