Order Book Depth Chart — Makie.jl

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 Makie.jl

Julia source (Makie.jl)

# anyplot.ai
# depth-order-book: Order Book Depth Chart
# Library: makie 0.22.10 | Julia 1.11.9
# Quality: 90/100 | Created: 2026-06-15

using CairoMakie
using Colors
using Random

Random.seed!(42)

# Theme tokens
const THEME       = get(ENV, "ANYPLOT_THEME", "light")
const PAGE_BG     = THEME == "light" ? colorant"#FAF8F1" : colorant"#1A1A17"
const ELEVATED_BG = THEME == "light" ? colorant"#FFFDF6" : colorant"#242420"
const INK         = THEME == "light" ? colorant"#1A1A17" : colorant"#F0EFE8"
const INK_SOFT    = THEME == "light" ? colorant"#4A4A44" : colorant"#B8B7B0"
const INK_MUTED   = THEME == "light" ? colorant"#6B6A63" : colorant"#A8A79F"

# Imprint palette — position 1 (brand green) for bids; position 5 (matte red) for asks
const BID_COLOR = colorant"#009E73"
const ASK_COLOR = colorant"#AE3030"

# Data — BTC/USD order book snapshot near $60,000
const MID_PRICE = 60_000.0
const SPREAD    = 10.0
const N_LEVELS  = 50
const TICK      = 10.0

best_bid = MID_PRICE - SPREAD / 2
best_ask = MID_PRICE + SPREAD / 2

bid_prices = [best_bid - (i - 1) * TICK for i in 1:N_LEVELS]
ask_prices = [best_ask + (i - 1) * TICK for i in 1:N_LEVELS]

# Quantities — thin near mid price, thicker away from it, with realistic variation
bid_qtys = max.(0.05, 0.8 .+ collect(0:N_LEVELS-1) .* 0.04 .+ randn(N_LEVELS) .* 0.25)
ask_qtys = max.(0.05, 0.9 .+ collect(0:N_LEVELS-1) .* 0.04 .+ randn(N_LEVELS) .* 0.25)

# Large resting limit orders acting as support / resistance walls
bid_qtys[12] += 6.5
bid_qtys[28] += 9.0
ask_qtys[18] += 7.5
ask_qtys[35] += 8.5

# Cumulative volumes from best price outward
bid_cum = cumsum(bid_qtys)
ask_cum = cumsum(ask_qtys)

# Build staircase for bids (prices descend: best → worst)
bid_xs = Float64[bid_prices[1]]
bid_ys = Float64[0.0]
for i in 1:N_LEVELS
    push!(bid_xs, bid_prices[i])
    push!(bid_ys, bid_cum[i])
    if i < N_LEVELS
        push!(bid_xs, bid_prices[i + 1])
        push!(bid_ys, bid_cum[i])
    end
end

# Build staircase for asks (prices ascend: best → worst)
ask_xs = Float64[ask_prices[1]]
ask_ys = Float64[0.0]
for i in 1:N_LEVELS
    push!(ask_xs, ask_prices[i])
    push!(ask_ys, ask_cum[i])
    if i < N_LEVELS
        push!(ask_xs, ask_prices[i + 1])
        push!(ask_ys, ask_cum[i])
    end
end

# Polygon for bid fill — close staircase back to x-axis
bid_poly = [Point2f(x, y) for (x, y) in zip(
    vcat(bid_xs, [bid_xs[end], bid_xs[1]]),
    vcat(bid_ys, [0.0, 0.0]),
)]

# Polygon for ask fill
ask_poly = [Point2f(x, y) for (x, y) in zip(
    vcat(ask_xs, [ask_xs[end], ask_xs[1]]),
    vcat(ask_ys, [0.0, 0.0]),
)]

max_cum = max(maximum(bid_cum), maximum(ask_cum))

# Figure
fig = Figure(
    size            = (1600, 900),
    fontsize        = 14,
    backgroundcolor = PAGE_BG,
)

ax = Axis(
    fig[1, 1];
    title              = "depth-order-book · julia · makie · anyplot.ai",
    titlesize          = 20,
    titlecolor         = INK,
    xlabel             = "Price (USD)",
    ylabel             = "Cumulative Volume (BTC)",
    xlabelsize         = 14,
    ylabelsize         = 14,
    xlabelcolor        = INK,
    ylabelcolor        = INK,
    xticklabelsize     = 12,
    yticklabelsize     = 12,
    xticklabelcolor    = INK_SOFT,
    yticklabelcolor    = INK_SOFT,
    xtickcolor         = INK_SOFT,
    ytickcolor         = INK_SOFT,
    backgroundcolor    = PAGE_BG,
    topspinevisible    = false,
    rightspinevisible  = false,
    leftspinecolor     = INK_SOFT,
    bottomspinecolor   = INK_SOFT,
    xgridvisible       = false,
    ygridcolor         = RGBAf(Float32(INK.r), Float32(INK.g), Float32(INK.b), 0.12f0),
    yminorgridvisible  = false,
    xminorgridvisible  = false,
)

# Semi-transparent fill areas
poly!(ax, bid_poly; color = (BID_COLOR, 0.25), strokewidth = 0)
poly!(ax, ask_poly; color = (ASK_COLOR, 0.25), strokewidth = 0)

# Staircase outlines (labeled for legend)
lines!(ax, bid_xs, bid_ys; color = BID_COLOR, linewidth = 2.5, label = "Bids (Buy)")
lines!(ax, ask_xs, ask_ys; color = ASK_COLOR, linewidth = 2.5, label = "Asks (Sell)")

# Dashed vertical line at mid price
vlines!(ax, [MID_PRICE]; color = (INK_MUTED, 0.65), linestyle = :dash, linewidth = 1.5)

# Spread annotation
text!(ax, MID_PRICE, max_cum * 0.87;
    text     = "Spread: \$$(Int(SPREAD))",
    align    = (:center, :center),
    fontsize = 12,
    color    = INK_MUTED,
)

# Legend in right column
Legend(
    fig[1, 2], ax;
    framecolor      = INK_SOFT,
    framevisible    = true,
    backgroundcolor = ELEVATED_BG,
    labelcolor      = INK,
    labelsize       = 13,
    padding         = (8f0, 8f0, 8f0, 8f0),
)
colsize!(fig.layout, 2, Fixed(140))

# Axis limits — symmetric x range around mid price
x_half = (N_LEVELS - 1) * TICK + 200.0
xlims!(ax, MID_PRICE - x_half, MID_PRICE + x_half)
ylims!(ax, 0.0, max_cum * 1.1)

save("plot-$(THEME).png", fig; px_per_unit = 2)

Part of Order Book Depth Chart on anyplot.ai.

Other implementations