Real-time options data is useful only when the application has a clear policy for initialization, freshness, streaming, reconnects, REST backfills, quote access, and user-facing labels. A live page that says "real time" without those details leaves too much work to the developer.
This guide describes a production-oriented design for options scanners, dashboards, alerts, and internal tools using CuteMarkets REST endpoints and, where available by plan, WebSockets.
Read it together with Real-Time Options Data API, WebSockets, Live, Delayed, and Entitlements, Options Chain Scanner Architecture, and Options Data API. The terminology should remain precise across articles: REST snapshot, WebSocket stream, reconnect, REST backfill, live data, delayed data, stale quote, latest trade, quote age, spread percent, subscription state, and entitlement.
System phases
| Phase | Goal | Data used |
|---|---|---|
| Initialize | Build the first known state | Expirations, chain snapshots, contract snapshots |
| Subscribe or refresh | Keep important state current | WebSockets where available, repeated REST snapshots otherwise |
| Validate | Decide whether a row is usable | Latest quote, latest trade, quote age, spread, OI, volume |
| Alert | Produce an event or UI update | Filtered chain rows, selected contract state, stream events |
| Backfill | Repair gaps after restart or disconnect | Historical quotes, trades, aggregates |
| Audit | Explain what the app showed and why | Request logs, subscription logs, timestamps, rejects |
A live options product should not start by streaming random symbols. It should first know which underlying, expiration, and contract set it cares about. The same idea appears in the Options Chain API page, the Option Chain docs, and the contract snapshot docs.
Initialization with REST
REST endpoints are the safest way to build the initial state.
- Fetch listed expirations for the underlying.
- Choose the relevant expiration or DTE range.
- Request the chain for that expiration.
- Apply scanner filters locally.
- Store selected OCC tickers.
- Fetch contract snapshots for selected rows if the UI needs focused panels.
- Start stream subscriptions or polling for the selected scope.
curl "https://api.cutemarkets.com/v1/tickers/expirations/SPY/" \
-H "Authorization: Bearer YOUR_API_KEY"
curl "https://api.cutemarkets.com/v1/options/chain/SPY/?expiration_date=2026-06-19&limit=100" \
-H "Authorization: Bearer YOUR_API_KEY"
The chain response should be treated as a state snapshot. It is not a permanent truth. Store the response timestamp, row count, pagination status, selected filters, and plan state.
Freshness policy
Real-time systems need freshness labels.
| Field | Why it matters |
|---|---|
snapshot_loaded_at | Shows when the app initialized or refreshed the chain |
latest_quote_timestamp | Drives quote-age checks and spread-sensitive filters |
latest_trade_timestamp | Shows recent print activity but not fill availability |
last_stream_event_at | Shows whether live updates are still flowing |
last_rest_backfill_at | Shows whether a reconnect gap was repaired |
data_freshness_label | Communicates live, delayed, stale, or unavailable state |
For user-facing tools, do not bury staleness in logs. If the quote is too old, mark it. If the plan is delayed, label it. If the latest trade is present but the latest quote is missing, do not imply that the row is quote-aware.
REST versus WebSockets
Use REST for:
- initial chain load
- expiration lookup
- selected-contract snapshots
- historical quote and trade windows
- reconnect backfill
- deterministic audits
- small internal tools that do not need continuous updates
Use WebSockets when:
- the plan includes stream access
- the product needs continuous updates
- alerts depend on low-latency changes
- the application can monitor reconnects and subscriptions
- the team is prepared to store last-seen event state
REST and WebSockets are complementary. REST gives reproducible state. Streams give movement. A robust system uses REST to rebuild, then streams or polling to maintain.
Scanner model
A real-time chain scanner should rank only after it has enough evidence.
Recommended row fields:
| Category | Fields |
|---|---|
| Identity | underlying, expiration, OCC ticker, contract type, strike |
| Risk | delta, gamma, theta, vega, IV, underlying price |
| Participation | open interest, volume, latest trade timestamp |
| Quote quality | bid, ask, size, spread dollars, spread percent, quote age |
| State | selected filters, snapshot timestamp, plan freshness, pagination status |
| Decision | pass/fail, rank score, reject reason, last evaluated at |
The scanner should fail closed when required evidence is missing. For example, if the rule says spread percent must be below 20 percent, a missing quote should reject the row rather than make it look clean.
Reconnect and backfill
A stream disconnect is a data gap, not a harmless network detail.
Reconnect policy:
- Record disconnect time.
- Record last event timestamp per subscription.
- Reconnect and resubscribe.
- Request REST history for the missed window when the endpoint supports it.
- Mark the gap as repaired or unrecoverable.
- Recompute scanner state from the repaired timeline.
- Keep the gap visible in operational logs.
Do not silently continue as if nothing happened. A user may have missed the only quote or trade that made an alert meaningful. This is why live operations and historical quote windows should share the same audit vocabulary.
Alert design
Good alerts explain their evidence.
Example alert payload:
{
"alert_type": "option_chain_liquidity_candidate",
"underlying": "SPY",
"contract": "O:SPY260619C00550000",
"expiration": "2026-06-19",
"conditions": {
"delta_band": "0.35-0.55",
"max_spread_percent": 0.15,
"min_open_interest": 500,
"max_quote_age_ms": 1000
},
"evidence": {
"bid": 4.2,
"ask": 4.35,
"spread_percent": 0.034,
"open_interest": 18420,
"latest_quote_timestamp": "2026-06-04T15:31:12.002Z",
"latest_trade_timestamp": "2026-06-04T15:30:58.220Z"
},
"source": {
"snapshot_request": "/v1/options/chain/SPY/?expiration_date=2026-06-19",
"stream_topic": "options.SPY",
"freshness": "live"
}
}
This makes the alert debuggable. If a later review asks why the row fired, the answer is in the payload.
Common mistakes
- building a live scanner from last trade only
- ranking chain rows before pagination finishes
- showing delayed data without a delay label
- assuming quote access exists on every plan
- ignoring reconnect gaps
- treating WebSockets as a replacement for historical backfill
- using live chain state to validate historical fills
- suppressing reject reasons in the UI
Related CuteMarkets docs
Real-time system notes
Real-time systems need an initialization path and a repair path. Start with REST snapshots or chains, subscribe to WebSocket topics, then use REST backfill after disconnects, missed heartbeats, or stale rows. Store subscription topic, connection id, last message time, last REST backfill window, entitlement state, and the row timestamp shown in the UI.
For options, do not treat a connected socket as proof that every contract is fresh. A chain table still needs quote age, spread state, and selected-contract snapshots. Pair this page with WebSockets, Market Data Access Methods, Quotes, and Live and Delayed Entitlements before building live alerts.