# /ES futures-options quote finder **Status:** future feature; no quote-finder UI, API route, or futures-options subscription is implemented yet. ## Purpose Find a small, user-selected set of `/ES` futures options more quickly than the thinkorswim option-chain UI, show their live tradable quotes, and produce an unambiguous leg or spread description that the user can copy into thinkorswim. The app assists research and pricing only. The user reviews and enters every order in thinkorswim; it must not submit, simulate, or automate orders. The first useful workflow is deliberately narrow: 1. Select a futures-option expiration and call/put side. 2. Select one or more strikes, including the two legs of a vertical spread. 3. Fetch a current snapshot of bid, ask, mark, last, volume, and open interest for that small set of exact contracts. 4. Copy a thinkorswim-tested contract or spread description for manual entry. Do not subscribe to or poll the whole option universe. Discovery should narrow the candidates first, then one REST request obtains the selected quotes. A user may explicitly refresh a stale snapshot; continuous streaming is out of scope. ## Schwab API status Checked against the configured live Schwab credentials on 2026-08-14. These were read-only requests; no account or order endpoint was called. | Capability | Result | Implication | |---|---|---| | OAuth token and Schwab client | Available | The existing app already authenticates and streams `/ES` futures. | | `get_quotes(["/ES"])` | Works: HTTP 200, resolving to active future `/ESU26` with `assetMainType: FUTURE` | Use the plural quote endpoint. `get_quote("/ES")` puts the slash in a URL path and can return the `ES` equity instead. | | `get_option_expiration_chain("/ES")` | Works: HTTP 200; it returned four `/ES` expiry entries and option root `ES` | Use it to enumerate available expiration dates and roots. | | `get_option_chain("/ES")` | Fails: HTTP 400 | It is not a usable `/ES` futures-options chain/discovery endpoint. | | `get_option_chain("/ESU26")` | Fails: HTTP 400 | Resolving the active underlying contract does not make the chain endpoint work. | | `get_quotes()` for the supplied thinkorswim text `./E3AQ26P7780:XCME` | Fails semantically: HTTP 200 with `errors.invalidSymbols` | A thinkorswim identifier is not automatically a valid Schwab REST symbol. Resolve the API equivalent explicitly. | | `get_quotes(["./E3AQ26P7780"])` | Works: `assetMainType: FUTURE_OPTION`; its reference description is `./E3AQ26P7780:XCME` | For this verified contract, the API form is the thinkorswim text with the `:XCME` exchange suffix removed. The snapshot included bid, ask, mark, last, volume, and open interest. | | `LEVEL_ONE_FUTURES_OPTIONS` for `./E3AQ26P7780:XCME` | The subscription command was accepted, but no quote handler message arrived during a 15-second premarket probe | Not needed for this feature: it uses snapshots, not continuous updates. This result is retained only as future reference. | | Historical futures-options prices | Not available | Schwab price history is not available for futures or options; the finder is a current-quote tool, not a historical-pricing system. | | Futures-options order entry | Not available for this workflow | Keep execution in thinkorswim. Schwab Trader API support for equities and standard options must not be mistaken for `/ES` futures-options routing. | The expiration endpoint narrows the date/root, but it does **not** return every strike or a quoteable option symbol. Exact futures-option symbol resolution is therefore the feature's critical discovery problem, not a formatting detail. ## Symbol and thinkorswim contract Do not invent a futures-option symbol from a guessed `ES`, month, strike, and call/put pattern. The supplied thinkorswim string `./E3AQ26P7780:XCME` maps to the verified API symbol `./E3AQ26P7780`: removing `:XCME` returned the intended `FUTURE_OPTION`, whose description returned the original thinkorswim form. This is one tested mapping, not yet a general rule for every exchange, product, expiration, or option root. Before building the finder, prove the following for representative current `/ES` options: 1. Schwab `get_quotes()` returns the intended futures option, including a valid bid and ask rather than an equity or an error. 2. The finder output can be pasted or searched in thinkorswim to select the same leg. A two-leg spread must preserve buy/sell direction and quantity as well as strike, expiration, and call/put side. Store separately any Schwab API symbol and the thinkorswim copy text. They may be identical, but that is an acceptance criterion to prove, not an assumption. ## Implementation constraints - Keep future-options code isolated with the existing broker integration in `app/market/`; no analysis, bars, or UI code should call Schwab directly. - Request REST snapshots only after a user has selected exact contracts or explicitly asked to refresh. Batch all displayed contracts into one `get_quotes()` request; do not open a futures-options WebSocket subscription. - Show quote freshness and whether data is delayed. A stale, wide, or missing market is more important than a calculated spread mark. - Treat a spread mark as a display calculation from the two current legs, not an executable price. Preserve both bid/ask combinations so the UI can show realistic debit/credit bounds. - Do not persist credentials, account details, or order state in this feature. ## First implementation gate Add a small read-only probe using representative current `/ES` options copied from thinkorswim and their mapped Schwab API identifiers. Capture both forms, the REST response type and quote fields, snapshot timestamp or delay status, and the expiration/strike shown by each system. Add a regression fixture only after that probe establishes a stable real payload and mapping rule. Until then, a full-chain UI or automatic symbol construction would be speculative.