The complete formula grammar.
Every StreamXLS value is a native Excel =RTD() formula against ProgID Tws.Rtd, addressed by a uniform topic-string tuple. One grammar covers six topic families: market data, accounts, positions, orders, order submission, and connection status. This page is the full catalog — contract syntax, every field name, and the return conventions. Topic and field names are case-insensitive throughout.
One formula, six families
The shape is always the same:
=RTD("Tws.Rtd", , <topic…>, <field>)
The first argument is the ProgID Tws.Rtd. The second argument is ignored — it is Excel's "Server" parameter, and StreamXLS reads none of it. All connection and contract information lives in the third argument onward. Leave the second argument empty (, ,).
Common mistake: putting a connection string in the second argument. =RTD("Tws.Rtd", "127.0.0.1:7497", "AAPL", "BID") is wrong — the connection string is silently ignored and StreamXLS falls back to the default 127.0.0.1:7496. Connection tokens must be topic arguments, e.g. =RTD("Tws.Rtd", , "127.0.0.1:7497", "AAPL", "BID").
The six topic families
There are six families. Two of them come in singular / list pairs — position/positions and order/orders — so you will see eight topic words in total, but they group into six families. A bare contract (no leading topic word) selects market data.
Each row links to its section below.
Return-value convention. A field returns a number (or text) when its value is known to be current. When it is not — TWS disconnected or unresponsive — time-sensitive fields return #N/A rather than a stale value. A visible gap is safer than a silently frozen price.
Point a formula at a session
With no connection tokens, StreamXLS connects to 127.0.0.1:7496 (TWS live). Add connection tokens anywhere in the topic arguments (order does not matter) to target a different host, port, or client ID.
| Token | Format | Default |
|---|---|---|
| Host | host=<ip-or-hostname> | 127.0.0.1 |
| Port | port=<number> | 7496 |
| Client ID | clientid=<number> | auto-generated |
Port aliases
| Alias | Port | Session |
|---|---|---|
paper | 7497 | TWS paper trading |
gw | 4001 | IB Gateway live |
gwpaper | 4002 | IB Gateway paper |
TWS live is 7496; TWS paper 7497; IB Gateway live 4001; IB Gateway paper 4002.
Compact form
Instead of separate host=/port=/clientid= tokens, use one host:port or host:port:clientid string. Use colons — never underscores.
=RTD("Tws.Rtd", , "host=192.168.1.100", "port=4001", "clientid=5", "AAPL", "BID")
=RTD("Tws.Rtd", , "192.168.1.100:4001:5", "AAPL", "BID")
=RTD("Tws.Rtd", , "paper", "AAPL", "BID") ' 127.0.0.1:7497
Multiple simultaneous connections
Each distinct host:port:clientid is a separate connection. A single workbook can watch a live and a paper session at once — put a different connection token in each cell:
=RTD("Tws.Rtd", , "port=7496", "AAPL", "BID") ' Live TWS
=RTD("Tws.Rtd", , "port=7497", "AAPL", "BID") ' Paper TWS
=RTD("Tws.Rtd", , "gw", "AAPL", "BID") ' Gateway live
The client ID can be pinned with the TWS_RTD_CLIENT_ID environment variable, which overrides any clientid= token. See Configuration → Environment variables.
Five ways to name an instrument
A contract can be specified five interchangeable ways. Pick whichever reads best for the security; the compact and key=value forms are recommended for options and futures.
1 · Simple symbol (stocks)
A bare symbol assumes SecType=STK, Exchange=SMART, Currency=USD.
=RTD("Tws.Rtd", , "AAPL", "BID")
2 · Positional
Symbol, security type, exchange, currency, then field.
=RTD("Tws.Rtd", , "AAPL", "STK", "NASDAQ", "USD", "LAST")
3 · Key=value (recommended for complex securities)
=RTD("Tws.Rtd", , "sym=SPY", "sec=OPT", "strike=680", "right=C", "exp=20251219", "BID")
| Key | Aliases | Meaning |
|---|---|---|
sym | symbol | Underlying symbol |
sec | sectype, securitytype | Security type (STK, OPT, FUT, CASH, BAG, …) |
exch | exchange | Exchange |
prim | primexch, primary, primaryexchange | Primary exchange |
cur | curr, currency | Currency |
exp | expiry, expiration, lasttradedate | Expiration (YYYYMMDD options, YYYYMM futures) |
strike | strikeprice | Option strike |
right | putcall, optiontype | Option right (C or P) |
mult | multiplier | Contract multiplier |
loc | localsymbol, local | Exchange-specific local symbol |
tc | tradingclass, class | Trading class |
conid | contractid | TWS Contract ID |
4 · Compact notation
Use @ for the exchange and / as a delimiter, omitting trailing segments you don't need. Format: SYMBOL@EXCH/PRIMEXCH/SECTYPE/EXP/RIGHT/STRIKE/CURRENCY.
=RTD("Tws.Rtd", , "AAPL@NASDAQ/STK/USD", "BID")
=RTD("Tws.Rtd", , "ES@CME/FUT/202503/USD", "LAST")
=RTD("Tws.Rtd", , "EUR.USD/CASH", "BID")
5 · ConID (most precise)
The TWS Contract ID identifies a contract unambiguously — useful for options with similar strikes. Find it in TWS via right-click → Financial Instrument Info → Description.
=RTD("Tws.Rtd", , "conid=265598", "BID") ' AAPL
Worked examples
| Instrument | Formula |
|---|---|
| SPY option (call) | "sym=SPY","sec=OPT","strike=680","right=C","exp=20251219" |
| ES future | "sym=ES","sec=FUT","exch=CME","exp=202503" |
| MES micro future | "sym=MES","sec=FUT","exch=CME","exp=202503" |
| EUR/USD forex | "sym=EUR","sec=CASH","exch=IDEALPRO","cur=USD" |
| Specific future by local symbol | "loc=ESH5","sec=FUT","exch=CME" |
Combo & spread (BAG) contracts
Multi-leg strategies use sec=BAG and a cmb= token listing each leg as conid#ratio#action#exchange, legs separated by semicolons. The cmb= value is preserved whole — it is not split on its semicolons.
=RTD("Tws.Rtd", , "sym=SPY", "sec=BAG",
"cmb=643929299#1#BUY#SMART;643929301#1#SELL#SMART", "BID")
A bull call spread is shown above (buy the lower strike, sell the higher). Ratios allow unbalanced spreads (e.g. 2:1). You need each leg's ConID first — get them from TWS (right-click → Financial Instrument Info) or by building a single-contract formula for each leg. Combo legs execute as a single all-or-none unit by default.
Ticks, derived prices, and greeks
Market-data formulas take a contract followed by a field: =RTD("Tws.Rtd", , "<contract>", "<field>"). These are the fields nearly every workbook uses.
Common price & size fields
| Field | Meaning | Field | Meaning |
|---|---|---|---|
BID | Best bid price | BIDSIZE | Size at best bid |
ASK | Best ask price | ASKSIZE | Size at best ask |
LAST | Last trade price | LASTSIZE | Last trade size |
OPEN | Session open | VOLUME | Total volume |
HIGH | Session high | AVGVOLUME | Average daily volume |
LOW | Session low | LASTTIME | Last-trade timestamp |
CLOSE | Previous close | HALTED | Halt indicator (0 = not halted) |
Derived price fields
Two fields are computed by StreamXLS so a cell always has a reasonable price regardless of market hours or subscription:
| Field | Precedence |
|---|---|
MarketPrice | Mid (BID+ASK)/2 when both present → else LAST → else CLOSE; blank until any source is available |
LastOrClose | LAST if available → else CLOSE |
Last is strict. It stays #N/A under real-time/frozen data until a trade actually prints, then shows the numeric last. If you want a value that resolves before the first trade — after hours, or without a real-time subscription — use MarketPrice. Per-contract, MarketDataType returns the data type TWS is actually serving for that contract, which can differ from the default.
Option greeks
For an option contract, greeks and model values are exposed per computation source. Field names compose as <Source><Measure>, where the source is Bid, Ask, Last, or Model and the measure is one of the eight below — e.g. ModelDelta, BidImpliedVol, LastOptPrice:
| Measure | Meaning |
|---|---|
ImpliedVol | Implied volatility |
Delta | Option delta |
Gamma | Option gamma |
Theta | Option theta |
Vega | Option vega |
OptPrice | Model option price |
UndPrice | Underlying price used in the computation |
PvDividend | Present value of dividends |
=RTD("Tws.Rtd", , "sym=SPY", "sec=OPT", "strike=680", "right=C", "exp=20251219", "ModelDelta")
Option-chain enumeration
Query an underlying to discover its option chain:
| Field | Returns |
|---|---|
OptionExpirationsCSV | Comma-separated expiration dates with options on the underlying |
OptionStrikesCSV | Comma-separated strike prices with options on the underlying |
StrikeStep | Minimum reported strike-price increment |
No quotes while orders and positions work? Your TWS API is almost certainly older than the market-data floor (negotiated ServerVersion 206 / TWS API 10.38.01). StreamXLS withholds market-data topics fail-loud in that case. Diagnose and fix at Configuration → The TWS-API version floor; the per-connection status fields MarketDataState and MarketDataMessage report it.
Full tick catalog
Every tick type StreamXLS maps, by field name. Core price/size ticks arrive for any tradeable security; the rest are requested per security type. When delayed data is active, the delayed tick IDs (66–76, 88, 90) feed the same base field names above — you keep using BID, LAST, and so on.
| RTD field | Tick ID | Description |
|---|---|---|
BIDSIZE | 0 | Size at best bid |
BID | 1 | Best bid price |
ASK | 2 | Best ask price |
ASKSIZE | 3 | Size at best ask |
LAST | 4 | Last trade price |
LASTSIZE | 5 | Last trade size |
HIGH | 6 | Session high |
LOW | 7 | Session low |
VOLUME | 8 | Total volume |
CLOSE | 9 | Previous session close |
OPEN | 14 | Session open |
BIDOPTIONCOMPUTATION | 10 | Greeks at bid price |
ASKOPTIONCOMPUTATION | 11 | Greeks at ask price |
LASTOPTIONCOMPUTATION | 12 | Greeks at last price |
MODEL_OPTION_COMPUTATION | 13 | Model-computed greeks |
WEEK13LO / WEEK13HI | 15 / 16 | 13-week low / high |
WEEK26LO / WEEK26HI | 17 / 18 | 26-week low / high |
WEEK52LO / WEEK52HI | 19 / 20 | 52-week low / high |
AVGVOLUME | 21 | Average daily volume |
OPTIONHISTORICALVOL | 23 | Option historical volatility |
OPTIONIMPLIEDVOL | 24 | Option implied volatility |
CALLOPTIONOPENINTEREST | 27 | Call option open interest |
PUTOPTIONOPENINTEREST | 28 | Put option open interest |
CALLOPTIONVOLUME | 29 | Call option volume |
PUTOPTIONVOLUME | 30 | Put option volume |
INDEXFUTUREPREMIUM | 31 | Index-future premium |
BIDEXCH | 32 | Exchange(s) posting best bid |
ASKEXCH | 33 | Exchange(s) posting best ask |
AUCTIONVOLUME | 34 | Auction volume |
AUCTIONPRICE | 35 | Auction price |
AUCTIONIMBALANCE | 36 | Auction imbalance |
PLPRICE | 37 | P&L mark price |
LASTTIME | 45 | Timestamp of last trade |
SHORTABLE | 46 | Shortability indicator (>2.5 = easy) |
HALTED | 49 | Trading-halt indicator |
TRADECOUNT | 54 | Trade count |
TRADERATE | 55 | Trades per minute |
VOLUMERATE | 56 | Volume per minute |
LASTRTHTRADE | 57 | Last regular-hours trade |
RTHISTORICALVOL | 58 | Real-time historical volatility |
IBDIVIDENDS | 59 | Dividend info |
BONDMULTIPLIER | 60 | Bond factor multiplier |
REGULATORYIMBALANCE | 61 | Regulatory imbalance |
SHORTTERMVOLUME3MIN | 63 | 3-minute volume |
SHORTTERMVOLUME5MIN | 64 | 5-minute volume |
SHORTTERMVOLUME10MIN | 65 | 10-minute volume |
CREDITMANMARKPRICE | 78 | Credit mark price |
CREDITMANSLOWMARKPRICE | 79 | Slow credit mark price |
LASTEXCH | 84 | Exchange of last trade |
FUTURESOPENINTEREST | 86 | Futures open interest |
AVGOPTVOLUME | 87 | Average option volume (STK) |
SHORTABLESHARES | 89 | Shares available to short |
ETFNAVLAST | 96 | ETF NAV last |
ETFFROZENNAVLAST | 97 | Frozen ETF NAV last |
ETFNAVHIGH | 98 | ETF NAV high |
ETFNAVLOW | 99 | ETF NAV low |
SOCIALMARKETANALYTICS | 100 | Social sentiment |
ESTIMATEDIPOMIDPOINT | 101 | Estimated IPO midpoint |
FINALIPOLAST | 102 | Final IPO price |
Account values
Read any IBKR account-summary value with =RTD("Tws.Rtd", , "account", "<acct>", "<field>"). Numeric values return as numbers. Append a currency filter ("cur=USD") to pull a per-currency variant instead of the generic figure.
=RTD("Tws.Rtd", , "account", "U1234567", "NetLiquidation")
=RTD("Tws.Rtd", , "account", "U1234567", "AvailableFunds", "cur=USD")
=RTD("Tws.Rtd", , "account", "U1234567", "OpenPositionCount")
Fields are pass-through. Any IBKR account-summary tag resolves — case-insensitive and separator-tolerant ("Net Liquidation" matches NetLiquidation). Around 136 tags are delivered; the demo workbook's Account worksheet is the canonical enumeration. Rather than list all of them, here are the common anchors:
| Field | Field | Field |
|---|---|---|
NetLiquidation | AvailableFunds | BuyingPower |
TotalCashValue | ExcessLiquidity | MaintMarginReq |
GrossPositionValue | EquityWithLoanValue | OpenPositionCount |
OpenPositionCount is computed per-account from non-zero positions and updates live. For the full field list open the demo workbook and read its Account worksheet.
A single position, or the whole list
Single / aggregate position
=RTD("Tws.Rtd", , "position", "<acct>", "<contract>", "<field>"). The account argument accepts one code, a comma-separated list, or * / blank for all accounts — matched positions aggregate (shares and market values sum; average cost is position-weighted).
=RTD("Tws.Rtd", , "position", "U1234567", "AAPL", "UnrealizedPnL")
=RTD("Tws.Rtd", , "position", "*", "AAPL@SMART", "MarketValue")
| Value fields | Contract-metadata fields |
|---|---|
Position (shares) | ConID, Symbol, SecType |
AverageCost (per share) | Strike, Right, Expiry |
MarketValue | Exchange, PrimaryExch |
DailyPNL | LocalSymbol, TradingClass |
RealizedPNL / UnrealizedPNL | Currency, Multiplier |
Positions list
=RTD("Tws.Rtd", , "positions", "<accts>", "<field>") enumerates the active positions across the accounts (every position where size ≠ 0 or market value ≠ 0).
| Field | Returns |
|---|---|
SymbolsCsv | Semicolon-delimited position identifiers (bare symbol for stocks; compact slash notation for options/futures) |
ConIdCsv | Semicolon-delimited ConIDs for the same positions |
PositionsChangedUtc | Updates when the set membership changes (legacy synonym: SymbolsChangedUtc) |
Spill the list across cells with TEXTSPLIT (Excel 365). The list delimiter is a semicolon:
=TEXTSPLIT(RTD("Tws.Rtd", , "positions", , "SymbolsCsv"), ";") ' across columns
=TEXTSPLIT(RTD("Tws.Rtd", , "positions", , "SymbolsCsv"), , ";") ' down rows
=IFERROR(TEXTSPLIT(RTD("Tws.Rtd", , "positions", , "SymbolsCsv"), ";"), "") ' first-load guard
Initial-load guard. The server withholds the first SymbolsCsv/ConIdCsv/PositionsChangedUtc until the initial positions snapshot completes, so wrap the spill in IFERROR to avoid a transient error on first load. Pair PositionsChangedUtc with SymbolsCsv to detect when the set changes.
Monitoring orders
Orders list
=RTD("Tws.Rtd", , "orders", "<accts>", "<field>") returns a comma-separated list of PermIDs, filtered by account (* / blank = all).
| Field | Returns |
|---|---|
ListCsv | All orders the server has seen, including filled / cancelled / completed |
OpenListCsv | Active orders only — excludes Filled, Cancelled, Inactive, ApiCancelled |
Single-order fields
=RTD("Tws.Rtd", , "order", "<permID>", "<field>"). Orders are addressed by PermID (the permanent, cross-client order ID that the orders lists return) — not the transient client-side order ID. Individual order fields always show last-known values regardless of order status.
| Identity & status | Sizing & price | Contract & routing |
|---|---|---|
PERMID, PARENTID | QUANTITY | SYMBOL, CONID, SECTYPE |
Status | FILLED, REMAINING | EXCHANGE, CURRENCY |
SIDE (ACTION) | LMTPRICE, STOPPRICE | EXPIRY, STRIKE, RIGHT |
ORDERTYPE (TYPE) | AVGFILLPRICE | ACCOUNT, SUBMITTER |
FirstSeenUtc | TRAILSTOPPRICE | TIF, GOODAFTERTIME |
LastUpdateUtc | TRAILINGPERCENT | GOODTILLDATE, OUTSIDERTH |
WHYHELD | HIDDEN, DISPLAYSIZE | ALGOSTRATEGY, ALGOPARAMS |
WARNINGTEXT | ALLOWPREOPEN |
Reflection fallback. Any field not explicitly mapped is resolved by case-insensitive reflection against the IBKR C# API types (Order, Contract, OrderState) — so many IBApi properties beyond the list above resolve by their native name.
Order-status glossary
| Status | Meaning |
|---|---|
PendingSubmit | Transmitted but not yet confirmed |
PendingCancel | Cancel request sent, awaiting confirmation |
PreSubmitted | Simulated order accepted, awaiting election |
Submitted | Order accepted by the system |
Filled | Completely filled |
Cancelled | Cancelled (confirmed) |
ApiCancelled | Cancelled via API before acknowledgment |
Inactive | Rejected or cancelled |
StageOrder
StageOrder stages an order in TWS as a side-effect of subscribing — placing the formula in a cell is what stages it. It takes key=value tokens in any order and returns a status string. (SendOrder is an accepted synonym; both spellings parse identically.)
=RTD("Tws.Rtd", , "StageOrder", "sym=AAPL", "side=BUY", "shares=100",
"type=LMT", "limit=150.05", "exch=SMART")
Required keys
| Key | Aliases | Notes |
|---|---|---|
sym | symbol | Symbol |
side | action | BUY or SELL |
shares | quantity, qty, size | Integer quantity |
type | MKT, LMT, and other IB order types | |
limit | Required when type=LMT |
Common optional keys
| Key | Sets |
|---|---|
exch | Exchange (defaults to SMART) |
account | IB account code |
fagroup | FA group |
algo | Algo strategy name |
algoparams | Algo params, encoded tag=value|tag=value|… |
tag / nonce / seq / submit | Client tag for uniqueness/traceability (order reference) |
For a complete list of supported keys see the TWS API Order reference.
Return values
| Value | Meaning |
|---|---|
Sending | Topic registered, send scheduled |
Staged | Order delivered to TWS with Transmit=false — it sits in the TWS order list awaiting your Transmit click |
PreSubmitted / Submitted / Filled / Inactive | After you transmit in TWS, the cell follows TWS's own status reports |
Canceled | The staged order was discarded, the working order was cancelled, or the formula was removed before the order was placed |
SendOrder Error: … / Error nnn: … | Validation / connection / TWS order error |
Staged is not the order's market state: StreamXLS always places orders with Transmit=false, so the order lands in the TWS order list staged, awaiting Transmit — it shows a Transmit button you must click to actually send it to the market. TWS sends no confirmation for staged orders (they are invisible to order queries until transmitted or discarded, so they also don't appear in StreamXLS Orders topics); Staged means "delivered to TWS without error." Once you act on the order in TWS, the cell tracks TWS's reports — including recovery from a failed Transmit attempt (e.g. a missing account allocation): fix and transmit in TWS and the cell updates to the working status.
Two cautions
Deduplication. Excel deduplicates RTD topics with identical parameters, so submitting the same contract/side/price/size twice in a row places only one order. To force a second order, add a unique tag/nonce (e.g. nonce=2) so Excel issues a distinct subscription.
Practice in paper first. Because a live cell can stage a live order, build and test order-staging workbooks against a paper session (paper / port 7497) before pointing them at a funded account.
Connection & data-freshness status
=RTD("Tws.Rtd", , "status", "<field>"). Status fields are per-connection: when several connections exist, supply a connection token (paper/live, or host=/port=) to target one, or omit it to piggyback the single connection.
| Field | Meaning |
|---|---|
IsConnected | Link between the engine and TWS (not Excel ↔ engine): TRUE / FALSE |
ActiveTopicCount | Number of subscribed topics |
LastUpdateUtc | Timestamp of the last successful update (Excel UTC datetime) |
ServerHeartbeatUtc | Last Excel heartbeat (interval is unpredictable — minutes are possible) |
AccountsCSV | Comma-separated managed account IDs from the connection handshake |
MarketDataType | Configured default type: 1 REALTIME · 2 FROZEN · 3 DELAYED · 4 DELAYED_FROZEN. (Per-contract, the market-data field MarketDataType reports what TWS is actually serving.) |
ServerVersion | This connection's negotiated TWS ServerVersion (int), or Not Connected |
MarketDataState | Ok (≥206) / TooOld (1–205) / Unknown (0) |
MarketDataMessage | Actionable "update your TWS API" text when TooOld, else empty |
OrderDataState | Disconnected / Idle / Requested / Ready |
LastOrderListChangeUtc | Updates when the order-list membership changes for subscribed accounts |
LastOrderUpdateUtc | Updates on any new orderStatus from TWS |
PositionDataState | Disconnected / Idle / Requested / Receiving / Ready |
LastPositionListChangeUtc | Updates when the open-symbol list membership changes |
LastPositionUpdateUtc | Updates on every position data callback |
ConfigWarnings | TWS_RTD_* configuration-validation warnings; empty when clean (see Configuration) |
The bare token-free form also works for single-value status/metadata reads, e.g. =RTD("Tws.Rtd", , "ServerVersion"). Combine IsConnected with LastUpdateUtc to flag stale subscriptions.
Build, license, and TWS-API fields
Metadata fields take no topic word — just the field: =RTD("Tws.Rtd", , "<field>"). They resolve in every license state, so a workbook can surface build and license status without special handling.
Build
| Field | Returns |
|---|---|
VERSION | Product version, SemVer (e.g. 1.0.0) |
BUILD_TIME | When the DLL was compiled (UTC) |
SERVER_PATH | Full path to the loaded StreamXLS.dll |
CONFIGURATION | Build configuration (Debug / Release) |
ASSEMBLY_NAME | Assembly name (StreamXLS) |
License
| Field | Returns |
|---|---|
LICENSE_STATE | Developer / Trial / Paid / Expired / Unknown |
LICENSE_MESSAGE | Human-readable status (trial days, reconnect heads-up, or purchase pointer) |
LICENSE_DAYS_REMAINING | Whole days left in the trial (empty when not in a trial) |
TWS-API binding
| Field | Returns |
|---|---|
TWSAPI_STATE | State of the runtime binding to IBKR's CSharpAPI.dll |
TWSAPI_MESSAGE | Actionable guidance when the TWS API is absent / too old / incompatible |
TWSAPI_VERSION | Detected TWS API version (empty if not detected) |
Update breadcrumb
| Field | Returns |
|---|---|
UPDATE_AVAILABLE | 1 if an update is available, else 0 |
UPDATE_CRITICAL | 1 if that update is critical, else 0 |
UPDATE_LATEST_VERSION | Latest known version (empty when none) |
UPDATE_MESSAGE | Human-readable update notice (empty when up to date) |
The UPDATE_* fields read a local, fail-open breadcrumb; the engine makes no network call, and no breadcrumb means "up to date". For how the 30-day trial auto-starts and how to activate a license key, see Get Started → Your trial & license.