Skip to main content
NOTE: This is the documentation for the websocket channels greek_flow_expiry and greek_flow_expiry:<TICKER>. For the same data aggregated across all expiries, see greek_flow. Websocket access for personal use is only available through the Advanced plan. You can find fully-functional examples that stream data from many channels here: Connect to the websocket URI: wss://api.unusualwhales.com/socket?token=<YOUR_API_TOKEN> then join the channel you wish to stream, for example greek_flow_expiry:SPY for SPY’s delta and vega flow broken out per option expiry. Omit the ticker suffix to receive updates for every ticker. Each message carries the delta and vega exposure of the option trades that printed for one ticker, in one minute, for a single option expiry, and arrived since the previous message for that minute and expiry; see Delivery characteristics below for how to sum them. Both channels are built from the same option trades, so once every message for a minute has arrived, that minute’s expiries sum to the same minute on the greek_flow channel. total_* fields carry the greek’s own sign - for delta that means calls contribute positive and puts negative - so they are net greek exposure regardless of who was the aggressor. dir_* fields instead sign the magnitude by trade sentiment: for delta, bullish trades (bought calls, sold puts) positive and bearish negative; for vega, buys (ask side) positive and sells (bid side) negative. Mid/no-side trades are excluded from every dir_* field.

Delivery characteristics

Read these before writing a client, they are not obvious from the payload:
  • Each message is a partial sum, not a running total. A minute’s bucket is flushed roughly once per second as trades arrive, so to get that minute’s total for one expiry you must add together every message sharing the same ticker, timestamp and expiry. Grouping on timestamp alone is wrong even on the per-ticker channel, since every expiry that traded carries that same minute; on the global channel every ticker does too. A client that overwrites on the key instead of adding will silently under-report.
  • Because of that, a dropped frame does not just delay a value, it changes your sum. Read from the socket promptly: a slow consumer is not disconnected, but frames it fails to keep up with are dropped.
  • Updates are trade-driven, not scheduled. An expiry with no option trades in the window produces no message at all - there is no per-minute tick and no zero-valued heartbeat. A minute bucket is also never announced as closed: messages carrying a given timestamp simply stop arriving.
  • This channel carries considerably more messages than greek_flow - one per expiry that traded, rather than one per ticker.
  • The channels are keyed by the root ticker: weekly/PM index series are folded into their root (SPXW under SPX, NDXP under NDX, VIXW under VIX, RUTW under RUT). Joining greek_flow_expiry:SPXW is acknowledged as, and streams, greek_flow_expiry:SPX.
  • All flow values are decimal strings, matching the REST endpoint below.
This is the live counterpart of /stock/:ticker/greek-flow/:expiry, which returns the same fields with the same encodings. Note the REST endpoint serves each minute’s accumulated total, while this channel serves the per-second partials that add up to it. Payload format for greek_flow_expiry:<TICKER>:

Field reference

Last modified on September 28, 2026