An options chain scanner turns a broad contract surface into a smaller set of contracts worth showing, alerting on, or sending into deeper analysis. The hard part is not requesting a chain. The hard part is avoiding false precision from stale quotes, incomplete pagination, weak liquidity, wrong expirations, and historical leakage.
This guide describes a practical scanner architecture for current chain workflows.
It connects the Options Chain API, Option Chain docs, Options Data API, Unusual Options Activity, Options Liquidity Scanner, and Historical Options Quotes API. Use consistent terminology in scanner articles: expiration, DTE, strike, moneyness, delta, IV, Greeks, open interest, volume, bid, ask, midpoint, spread percent, quote age, pagination, OCC ticker, and reject reason.
Request order
The scanner should not begin with a made-up OCC symbol.
- Choose an underlying.
- Fetch listed expirations.
- Select an expiration or DTE policy.
- Request the chain for that date.
- Load all required pages.
- Normalize rows into a scanner table.
- Apply filters.
- Rank candidates.
- Drill into contract snapshots or quote/trade history.
- Store the decisions and rejects.
curl "https://api.cutemarkets.com/v1/tickers/expirations/AAPL/" \
-H "Authorization: Bearer YOUR_API_KEY"
curl "https://api.cutemarkets.com/v1/options/chain/AAPL/?expiration_date=2026-06-19&limit=100" \
-H "Authorization: Bearer YOUR_API_KEY"
Expiration discovery is a small step, but it prevents many scanner bugs. It keeps the UI from offering dates that are not listed and keeps the backend from guessing weekly calendars. For calendar-heavy workflows, link out to Expiration Calendar, Options Expiration Data Workflow, and Options Expiration API.
Scanner row model
Store a row model that separates identity, market data, risk fields, derived filters, and decision output.
| Group | Fields |
|---|---|
| Identity | underlying, OCC ticker, expiration, contract type, strike |
| Underlying context | underlying price, snapshot timestamp |
| Risk fields | delta, gamma, theta, vega, IV |
| Participation | open interest, volume, latest trade price, latest trade timestamp |
| Quote context | bid, ask, bid size, ask size, quote timestamp |
| Derived metrics | midpoint, spread dollars, spread percent, moneyness, DTE |
| Scanner state | loaded page, pagination complete, plan freshness, row evaluated at |
| Decision output | pass, rank, reject reason, next endpoint |
Do not store only the displayed columns. The hidden fields are what make the row auditable.
Filters
A scanner should make filters explicit. Each filter should have a reason and a failure behavior.
| Filter | Reason | Failure behavior |
|---|---|---|
| Expiration or DTE | Matches the strategy horizon | Reject if outside policy |
| Contract type | Separates calls, puts, spreads, and straddles | Reject if wrong side |
| Moneyness or delta | Keeps the contract tied to the thesis | Reject or down-rank |
| Minimum open interest | Avoids empty contract lines | Reject or mark thin |
| Minimum volume | Confirms recent attention | Down-rank if low |
| Maximum spread percent | Controls execution drag | Reject if quote exists and spread is too wide |
| Maximum quote age | Avoids stale market context | Reject if stale or missing |
| Minimum bid | Prevents impossible exits | Reject if bid is zero or too small |
| IV present | Supports volatility workflows | Reject if IV is required |
| Pagination complete | Prevents partial-surface rankings | Block ranking until complete |
The policy can be configurable, but it should not be invisible. Users and developers need to know why a row appeared.
Ranking
Ranking should happen after hard filters.
Example score components:
- lower spread percent
- higher open interest
- recent quote timestamp
- target delta proximity
- IV percentile or relative IV signal if available
- volume relative to open interest
- DTE match
- notional premium or contract price range
Avoid a single "unusual" score that hides everything. Show the evidence behind the rank. A high-volume far-wing contract with a wide market should not outrank a tighter, more usable candidate unless the scanner is explicitly designed for lottery-ticket activity.
Chain versus snapshot versus quotes
Use the chain for breadth. Use the contract snapshot after the user selects a leg. Use historical quotes when the question is fill realism. Use trades when the question is printed activity.
| User question | Endpoint |
|---|---|
| Which strikes are available for this expiration? | Chain |
| What is the current state of this one contract? | Contract snapshot |
| Was this contract executable near 10:00? | Historical quotes |
| Did anything print after the alert? | Trades |
| How did the contract move over 5-minute bars? | Aggregates |
| Did this contract exist last month? | Contracts with as_of |
This handoff is the main architectural boundary. A chain scanner that tries to answer every question from one response will either overfetch or make weak claims. The same boundary appears in Options Quotes vs Trades, Options Aggregates vs Quotes, and Why Is Last Price Bad for Options Backtesting.
Historical leakage warning
The current chain is not a historical fill surface. It is a current snapshot. If you are replaying a past event, switch to:
- contracts with
as_of - historical quotes for the selected contracts
- historical trades for activity validation
- aggregates for chart context
Do not use today's chain to choose a contract for a past date. That can include contracts that were not listed, exclude adjusted contracts, and shift the liquidity profile.
UI notes
A scanner UI should show enough context to prevent misuse:
- expiration selector backed by listed dates
- current freshness label
- plan label for live or delayed data
- quote-aware badges only when quote fields are available
- spread and quote age columns
- reject counts and reasons
- pagination or partial-load status
- selected contract links to snapshots, quotes, trades, and docs
Avoid a huge table that looks precise but hides whether quotes are stale or missing.
Related CuteMarkets docs
Scanner architecture notes
A chain scanner needs two outputs: accepted candidates and rejected candidates. Accepted rows keep underlying, expiration, OCC symbol, strike, side, DTE, moneyness, IV, Greeks, open interest, volume, quote timestamp, bid, ask, spread percent, and score inputs. Rejected rows keep the same identity fields plus the reason: stale quote, wide spread, no bid, low OI, missing size, event mismatch, or incomplete pagination.
Use Expirations before requesting the chain and Option Contract Snapshot after a user drills into one row. For historical scanners, add Contracts with as_of and Historical Options Replay Runbook. This sequence makes scanner alerts reviewable instead of turning volume into a black-box ranking.