MarketTrace
Methodology · v1.2.0 · updated 2026-11-13

Order book heatmap methodology

The order book heatmap draws the USD of limit orders resting at each price over time, combined from Binance, Bybit, OKX and Hyperliquid. This page states where the four books come from, how they are combined, what one cell holds, how the live map and the archive are built, and what the map cannot show.

See the live map at /perpetuals/order-book-heatmap.

What the map shows

Time runs left to right and price bottom to top. Each column is one moment, or one step of time on the longer windows, and each row is one price bin. A cell's brightness is the USD of limit orders resting in its bin at that time: bids below the white mid line, asks above it. The map draws resting orders only, not trades.

Data sources

Four public order book feeds of perpetual futures; none needs an API key. One process, mt-ingest, keeps a local book for every exchange and asset. How far each feed goes:

Combining the four books

Ten times a second, mt-aggdreads the four books of each asset and puts every level into a price bin of one fixed size per asset, the aggregator's bucket. A level's price is rounded down to its bin's lower edge, so nearby prices of different exchanges share a bin, and the bin keeps each exchange's quantity apart. The bin sizes:

BTC    $1
ETH    $0.10
SOL    $0.01
BNB    $0.02
XRP    $0.0002
DOGE   $0.00002
HYPE   $0.005
ZEC    $0.10
ENA    $0.00002

Hyperliquid's subscriptions describe one book at different roundings, so they are not added together: the finest one is used as far as it reaches, and each coarser one adds only the price steps wholly beyond that. A coarse level is one total for a whole price step. It goes into the bin at the price Hyperliquid reports and is not spread over the bins the step covers, since nothing says how its orders sit inside the step.

Per side, the combined book keeps the 600 occupied bins nearest the mid, none more than 5% from it. The mid is halfway between the highest best bid and the lowest best ask of the Binance, Bybit and OKX feeds that are up to date. Hyperliquid is not part of the mid.

What a cell holds

For each exchange, a bin's USD is the coin quantity resting in it times the bin's price, bids and asks apart, in whole dollars. Only bins that hold orders are recorded; an empty bin has no cell. The live feed and the archive build these values with the same function (grid_rows in mt-agg), so a live frame and an archived sample of the same moment hold the same values.

A bin below the mid normally holds bids and one above it asks. The map draws no combined best bid and best ask: across exchanges, one exchange's best bid can sit above another's best ask, and a bin then holds both.

On the 15-minute window a cell is one live frame: the whole-dollar values of the exchanges you have on, added up. On the longer windows a column stands for a step of time, and mt-api serves the history exchange by exchange: for each one, the most USD it had in the bin at any sample inside the step, bids and asks each on their own, added up over the bins a row merges (see Brightness and rows) and then rounded to three significant digits, half up (94,912,345 becomes 94,900,000; values under $1,000 stay as they are). The map adds up the rounded values of the exchanges you have on, with Hyperliquid cut first (next section); where it merges rows further, it adds them up too. So history cells are rounded and live frames carry whole dollars.

A cell's brightness is its bids plus its asks (only the side shown, when Layers in Pro hides the other). The CSV export carries the same values the map draws.

per exchange, bin and sample, bids and asks apart:
    usd = round(bin price × coin quantity in the bin)        whole dollars
live cell (15m)  = sum over the exchanges on of usd in the frame
history part     = sig3(sum over the bins a row merges of (max of usd over the step's samples))
history cell     = sum over the exchanges on of their history parts
sig3             = three significant digits, half up; under 1,000 unchanged

Hyperliquid, cut to the others' band

Hyperliquid is on by default, on the free map and in Pro. Its coarse subscriptions reach a few percent from the price, far past the other three books on BTC and ETH, and would stretch the map. So in every column, before the sum, Hyperliquid's bins outside the band from the lowest to the highest bin the other selected exchanges reach in that column are removed; bins on the band's edges stay. With no other exchange selected (Pro), Hyperliquid is shown whole. On the Pro windows the footer gives Hyperliquid's share of the archived USD in the window, counted after the cut, and counted again each time the history is asked again.

The live map and the archive

Live: the 15-minute window, Free and Pro. Once a second, mt-server reads the combined book and, if it has been updated since the last read, sends its cells over a socket. It also keeps the last 15 minutes of every asset in memory, one sample of the same cells every 5 seconds, and sends them first when the page opens: the window is whole at once, the time before the page opened in 5-second samples and the time since in one-second frames. The browser keeps the last 15 minutes, at most 900 frames, and saves nothing. A tab hidden for more than 15 seconds closes its socket and opens it again when shown; it is then sent the samples of the time it was away. The samples are held in memory only, so for 15 minutes after mt-serverrestarts the window holds less, and the footer says how much. On this window a cell is one frame's or one sample's value, and a sample stands for its 5 seconds.

The archive, for the Pro windows. Every 5 seconds, mt-book-archiveturns each asset's combined book into cells and writes them to Parquet once a minute. A daily job folds each finished day into one file and writes two roll-ups: every cell's maximum over 5 minutes and over an hour. The archive keeps 30 days. The windows read it like this:

window   one column   read from
15m      1 s          the live feed
1h       5 s          the 5-second samples
4h       10 s         the 5-second samples
1d       1 min        the 5-second samples
7d       10 min       the 5-minute roll-up
30d      1 h          the 1-hour roll-up

The roll-ups are written for the days the daily job has closed, so the steps of the current day are read from the 5-second samples, which gives the same maximum. The archive is written once a minute, so the newest columns of a Pro window come from the live frames this browser holds, folded to the window's step the same way: each exchange's most USD in the step. In the step the archive is still writing, each cell is the larger of the two. While the tab is on screen, the page asks the archive again about 90 seconds after it loads and then every 5 minutes, only for the steps since its newest archived column, and the oldest columns leave as new ones come, so the window keeps its length. A hidden tab asks nothing; shown again after 15 seconds or more, it asks at once and again about 90 seconds later. A stretch that neither covers is drawn dark.

The mid line

On the free map the white line is the combined mid described above, as each live frame carries it. With Pro it is the mid of the exchanges you have on, Hyperliquid included when it is on: in each sample, halfway between the highest best bid and the lowest best ask among those of them whose feed is up to date and that quote both sides. On the longer windows each column holds its average over the step. The archive and the live frames follow the same rule, so the line keeps its level where the two meet. A sample in which none of the exchanges you have on qualifies has no mid, and the line breaks there.

In Layers, Pro can switch the line to Each exchange: one line for each exchange you have on, in that exchange's colour, each halfway between that exchange's own best bid and best ask while its feed is up to date, averaged over the step the same way. The white line and its price label are not drawn in this mode. Each line is a mid, not the last trade price.

Brightness and rows

Brightness follows the USD on a log scale. One scale covers the whole map and is set from its non-zero cells: the dim end is their 5th percentile, never below $1,000, and the bright end their 99.5th percentile. A cell's place between the two ends, as a share of the log distance, is cubed before it is painted: a cell halfway up is drawn at an eighth of full brightness, so ordinary depth stays dim and only the largest cells light up. Cells under the dim end share the faintest shade and cells over the bright end the brightest. Bids are painted green and asks rose; a cell holding both takes the colour of the side with more USD, bids on a tie. The scale is set before the USD per bin slider, so moving the slider does not move the scale.

When the bins in view would make rows less than two pixels tall, neighbouring bins merge into one row, in powers of two up to 256, so that every row stays at least two pixels tall. A merged row holds the sum of its bins, and the footer says how many bins each row holds. The history of a Pro window arrives already merged for the price range the window is expected to span, so zooming in does not split those rows.

Coverage and gaps

On the Pro windows the footer's coverage strip marks where the archive has no data. A run of empty columns longer than 60 seconds is a gap, judged at the window's own step, so on the 30-day window an hour is either there or a gap. Time before the archive's first sample is not a gap; the strip shows it as before the archive began. The last two minutes, which the archive may not have written yet, are never marked as a gap. A gap is missing data, not an empty book.

Limitations

Versioning

Methodology version v1.2.0 · updated 2026-11-13. Material changes (new sources, a different cell rule, new windows or a different retention) bump the version and update dateModified in the structured data above.

v1.2.0 (2026-11-13): the 15-minute window is whole as soon as the page opens, because mt-server sends its last 15 minutes first, in 5-second samples. v1.1.0 (2026-11-13): bids and asks became the map's colours for everyone, brightness is cubed on the log scale so ordinary depth stays dim, and the USD per bin slider became free. v1.0.0 (2026-11-13): first published methodology for the order book heatmap.