# /ES futures-options quote finder **Status:** first version shipped. Sidebar **Options** is a lazy-load snapshot finder. It does not stream, poll, or place orders. ## Purpose Find `/ES` futures options faster than the thinkorswim chain UI: pick a nearby expiration, filter by approximate delta or mark, list the matches, and copy a thinkorswim contract string. The user reviews and enters every order in thinkorswim. ## UI Same sidebar level as Tools and Drawings. Closed by default. - **Until opened:** no calendar work, no HTTP, no Schwab. - **On first open:** `GET /api/es-options/expirations` (calendar only). - **On Search/Refresh only:** `GET /api/es-options/search` → batched `get_quotes()`. Controls: next 3 dailies, next Friday weekly, next monthly; Puts/Calls (default Puts); Delta or Price from/to; Search. Results show strike, mark, **Δ ≈**, and Copy. Last expiration, side, mode, and ranges persist in `localStorage`. ## Schwab API status Checked against the configured live credentials on 2026-08-14. Read-only. | Capability | Result | Implication | |---|---|---| | OAuth token and Schwab client | Available | The app already authenticates and streams `/ES`. | | `get_quotes(["/ES"])` | Works: `/ESU26`, `assetMainType: FUTURE` | Use the plural quote endpoint. | | `get_option_expiration_chain("/ES")` | Works, but only four standard `ES` monthlies | Not used. Dailies/weeklies are built from a calendar. | | `get_option_chain("/ES")` / `("/ESU26")` | HTTP 400 | No chain discovery. | | `get_quotes(["./E3AQ26P7780:XCME"])` | HTTP 200 + `errors.invalidSymbols` | TOS text is not the REST symbol. | | `get_quotes(["./E3AQ26P7780"])` | `FUTURE_OPTION`; description is the TOS form | REST symbol = TOS text without `:XCME`. | | Futures-option quote fields | bid, ask, mark, last, volume, OI; **no Greeks** | Delta is Black-76, labeled approximate. | | Weekday 5-point grids | 81/81 valid for `EW2`, `E3A`, `E3B`, `EW3` | Daily/weekly search uses a ±200 / 5-point grid. | | Monthly `ESU26` | 18/81 at 5-point; 25-point strikes quote | Monthly `ES` roots use a ±600 / 25-point grid. | | `LEVEL_ONE_FUTURES_OPTIONS` | Not used | Snapshots only. | | History / order entry | Not available | Current quotes; execute in thinkorswim. | ## Symbol construction Verified August 2026 weekday roots: | Weekday | Root | Example | |---|---|---| | Mon | `E{n}A` | `E3AQ26` = Aug 17 | | Tue | `E{n}B` | `E3BQ26` = Aug 18 | | Wed | `E{n}C` | `E3CQ26` = Aug 19 | | Thu | `E{n}D` | `E3DQ26` = Aug 20 | | Fri | `EW{n}` | `EW2Q26` = Aug 14 | | Quarterly monthly | `ES{month}{yy}` | `ESU26` = Sep 18 | | Serial monthly | that 3rd Friday's `EW{n}` | `EW3Q26` = Aug 21 | API: `./{root}{C\|P}{strike}`. TOS copy: that string plus `:XCME`. ## Implementation - `app/market/es_options.py` — calendar, symbols, Black-76, filters. No I/O. - `app/market/schwab_quotes.py` — REST `get_quotes` via the existing token. - `GET /api/es-options/expirations` and `GET /api/es-options/search` - Search runs in `asyncio.to_thread` so Schwab I/O does not block the loop. - IV is implied from the ATM mid; |Δ| is computed. Label **Δ ≈**. - Broker code stays in `app/market/`. No stream subscription. ## Out of scope Spreads, streaming, prefetch on page load, order entry.