DocumentationUnderstand

Market data and entitlements

Broker market data — quotes, option chains, Greeks, historical bars — arrives through your own TWS or IB Gateway session. Nothing is resold or proxied. If a symbol is real-time in TWS it is real-time here, and if TWS shows it delayed, so does canary. 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.

The data-health indicator describes the quote service's availability. Receiving live and delayed quotes together is informational and does not count as a data problem. Feed modes and live-access restrictions remain visible in the details; each quote keeps its own mode and timestamps. Request failures, a rejected live request with no usable fallback, unknown modes, and delayed last-session data still raise source warnings. A healthy feed does not make a delayed quote live or establish that it is suitable for a particular calculation.

A delayed Nasdaq-100 quote is a supported state for background market context. A paid live subscription is not a product prerequisite. Its delayed label and source time remain visible; time-sensitive calculations and execution quotes still need their required fresh evidence.

A short list of regime inputs is the exception: they come from the institution that publishes them, not from your broker session.

Series the daemon reads from the publisher

These are official daily series fetched over HTTPS, straight from the source that computes them:

Series Publisher Feeds
VVIX daily close Cboe The vol-of-vol row.
VIX3M daily close Cboe The off-window VIX3M leg of the VIX term-structure row, and the cross-check against the broker's own reading.
ICE BofA high-yield and investment-grade OAS FRED / St. Louis Fed The cash-credit row.
90-day AA financial commercial paper, 13-week T-bill Federal Reserve, US Treasury The funding-spread row.

Three things follow. No IBKR entitlement is involved, so these rows keep working on an account with no market-data subscription at all. They fail independently of the gateway: a broker outage leaves them current, and a publisher outage leaves them stale while your quotes stay live. And they are daily closes, so their age is counted in sessions rather than seconds — Sensors has that vocabulary.

VIX3M is the one row where both kinds of data meet. In session the broker's live tick is the source, because Cboe publishes closes and not intraday values. Once the publication window shuts, the served value is Cboe's dated close and the broker's own reading is compared against it.

That comparison is there for a specific failure. A gateway that keeps answering with a stale value looks exactly like a quiet market: in frozen mode it re-sends its last known price on request, so the tick arrives new however old the value is, and an index carries no trade timestamp to date it with. A lapsed market-data entitlement fails this way rather than going silent. The published close is what settles it, and Regime dashboard has the verdicts and what each one does to the row.

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.

Shared ordinary quotes rejected with IBKR 354 receive one bounded delayed-aware retry under type 4, then the connection returns to type 2. The quote retains its actual live, frozen, delayed or delayed-frozen mode and source times. Live probes reuse the 30-minute retry window; usable delayed prices remain available while recovery is pending. Exact execution quotes and derivative subscriptions do not inherit this fallback.

Dealer gamma has a separate regular-hours retry. If the gateway rejects an SPY or SPX spot request with IBKR 354, Canary retries that underlying once under type 3. An entitled request still comes back live; an unentitled one may come back 15–20 minutes delayed. The retry is bounded to the failed gamma phase and the connection returns to type 2 afterwards. Nothing learned about the account is stored as an entitlement.

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. Dealer gamma can use it as a coarse daily regime input only when both spot and every option model tick are delayed together.
delayed-frozen Orientation only. It is yesterday's close.

A quote from either delayed mode is never quote_quality: firm. It reads indicative, or stale, wide or prev_close when those apply, and carries a delayed_feed warning. That holds for indices too, which have no session calendar to mark a value off-hours. During market hours a price is stale once its timestamp is more than 15 minutes old; a delayed price is judged after allowing for the feed's 20-minute lag, so an ordinary delayed print is not.

Indices are the gap in that rule. Their hours do not follow their listing venue's stock session (VIX trades extended hours, and a Cboe or Nasdaq listing says nothing about when an index is calculated), so an index quote carries no session calendar and is never called stale or off-hours. An index served only its previous close during the trading day therefore reads prev_close, not stale, and canary market counts it as covered. Its price_source: prev_close, quote_quality: prev_close and delayed_feed warning still say what it is; a consumer that needs an intraday index level must check those itself.

canary market counts a delayed quote as covered, including a delayed-frozen row that carries only the previous close, and names it under delayed. Its data_type, feed_type, price_source and warning still say which delayed value it is. A row with no price, an error or a stale quote makes the snapshot partial.

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 unknown, not evidence of a live feed; exact execution quotes require a known suitable mode.

Some computations refuse delayed input rather than producing a plausible wrong answer. Dealer gamma accepts live, frozen, and clock-aligned delayed inputs. It never mixes a delayed spot with live, frozen, or untyped option prices: a delayed run must receive IBKR's delayed model-computation tick for every priced leg. delayed-frozen is still refused.

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". Shared ordinary quotes attempt the bounded delayed-aware recovery described above. If no usable fallback arrives, the restriction remains visible and retries are bounded; repeated reads do not hammer the rejected name. While a quote is served delayed after a 354, status.market_data_access keeps naming the refusal until the next live probe, 30 minutes after the refusal. It is a log of recent refusals, not an entitlement register: a probe refused again renews the entry, a probe the gateway leaves unanswered does not, and a confirmed live price clears it. The quote's own data_type, feed_type and delayed_feed warning say that it is delayed for as long as it is. A 354 that arrives during a data-farm outage may be transient, so it does not hold back later live requests and is named there only once a delayed price is actually served; until then it is not reported as an entitlement problem. Other terminal request failures keep their backoff. A reconnect re-arms acquisition. The dealer-gamma retry remains separate and requires clock-aligned delayed spot and option evidence. 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
Position marks and quote sensors Streaming or snapshot market data for that instrument.
Option and exercise sensors Option market data for the class, typically OPRA. Contract details alone need less.
Gamma engine Option market data for SPX and SPY. After an RTH IBKR 354 it can retry once on delayed spot plus delayed option-model ticks; mixed clocks and delayed-frozen data are refused.
Breadth engine and canary technical Historical daily bars. No streaming-quote entitlement is involved.
Calendar engine 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 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.

The published series above need no broker session at all, so the vol-of-vol, cash-credit, and funding rows are unaffected. Daily bars are a separate entitlement path from streaming quotes, so canary 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 the brief and app retain session context 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.