Order Book Depth Chart — MUI X Charts

A market depth chart visualizes a snapshot of an exchange order book as two cumulative step areas around the mid price. Cumulative bid volume rises as a green step area to the left of the mid price (summing buy orders from the best bid downward), while cumulative ask volume rises as a red step area to the right (summing sell orders from the best ask upward). The bid-ask spread appears as a gap at the center, with price on the x-axis and cumulative quantity on the y-axis. This is the iconic chart found in nearly every trading and crypto exchange UI, revealing liquidity, support/resistance walls, and the imbalance between buying and selling pressure.

Order Book Depth Chart rendered with MUI X Charts

JavaScript source (MUI X Charts)

// anyplot.ai
// depth-order-book: Order Book Depth Chart
// Library: muix 7.29.1 | JavaScript 22.22.3
// Quality: 87/100 | Created: 2026-06-15
//# anyplot-orientation: landscape
// anyplot.ai
// depth-order-book: Order Book Depth Chart
// Library: MUI X Charts | React | Node 22
// License: @mui/x-charts — MIT (community). Pro/Premium are out of scope.
// Quality: pending | Created: 2026-06-15

import { LineChart } from "@mui/x-charts/LineChart";
import { ChartsReferenceLine } from "@mui/x-charts";

const t = window.ANYPLOT_TOKENS;

// --- Data (in-memory, deterministic) -----------------------------------------
const MID_PRICE = 60000;
const BEST_BID = 59995;
const BEST_ASK = 60005;
const N = 50;
const TICK = 5;

// Minimal LCG for reproducible pseudo-random data (seed = 42)
let _s = 42;
const rng = () => {
  _s = (Math.imul(1664525, _s) + 1013904223) >>> 0;
  return _s / 4294967296;
};

// Bid quantities: index 0 = best bid (nearest mid), index N-1 = worst bid
const bidQtys = Array.from({ length: N }, (_, i) => {
  const base = 0.4 + rng() * 2.0;
  const wall = i === 14 || i === 31 ? rng() * 35 + 18 : 0;
  return +(base + wall).toFixed(3);
});

// Ask quantities: index 0 = best ask (nearest mid), index N-1 = worst ask
const askQtys = Array.from({ length: N }, (_, i) => {
  const base = 0.4 + rng() * 2.0;
  const wall = i === 11 || i === 37 ? rng() * 35 + 18 : 0;
  return +(base + wall).toFixed(3);
});

// Cumulative sums from best price outward
const accumulate = (arr) =>
  arr.map((_, i) =>
    +arr
      .slice(0, i + 1)
      .reduce((a, b) => a + b, 0)
      .toFixed(3)
  );

const bidCum = accumulate(bidQtys); // [cum_at_best_bid, ..., cum_at_worst_bid]
const askCum = accumulate(askQtys); // [cum_at_best_ask, ..., cum_at_worst_ask]

// Bid prices sorted ascending: worst bid (leftmost) → best bid (rightmost)
const bidPricesAsc = Array.from(
  { length: N },
  (_, i) => BEST_BID - (N - 1 - i) * TICK
);
// Reverse cumulative so max cum is at left (worst bid), min cum at right (best bid)
const bidCumAsc = [...bidCum].reverse();

// Ask prices sorted ascending: best ask (leftmost) → worst ask (rightmost)
const askPricesAsc = Array.from({ length: N }, (_, i) => BEST_ASK + i * TICK);

// Combined x-axis (all prices, ascending); bid and ask regions separated by spread gap
const xData = [...bidPricesAsc, ...askPricesAsc];
const bidData = [...bidCumAsc, ...Array(N).fill(null)]; // null at ask positions → gap
const askData = [...Array(N).fill(null), ...askCum]; // null at bid positions → gap

const SPREAD = BEST_ASK - BEST_BID;

const W = window.ANYPLOT_SIZE.width;
const H = window.ANYPLOT_SIZE.height;
const TITLE_H = 60;

// --- Chart -------------------------------------------------------------------
export default function Chart() {
  return (
    <div style={{ width: W, height: H, display: "flex", flexDirection: "column" }}>
      <div
        style={{
          height: TITLE_H,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          color: t.ink,
          fontSize: 22,
          fontWeight: 500,
          letterSpacing: 0.3,
        }}
      >
        BTC/USD Order Book · depth-order-book · javascript · muix · anyplot.ai
      </div>
      <LineChart
        width={W}
        height={H - TITLE_H}
        skipAnimation
        xAxis={[
          {
            data: xData,
            scaleType: "linear",
            label: "Price (USD)",
            valueFormatter: (v) => `$${v.toLocaleString("en-US")}`,
            labelStyle: { fill: t.ink, fontSize: 14 },
            tickLabelStyle: { fill: t.inkSoft, fontSize: 14 },
            tickNumber: 10,
          },
        ]}
        yAxis={[
          {
            label: "Cumulative Volume (BTC)",
            labelStyle: { fill: t.ink, fontSize: 14 },
            tickLabelStyle: { fill: t.inkSoft, fontSize: 14 },
            min: 0,
          },
        ]}
        series={[
          {
            id: "bids",
            data: bidData,
            label: "Bids",
            color: t.palette[0],
            area: true,
            curve: "stepAfter",
            connectNulls: false,
            showMark: false,
          },
          {
            id: "asks",
            data: askData,
            label: "Asks",
            color: t.palette[4],
            area: true,
            curve: "stepAfter",
            connectNulls: false,
            showMark: false,
          },
        ]}
        grid={{ horizontal: true }}
        sx={{
          "& .MuiAreaElement-series-bids": { fillOpacity: 0.35 },
          "& .MuiAreaElement-series-asks": { fillOpacity: 0.35 },
          "& .MuiLineElement-series-bids": { strokeWidth: 2 },
          "& .MuiLineElement-series-asks": { strokeWidth: 2 },
          "& .MuiChartsAxis-directionX .MuiChartsAxis-line": { strokeOpacity: 0.4 },
          "& .MuiChartsAxis-directionY .MuiChartsAxis-line": { strokeOpacity: 0.4 },
          "& .MuiChartsGrid-line": { strokeOpacity: 0.5 },
        }}
        slotProps={{
          legend: {
            labelStyle: { fill: t.inkSoft, fontSize: 14 },
          },
        }}
        margin={{ top: 20, right: 60, bottom: 70, left: 95 }}
      >
        <ChartsReferenceLine
          x={MID_PRICE}
          label={`Mid: $${MID_PRICE.toLocaleString("en-US")} · Spread: $${SPREAD}`}
          labelStyle={{ fill: t.inkSoft, fontSize: 13 }}
          lineStyle={{
            stroke: t.inkSoft,
            strokeDasharray: "6 4",
            strokeWidth: 1.5,
          }}
          labelAlign="end"
        />
      </LineChart>
    </div>
  );
}

Part of Order Book Depth Chart on anyplot.ai.

Other implementations