Unusual Whales API - GEX + Greeks endpoints

Foundation reference for any MK3 strategy that reads dealer-positioning data. Ten endpoints, three families: aggregated exposure (daily snapshots), flow (intraday transactional Greeks), and spot exposures (1-minute snapshots with intraday granularity). All under /api/stock/{ticker}/.... All Bearer-auth.

This page is the source-of-truth for endpoint shapes, request params, response schemas, and how each endpoint maps to MK3 strategy primitives.

1. Base contract (applies to all 10)

PropertyValue
Base URLhttps://api.unusualwhales.com
AuthAuthorization: Bearer <token> header
Date formatYYYY-MM-DD (ISO 8601 date)
Default dateLast trading date if date omitted
Numeric formatStrings (parse to float / Decimal)
Response envelope{ "data": [ ... ] }
Rate limitsNot in per-endpoint docs - check concepts/uw-api-overview (TBD)

Reminder. UW returns numbers as JSON strings ("call_gex": "227549667.4651"). Every Python deserializer must coerce. Burned MK2 once.

2. Endpoint matrix

#FamilyPathGranularityKey extras
1ExposureGET /api/stock/{ticker}/greek-exposureDaily, time seriestimeframe (1D-2D, 1W-2W, …, YTD, 1Y)
2ExposureGET /api/stock/{ticker}/greek-exposure/expiryDaily, by expiryDTE + expiry
3ExposureGET /api/stock/{ticker}/greek-exposure/strikeDaily, by strike
4ExposureGET /api/stock/{ticker}/greek-exposure/strike-expiryDaily, strike × expiryRequires expiry query param
5FlowGET /api/stock/{ticker}/greek-flowIntraday total flowTransactional, not positional
6FlowGET /api/stock/{ticker}/greek-flow/{expiry}Intraday flow by expiryPath param expiry
7SpotGET /api/stock/{ticker}/spot-exposures1-minuteTime-series of intraday spot Greeks
8SpotGET /api/stock/{ticker}/spot-exposures/expiry-strikeDaily, strike × expiry (v2)expirations[], pagination, DTE filters
9SpotGET /api/stock/{ticker}/spot-exposures/strikeDaily, by strikeStrike + pagination filters
10SpotGET /api/stock/{ticker}/spot-exposures/{expiry}/strikeDEPRECATED - use #8v1, do not build new code against this

3. Family 1: Greek Exposure (positional, daily)

These return dealer positioning (where the book is right now). One data point per trading date. Use for regime gates, OPEX framing, daily context.

3.1 GET /api/stock/{ticker}/greek-exposure

Aggregate Greeks across all strikes + all expiries, one row per trading date over a timeframe.

ParamTypeRequiredDefaultNotes
ticker (path)stringyes-AAPL, SPY, …
date (query)datenolast trading date
timeframe (query)stringno1Y1D, 2D, 1W, 2W, 1M, 2M, 1Y, 2Y, YTD

Response fields per row:

FieldDescription
dateTrading date
call_charmAggregate call charm GEX
call_deltaAggregate call delta GEX
call_gammaAggregate call gamma GEX
call_vannaAggregate call vanna GEX
put_charmAggregate put charm GEX
put_deltaAggregate put delta GEX
put_gammaAggregate put gamma GEX
put_vannaAggregate put vanna GEX

Use in MK3: primary daily regime feature. net_gex = call_gamma - put_gamma drives the negative-GEX trend gate (60.5% hit rate per 2026-05-22-uw-historical-findings).

3.2 GET /api/stock/{ticker}/greek-exposure/expiry

Same Greeks, broken by expiration date.

ParamTypeRequiredDefault
ticker (path)stringyes-
date (query)datenolast trading date

Response per row: expiry, dte, date, call_delta, call_gex, call_vanna, call_charm, put_delta, put_gex, put_vanna, put_charm.

Use in MK3: OPEX-week regime modulation, term-structure of dealer positioning. The 0DTE row is the most informative for SPY hunter.

3.3 GET /api/stock/{ticker}/greek-exposure/strike

Same Greeks, broken by strike.

ParamTypeRequiredDefault
ticker (path)stringyes-
date (query)datenolast trading date

Response per row: strike, call_gex, call_delta, call_vanna, call_charm, put_gex, put_delta, put_vanna, put_charm.

Use in MK3: locate gamma walls and pin levels. The strike with the largest call_gex + |put_gex| cluster is the magnet level for 0DTE.

3.4 GET /api/stock/{ticker}/greek-exposure/strike-expiry

Cross of strike × single expiry. expiry is REQUIRED.

ParamTypeRequiredDefault
ticker (path)stringyes-
expiry (query)dateyes-
date (query)datenolast trading date

Response per row: strike, expiry, call_delta, call_gex, call_vanna, call_charm, put_delta, put_gex, put_vanna, put_charm.

Use in MK3: the finest cut of dealer positioning. For 0DTE SPY, this is the table that tells you “the dealer book is short gamma below 580 and long gamma above 585” - exactly where pinning fails and trends start.

4. Family 2: Greek Flow (transactional, intraday)

Flow ≠ exposure. Flow is what the tape just executed (transactional delta/vega change). Exposure is where the book sits. Trade flow is what shifts exposure.

4.1 GET /api/stock/{ticker}/greek-flow

Aggregate intraday flow.

ParamTypeRequiredDefault
ticker (path)stringyes-
date (query)datenolast trading date

Response fields:

FieldDescription
tickerSymbol
timestampISO 8601
transactionsTrade count
volumeTotal volume
total_delta_flowSum
total_vega_flowSum
dir_delta_flowDirectional (signed) delta flow
dir_vega_flowDirectional (signed) vega flow
otm_total_delta_flowOTM-only total
otm_total_vega_flowOTM-only total
otm_dir_delta_flowOTM-only directional
otm_dir_vega_flowOTM-only directional

Use in MK3: real-time aggressor confirmation. Crucially, per 2026-05-22-uw-historical-findings, strongly positive dir_delta_flow on OTM calls is CONTRARIAN-bearish, not bullish - high call-buying predicts SPY down -3.6 to -8.7 lift below baseline. Sign carefully.

4.2 GET /api/stock/{ticker}/greek-flow/{expiry}

Same fields plus expiry, filtered to one expiration.

ParamTypeRequiredDefault
ticker (path)stringyes-
expiry (path)dateyes-
date (query)datenolast trading date

Use in MK3: 0DTE-isolated flow. For SPY hunter, query expiry = today’s date.

Example response (from docs):

{
  "data": [
    {
      "ticker": "SPY",
      "expiry": "2024-10-28",
      "timestamp": "2024-10-28T18:46:00Z",
      "transactions": 1188,
      "volume": 12348,
      "total_delta_flow": "-21257.36",
      "total_vega_flow": "350944.58",
      "dir_delta_flow": "-43593.96",
      "dir_vega_flow": "31243.04",
      "otm_total_delta_flow": "-28564.02",
      "otm_total_vega_flow": "101745.64",
      "otm_dir_delta_flow": "14947.51",
      "otm_dir_vega_flow": "11421.03"
    }
  ]
}

5. Family 3: Spot Exposures (positional, 1-minute intraday)

The crown jewel for intraday work. Same Greeks as Family 1 (positional, not flow) but refreshed every minute through the trading session. The dimensional cuts also split exposure across vol, oi, dir, and bid/ask bands, giving a much richer view than the daily summaries.

5.1 GET /api/stock/{ticker}/spot-exposures

Per-minute aggregate spot exposures.

ParamTypeRequiredDefault
ticker (path)stringyes-
date (query)datenolast trading date

Response per row:

FieldDescription
timeISO 8601 timestamp (per-minute)
priceUnderlying spot price at snapshot
gamma_per_one_percent_move_volGamma exposure per 1% move (volume-weighted)
gamma_per_one_percent_move_oiGamma exposure per 1% move (open-interest weighted)
gamma_per_one_percent_move_dirGamma exposure per 1% move (directional / signed)
vanna_per_one_percent_move_volVanna per 1% move (vol)
vanna_per_one_percent_move_oiVanna per 1% move (OI)
vanna_per_one_percent_move_dirVanna per 1% move (dir)
charm_per_one_percent_move_volCharm per 1% move (vol)
charm_per_one_percent_move_oiCharm per 1% move (OI)
charm_per_one_percent_move_dirCharm per 1% move (dir)

Use in MK3: the regime gate becomes intraday-dynamic. Instead of “net GEX from yesterday’s close” you have “net GEX one minute ago”. The _dir variants are signed (long vs short dealer position), so the negative-GEX trend gate can be re-evaluated minute by minute.

5.2 GET /api/stock/{ticker}/spot-exposures/expiry-strike (v2)

Strike × expiry cut of spot exposures with full filter set. Use this, not the deprecated v1.

ParamTypeRequiredDefault
ticker (path)stringyes-
expirations[] (query, repeatable)dateyes-
date (query)datenolast trading date
limit (query)intno500 (max 500)
page (query)intno0
min_strike (query)numberno-
max_strike (query)numberno-
min_dte (query)intno-
max_dte (query)intno-

Response per row: call and put variants of: {delta,gamma,vanna,charm}_{ask,bid,oi,vol} (16 fields per side, 32 total) plus price, time, strike, expiry.

That _ask/_bid/_oi/_vol split is unique to spot-exposures (Family 3) - the aggregate daily Greek exposure endpoints (Family 1) do not provide it. It separates book (_oi), demand-paid (_ask), supply-paid (_bid), and traded (_vol) exposure.

5.3 GET /api/stock/{ticker}/spot-exposures/strike

Strike-only cut, no expiry filter. Same field set as 5.2 minus the expiry breakout.

ParamTypeRequiredDefault
ticker (path)stringyes-
date (query)datenolast trading date
min_strike (query)numberno-
max_strike (query)numberno-
limit (query)intno500 (max 500)
page (query)intno0

5.4 GET /api/stock/{ticker}/spot-exposures/{expiry}/strike (DEPRECATED)

V1 of the strike+expiry cut, marked deprecated in docs. Use 5.2 (/expiry-strike) instead. Listed here only so any future Codex session that finds it in legacy code knows to migrate, not extend.

6. MK3 strategy mapping

How each family lands in Setup Hunter:

NeedEndpointCadence
Daily regime gate (negative GEX trend day)3.1 /greek-exposure (or 5.1 /spot-exposures for intraday refresh)Once at open + minute refresh
OPEX framing3.2 /greek-exposure/expiryOnce daily
Gamma wall + pin level for 0DTE3.3 /greek-exposure/strike or 5.3 /spot-exposures/strikeOnce at open, refresh on big moves
Strike-expiry book (where dealers flip from short to long gamma)3.4 /greek-exposure/strike-expiry or 5.2 /spot-exposures/expiry-strikeOnce at open + on regime change
Aggressor flow (contrarian gate)4.1 /greek-flowEvery minute
0DTE-isolated flow4.2 /greek-flow/{expiry}Every minute
Intraday dynamic GEX (the live regime signal)5.1 /spot-exposuresEvery minute

The Setup Hunter spine (2026-05-15-mk3-setup-hunter-architecture) gates trades on regime first; this API surface is the substrate for that gate. The contrarian-aggressor finding (2026-05-22-uw-historical-findings) lives in family 2.

7. Nautilus integration shape (design notes, not code)

The UW REST surface fits Nautilus’s Actor + custom-data model cleanly:

  1. Custom data classes (one per endpoint family, defined with @customdataclass):

    • UWGreekExposure (family 1)
    • UWGreekFlow (family 2)
    • UWSpotExposure (family 3)

    Each carries ts_event from the response time/timestamp and ts_init from the receive time. Numeric strings get coerced in __post_init__.

  2. Polling Actor (UWGreeksActor) - background task on the Nautilus message bus that:

    • At session start: pulls daily exposure family (1.1-1.4).
    • Every minute: pulls family 3 spot exposures and family 2 flow.
    • Publishes each row to the MessageBus as the matching custom-data type.
  3. Subscribers (Strategy / signal computations) consume from the bus via subscribe_data(UWSpotExposure) and compute derived features (net_gex, dir_delta_flow_zscore, etc.).

  4. Determinism: timestamps go through self.clock for replay. Don’t read wall-clock in derived feature math.

  5. Adapter authoring contract: concepts/nautilus-dev-adapters.md (the Adapter Authoring Bible). Phase 1-7 of that doc is the gate for landing this in MK3. Codex-only territory.

8. Known gaps + follow-ups

  • Rate limits not on per-endpoint docs. Need to file concepts/uw-api-overview from the root docs page (auth, rate limits, response envelope conventions).
  • No WebSocket here. This page only covers REST. The streaming side (live flow + spot exposures push) is a separate set of docs; file under concepts/uw-api-streaming when those URLs arrive.
  • Account / portfolio endpoints absent. Not relevant to MK3 at current scope.
  • No historical bulk endpoint visible. The 1Y Parquet bundle is a separate data-shop product, not these REST endpoints.

9. Source URLs (verbatim, for re-fetch)

  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.greek_exposure
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.greek_exposure_by_expiry
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.greek_exposure_by_strike
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.greek_exposure_by_strike_expiry
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.greek_flow
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.greek_flow_expiry
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.spot_exposures_one_minute
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.spot_exposures_by_strike_expiry_v2
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.spot_exposures_by_strike
  • https://api.unusualwhales.com/docs/operations/PublicApi.TickerController.spot_exposures_by_strike_expiry

2026-05-22-uw-historical-findings 2026-05-15-mk3-setup-hunter-architecture 2026-05-15-mk3-data-foundation-constraint nautilus-dev-adapters nautilus-custom-data