# Liquidity heatmap

> How Flowscope records resting liquidity and how to read the heatmap, bubbles and book profile.

The liquidity heatmap shows where limit orders rested over time. Each price level is a thin horizontal line whose brightness is the resting size. Walls glow, thin liquidity fades, and you can see orders arrive, sit and get pulled or filled.

## How it is recorded

Flowscope keeps the exact order book of every open market live: a snapshot plus every change from the venue's websocket, with the venue's sequence checks.

From that book it records **each price bucket's resting size at the close of every minute**, stored as runs:

```text
(start, duration, price bucket, quantity, side)
```

- A price bucket is about 0.001 % of the price.
- A run is cut only where a bucket's size at one minute's close differs from the minute before, so a level that rests for hours is one run, not a snapshot per minute.
- The minute that is forming shows the book as it stands; once it closes, it keeps what stood at its close.
- A gap in the venue's sequence, or a dropped connection, ends every run at that instant, clears the book and resynchronizes. Nothing is invented to fill the gap.

What this gives up, by choice, is whatever happens inside a minute: an order that came and went within it, such as the one that sat for 400 ms or the wall pulled and re-posted, is not in the record. On bars shorter than a minute the heatmap moves in minute steps.

How far above and below the price the heatmap reaches is how deep each venue publishes its book. For BTC (measured October 2026):

| Venue | How the book is built | Reach around the price |
|---|---|---|
| Coinbase | The whole book on the stream, then every change | everything: cents to millions |
| Deribit | The whole book on the stream, then changes chained by id; inverse amounts in BTC | everything: $6 700 to $300 000 for BTC |
| Binance spot | REST snapshot (5 000 levels) and 100 ms depth deltas | about ±1 % at first, wider as the price moves |
| Binance Futures | REST snapshot (1 000 levels) and 100 ms depth deltas | about ±0.2 % |
| Bybit | 1 000-level snapshot and deltas on the stream | about ±0.2 % |
| Bybit Spot | 1 000-level snapshot and deltas on the stream | about ±0.8 % |
| OKX Spot | 400-level snapshot and deltas on the stream | about ±0.2 % |
| Kraken | 1 000-level snapshot and updates on the stream; levels that leave its depth are dropped here | about ±3 % |
| OKX | 400-level snapshot and deltas on the stream, quantities scaled by contract value | about ±0.06 % |
| Aster | REST snapshot (1 000 levels) and 100 ms depth deltas | about ±2 % |
| Lighter | The whole book on subscription, then updates | the whole book |
| Hyperliquid | Full book images every block, diffed against the previous one | 20 levels a side |

An aggregated market (**All venues**) sums them, so its heatmap reaches as far as the deepest venue in it. Coinbase is one of the venues BTC, ETH and the other majors sum by default, so walls thousands of dollars away show.

## Adding it to a chart

The heatmap is the **Liquidity Heatmap** study. It is already on liquidity charts and the included [Liquidity & execution layout](/docs/app/layouts#starting-a-layout). Add it to any chart from the indicator dialog (<kbd>/</kbd>), group **Heatmaps**.

The **Liquidity (price line)** chart type hides the bars entirely and leaves the heatmap and a price line. It is the cleanest way to read liquidity.

## Settings

| Setting | What it does | Default |
|---|---|---|
| Markets | The markets the heatmap reads: the chart's, another market of its coin, or several summed. See [Markets of an indicator](#markets) | The chart's |
| Colours | Ramp, 26 of them: Ocean, Thermal, Viridis, Mono, Magma, Inferno, Plasma, Turbo, Bookmap, Cividis, Mako, Rocket, Ice, Cubehelix, Deep, Parula, Jet, Rainbow, Spectral, Coolwarm, Hot, Copper, Bone, Blackbody, Electric or Sunset | Ocean |
| Range from, range to | Which part of the size distribution maps onto the ramp | 0.08 to 1.0 |
| Contrast | Gamma of the mapping | 0.9 |
| Saturation percentile | The visible size that maps to full intensity | 0.995 |
| Opacity | How strongly the heatmap covers the chart | 1.0 |
| Show range slider on chart | The floating slider over the chart | On |
| Style | Lines, Classic, Splat or Gaussian splat; see [Styles](#styles) | Lines |
| HD | The finest bins; off is SD, coarser. See [HD and SD](#hd-and-sd) | On |
| Classic: show sizes in cells | Each cell's size written in it, where it fits | On |
| Classic: row height, column width (px) | The size of a Classic cell in HD; SD doubles both | 14, 30 |
| Auto levels: show only sizes that stand out | Draws only sizes that stand out from the rest in view; the legend shows from what size (`≥ size`) | On |
| Low size | Sizes below are not drawn; `0` leaves it to the range and auto levels | 0 |
| Peak size | The size drawn at full colour; `0` measures it from what is in view | 0 |
| Sizes around the pointer on hover | The lens: a table of the surrounding cells around the pointer, with each cell's time, band, size and bid share | On |
| Lens grid | 3 × 3, 5 × 5 or 7 × 7 cells | 5 × 5 |
| Extend the live levels | Levels resting now drawn past the last bar, updated as the book changes | Off |
| Extension bars (0: right edge) | Number of chart bars beyond the newest bar; `0` extends to the right edge. Applies to all heatmap styles | 0 |

The floating range slider is the quickest control. Drag its left handle up to hide thin liquidity; drag the right handle down to saturate walls sooner. Its buttons turn auto levels on or off (the magic wand), switch between HD and SD, reset the range, switch between Lines and Classic, open the heatmap settings, or hide the slider. The slider appears when the chart is larger than about 380 × 160 px.

### Styles {#styles}

| Style | How a level is drawn |
|---|---|
| Lines | Each price bucket as it rests: a thin line where the bucket is taller than three pixels, its pixels where it is smaller |
| Classic | Cells of one or more bars by a band of prices, each holding the size that rested there over the bar |
| Splat | Each level spread a few pixels up and down, fading: soft blobs that read well under other layers |
| Gaussian splat | Each level keeps its core and gets a Gaussian glow; where many levels sit together, the glow adds up |

### HD and SD {#hd-and-sd}

HD draws the finest bins: every price bucket on its own in Lines and the splats, and Classic cells as set. SD merges more of the book into each bin: four buckets into one filled row in Lines and the splats, and Classic cells twice as tall and twice as wide. HD suits short timeframes and precise reading, SD longer ones.

### Low and peak size {#low-and-peak-size}

With a peak size set, the colours no longer follow what is in view: sizes from the low size up are drawn, and the peak size and above at full colour. Use them to keep one scale while scrolling, or to compare charts. Both `0` (the default) measure the scale from the view.

Intensity is relative to what is on screen: a percentile of the visible sizes maps to full brightness. Zooming into a quiet area brings out structure that a busy area would drown.

## Smooth panning

Rasterizing runs on an engine worker, never on the interface thread. A raster reaches past the plot on every side and is drawn again only when the view leaves that margin, the zoom changes or the book does. While a new image is on its way, the chart keeps drawing the last one mapped into the current view, so panning and zooming stay smooth.

When only the book changed, only the live part is drawn again: the columns from the minute that was forming at the last image on. The history in view stays as it was drawn, as a minute's levels are its close's. That takes about a millisecond where a whole image takes a hundred, so the heatmap follows the book live even in the browser. Every five seconds, and whenever history from the hub arrives, the image is drawn whole once. Zoomed far out, the hub sends its history at a coarser time resolution (down to one slot an hour), so a week in view loads and draws far fewer levels.

## Trade bubbles

The **Trade Bubbles** study draws the largest market orders in view as circles sized by quantity, buys and sells in their own colours.

| Setting | Default |
|---|---|
| Bubbles in view | 60 (5 to 400) |
| Hide below (fraction of the largest) | 0.06 |
| Size | 1.0 |
| Fill opacity | By the bubble's size (0); or one opacity for all |
| Outline thickness | 1 px; 0 draws none |

## Order book profile

The **Order Book Profile** study draws the current book as horizontal bars at the right edge of the chart, bids and asks in their own colours. Its width defaults to 96 px.

## Aggregated heatmaps

On an [aggregated market](/docs/app/aggregated-markets) the heatmap is drawn from the summed book of its venues. Each venue's contribution is tracked separately, so a venue that resynchronizes or disconnects removes exactly what it added.

### Markets of an indicator {#markets}

The heatmap does not have to read the chart's market. **Markets** in its settings opens the same picker as a pane's: the coin's venues in a perpetuals, a coin-margined and a spot column, each with **All**, the chart's market marked `current`. Choose one market to see its heatmap on this chart, or several to see them summed: an aggregated heatmap of Binance, Bybit and OKX over a Binance chart. **Chart's market** goes back to the chart's own. The legend names the choice (`Heatmap Viridis · 3 markets`).

The Liquidation Heatmap, Trade Bubbles, the Order Book Profile and Liquidations have the same setting, and so do the indicators computed from bars: CVD, Delta Volume, Volume, Trade Counter, Open Interest, Net Positioning, OB Depth and Liquidation Volume. Those run on the bars of their markets at the chart's interval and land on the chart's bars by time (a CVD of its own markets draws their sum, not one line per venue). [Bar Stats](/docs/app/bar-stats) reads every row from its markets' bars the same way, and the [visible-range volume profile](/docs/app/profiles#vpvr) is built from their footprints over the time on screen. The footprint chart itself shows the chart's market: open an [aggregated market](/docs/app/aggregated-markets) for a footprint of several venues. Each indicator keeps its own choice. When the chart turns to another coin, the same venues are taken for it, and venues that do not list the coin are left out.

The history of a summed choice is summed too. The hub records every venue's heatmap; for a choice of venues it sums their recorded hours when the app asks for them, so the aggregated heatmap reaches back as far as its venues were recorded. Changing the choice draws the heatmap again from the new sum.

## History

No venue publishes historical order books: heatmap history is what the data hub recorded, once a minute. The hub serves its [recorder](/docs/recorder)'s tiles for the hours before you opened the market, back as far as it recorded the market (`make dev` runs one; the browser app reaches it at `/hub`). The app keeps no heatmap on the machine: each session loads it from the hub again.

> [!NOTE]
> Serving sealed heatmap hours from object storage is planned, as is a level-of-detail pyramid for very long windows. Today the hub serves the tiles from its own disk.

## Related layers

- [Liquidation heatmaps](/docs/app/liquidations#liquidation-heatmap) use the same raster with their own ramps: modelled liquidation levels, and measured Hyperliquid take-profits, stops and liquidations.
- The [depth book](/docs/app/dom-and-tape#depth-book) shows the current book as a list with cumulative depth.
