DEV Community

Cover image for The 0DTE Gamma Heatmap API: Strike-by-Time GEX, a HIRO and Heatseeker Alternative
tomasz dobrowolski
tomasz dobrowolski

Posted on • Originally published at flashalpha.com

The 0DTE Gamma Heatmap API: Strike-by-Time GEX, a HIRO and Heatseeker Alternative

A strike-by-time gamma heatmap is the chart SpotGamma TRACE and Skylit Heatseeker are known for. GET /v1/flow/zero-dte/heatmap/{symbol} returns that same strike × time matrix for today's 0DTE chain as plain JSON — so you render it in your own stack or feed it to a model instead of staring at someone else's dashboard. It's the per-strike layer of the broader live 0DTE flow family.

Read this first. The heatmap is built on FlashAlpha's flow model — effective open interest plus aggressor-classified trades — not a dealer's actual book. The values are estimates. Read the bands, shifts, and signs as a relative map of where positioning sits, not exact dealer inventory.

What a strike-by-time heatmap shows

A single GEX snapshot tells you where dealer gamma sits right now. A heatmap adds the dimension every 0DTE trader wants: how that profile moves through the session. Strikes down one axis, time across the other, color encodes the metric. Read across a row to see one strike build or bleed; read down a column for the whole profile at one instant; watch the bright bands migrate to see the magnet and walls shift.

That migration is the signal. A bright positive-gamma band that locks onto a strike and stays is pinning. A band bracketing price that thins out means the walls are weakening and a breakout gets easier. On a 0DTE chain this happens within hours — a static morning chart misses it, a live matrix doesn't.

The endpoint

GET /v1/flow/zero-dte/heatmap/{symbol}?bar=1m&metric=gex&mode=raw&minutes=60

Strikes are pulled out into a top-level strikes_grid, and each bar's values array is parallel by index — so you index it as values[bar][strike], exactly the shape a heatmap library wants. Roughly 30% smaller on the wire than per-cell objects.

{
  "symbol": "SPX",
  "underlying_price": 6012.4,
  "expiration": "2026-06-12",
  "metric": "gex",
  "mode": "raw",
  "bar_size": "1m",
  "as_of": "2026-06-12T18:45:12Z",
  "market_open": true,
  "strikes_grid": [5995, 6000, 6005, 6010, 6015, 6020],
  "bars": [
    { "t": "2026-06-12T18:43:00Z", "spot": 6011.8,
      "values": [-1.1e9, -3.8e8, 1.9e8, 9.0e8, 1.7e9, 2.8e8] },
    { "t": "2026-06-12T18:44:00Z", "spot": 6012.1,
      "values": [-1.2e9, -4.0e8, 2.1e8, 9.5e8, 1.8e9, 3.0e8] }
  ],
  "gap_intervals": []
}
Enter fullscreen mode Exit fullscreen mode

Six metrics, one grid

The metric parameter swaps what the color channel represents:

  • gex — gamma exposure per strike (default). Bright positive = pin zones, deep negative = accelerant zones.
  • dex — delta exposure, directional dealer positioning.
  • vex — vega exposure, vol sensitivity by strike.
  • chex — charm exposure, where decay forces the fastest re-hedging into the close.
  • oi — effective open interest, the raw positioning mass.
  • signed_flow — net signed aggressor flow, where customers are buying (+) or selling (−) right now.

Raw vs delta mode

  • mode=raw shows the level at each cell — where the walls and magnet sit.
  • mode=delta shows the bar-over-bar change — where positioning is landing this minute. The closest analog to a HIRO-style "what just changed" read; a strike lighting up in delta often flags fresh flow before it shows in the raw level.

Common workflow: raw as the background field, delta as the overlay flagging active strikes.

Pull it and plot it

import numpy as np
import matplotlib.pyplot as plt
from flashalpha import FlashAlpha

fa = FlashAlpha("YOUR_KEY")
d = fa.flow_zero_dte_heatmap("SPX", metric="gex", mode="raw", bar="1m", minutes=120)

strikes = d["strikes_grid"]
times   = [b["t"][11:16] for b in d["bars"]]
spot    = [b["spot"] for b in d["bars"]]
grid    = np.array([b["values"] for b in d["bars"]]).T  # -> [strike][bar]

plt.imshow(grid, aspect="auto", origin="lower", cmap="RdBu_r",
           extent=[0, len(times), strikes[0], strikes[-1]])
plt.plot(np.arange(len(times)) + 0.5, spot, color="black", lw=1)  # spot overlay
plt.colorbar(label=f"{d['metric'].upper()} ({d['mode']})")
plt.title(f"{d['symbol']} 0DTE {d['metric'].upper()} heatmap")
plt.show()
Enter fullscreen mode Exit fullscreen mode

JavaScript / Plotly:

import { FlashAlpha } from 'flashalpha';

const fa = new FlashAlpha('YOUR_KEY');
const d = await fa.flowZeroDteHeatmap('SPX', { metric: 'gex', mode: 'delta', bar: '1m', minutes: 120 });

const z = d.strikes_grid.map((_, j) => d.bars.map(b => b.values[j]));  // transpose
const trace = { type: "heatmap", colorscale: "RdBu", reversescale: true,
  x: d.bars.map(b => b.t), y: d.strikes_grid, z };
Plotly.newPlot("chart", [trace], { title: `${d.symbol} 0DTE ${d.metric}` });
Enter fullscreen mode Exit fullscreen mode

vs SpotGamma TRACE and Skylit Heatseeker

Both popularized the intraday strike-by-time heatmap, and both are excellent dashboards. The gap they leave is programmatic access — you watch their chart, you don't pull their matrix. FlashAlpha returns the matrix as JSON: render it in your own stack, alert on a band crossing a strike, or feed it straight into a model. The point isn't that it looks better — it's that it's callable. It also pairs with FlashAlpha's numeric pin score and trade-setup classifier. The data is FlashAlpha's own, not resold from either product.

When you want the signed aggressor detail underneath — net delta-dollars, gamma-dollars, and contract counts per strike per bar — the companion GET /v1/flow/zero-dte/strike-flow/{symbol} returns three parallel arrays against the same grid.

Both the heatmap and strike-flow endpoints are on the Alpha plan (from $1,199/mo, unlimited requests) — the model-input granularity of the 0DTE flow family. Calling below Alpha returns 403 tier_restricted.

Full reference and an interactive playground: flashalpha.com

Top comments (0)