Market data and entitlements
Every price on every surface arrives through your own TWS or IB Gateway
session. Nothing is resold, proxied, or fetched from a third-party feed. If a
symbol is real-time in TWS it is real-time here, and if TWS shows it delayed,
so does ibkr. Market data is real-time wherever your IBKR market-data
subscriptions cover it, delayed where they don't.
That has a useful consequence: no configuration in this project can turn delayed data into real-time data. The only place to change what you receive is IBKR's account management. What the project can do is tell you, per row, which kind of data you are looking at, and refuse to compute things that the data cannot support.
What the daemon asks for
On every successful connect the daemon sets market-data type 2, frozen-aware. The gateway then returns live ticks for symbols your subscriptions cover and the last-known price when it cannot. Type 1, pure live, can leave snapshot requests hanging when the market is closed, so it is not used.
Entitlements are never stored. The daemon reports the data type it observed on
each request instead, which is why a DATA column appears beside a quote and
why the same symbol can report differently in two sessions.
What each type is good enough for
DATA |
Decisions it supports |
|---|---|
live |
Anything price-sensitive: a limit price, a spread you are about to cross, an option Greek. |
frozen |
Position accounting and after-hours review. It is the last recorded quote with no further updates, and it arrives as a single snapshot, never a stream. |
delayed |
Direction and rough level. Not a limit price: the number is 15 to 20 minutes old, which is several lifetimes for a short-dated option. |
delayed-frozen |
Orientation only. It is yesterday's close. |
Two more values appear on some surfaces. prev_close marks a price taken from
a prior close rather than the current session, and closed replaces the data
type on option chains outside option regular trading hours, with the real feed
state moved to a feed_type field beside it. An empty data type means the
gateway has not sent its notice yet, which happens for a few hundred
milliseconds after a fresh subscription; it is treated as live.
Some computations refuse delayed input rather than producing a plausible wrong
answer. Dealer gamma accepts live and frozen and rejects both delayed
types, because a 15-minute-old spot biases every gamma in the chain.
Why one symbol says delayed
There are two distinct causes and they need different fixes.
No subscription for that instrument class. IBKR answers with error 354, "Requested market data is not subscribed". That rejection is terminal for the subscription: there is no automatic retry in delayed mode. The key is suppressed for 30 minutes so a poller stops hammering a dead name, and a gateway reconnect re-arms it immediately. Options are a separate entitlement from the underlying stock, which is the usual surprise: a stock quote can be live while its chain returns nothing.
A competing live session. If the same login is already streaming live data somewhere else, in TWS or a mobile app, the gateway answers with error 10197 and the connection is forced into delayed mode as a whole. Closing the other session and reconnecting restores live data.
Troubleshooting has the symptom-side version of this, including what each badge string says verbatim.
Which surfaces need which entitlement
| Surface | What it needs |
|---|---|
ibkr quote, position marks |
Streaming or snapshot market data for that instrument. |
ibkr chain |
Option market data for the class, typically OPRA. The expiry list alone is contract details and needs less. |
ibkr gamma |
Option market data for SPX and SPY, and it rejects delayed input outright. |
ibkr scan |
Scanner access for the ranking, plus market data for the per-row enrichment. |
ibkr breadth, ibkr history, ibkr technical |
Historical daily bars. No streaming-quote entitlement is involved. |
ibkr calendar |
Nothing. It makes no broker call at all. |
Live quotes also consume subscription slots, which retail accounts cap at around a hundred concurrent. That is why a wide chain or a large scan serializes rather than firing every request at once.
What works with no market-data subscription at all
More than you would expect. Account and position data is broker account state, not market data, so balances, holdings, cost basis, and order history are unaffected. A position whose quote is missing stays account truth; the daemon marks the missing quote as the expected state rather than a data-quality defect.
Daily bars are a separate entitlement path from streaming quotes, so
ibkr history, ibkr technical, and the S&P 500 breadth engine keep working.
Breadth is computed from constituent daily bars precisely because the index
itself is not redistributed on retail subscriptions. Its first build is slow
for pacing reasons covered in
Troubleshooting.
Market calendars are embedded in the binary and read no broker data, so
ibkr calendar answers whether a market is open even with the gateway down.
When a quote looks wrong, read the session
A quote attaches a session_context block when the calendar state is needed to
interpret it, and omits it on an ordinary live in-session row. The block names
the market, its state (regular, closed, holiday, early_close, or
unknown), and the next open and close.
That is usually the answer when a price looks stale. A frozen quote at 20:00
ET on a Tuesday is the system working correctly; the same quote at 11:00 ET is
worth investigating. Concepts explains why the
embedded exchange calendar, rather than the gateway's quote state, decides
whether a market is open.