The DOM ladder
The depth-of-market order-entry ladder — side-bound click-to-trade over a live L2 book, the Elite liquidity heatmap, the cost-to-fill readout, and the PAPER/LIVE badge that says where a click goes.
The DOM lives in crates/vike-panels/src/dom.rs, whose header calls it the "Pro" click-trade
ladder plus the "Elite" order-flow surface — a time×price liquidity heatmap strip — switchable in the
window header. It is Rust-native (the Python app it descends from had no DOM), and it is pure egui
painting over vike_model::L2Book with no dependency on the execution core: draw is a stateless
render over caller-owned DomState and borrowed DomInputs, and every trader intent leaves as a
neutral DomAction the app maps to a vike_exec::Command. The same data-in, actions-out seam the
chart uses.
The interaction grammar
The header states it: click-to-trade is side-bound. The column decides the side — Buy/Bid on the
left, Sell/Ask on the right — and the row decides the price. Limit versus stop resolves by side of
market: a buy above the ask or a sell below the bid would cross, so it becomes a stop, and holding
Shift forces a stop regardless (resolve_is_stop). Clicking your own resting order cancels it;
dragging it reprices it and emits DomAction::Modify. The footer carries Close and Reverse plus
cancel-side buttons. DomAction is the complete vocabulary: Place, Modify, Cancel,
CancelSide, CancelAll, ClosePosition and Reverse.
The toolbar exposes quantity presets (QTY_PRESETS: 0.001, 0.005, 0.01, 0.05, 0.1 — BTC-scale
defaults), a price-grouping selector in ticks (GROUP_STEPS: 1, 2, 5, 10, 25, 50), recenter, and a
reduce-only arm. DomState::default starts in Pro mode on Binance at qty 0.01, grouping 1.
What the ladder is showing
DomVenue cycles Binance → Bybit → OKX → Aster → Hyperliquid in the header. The glue in
crates/vike-app-core/src/tool_views/dom.rs renders the live L2 book for the selected venue,
folded in data_sink::BookStore, and paints a synthetic stand-in
(crates/vike-app-core/src/dom_math.rs's synth_book, seeded by default_price and tick_for)
only until the first real snapshot lands. Working orders and the position are projected per venue
from the published snapshot — orders filtered to the window's venue and instrument, the position
from that venue's block — and signed_position_size resolves direction the venue-correct way:
hedge-mode perps carry it in the LONG/SHORT string, one-way and paper positions in the sign of
the size. Reading the string alone once made every short render as a long with inverted P/L and
made Close/Reverse pick the wrong side.
The ladder centres on the live book's mid rather than on the last trade, so real depth stays in view even when the last-trade mark lags a few ticks; scrolling latches a manual centre. Depth bars scale against the peak grouped quantity over the visible rows, the last-trade row is amber, and the position's average price gets a marker.
The header badge is where a click's order actually goes
header paints PAPER in amber or ● LIVE in red — in the source's own words, "where a click's
order actually goes." The glue sets paper to the inverse of the window's live flag, which is true
only when the selected venue has a credential-gated live execution client. A ● STALE badge appears
and the ladder dims when no book update has arrived inside the freshness window, so a frozen book
never reads as live.
Capabilities, not post-hoc rejects
DomInputs::caps carries the selected venue's declared adapter capabilities, filled by the app from
vike_model::caps_for. The widget consults caps.allows_modify() at drag-start, at the drop and at
the marker affordance, so a venue with no native modify never offers drag-to-reprice instead of
letting it become a reject after the fact; an unknown venue resolves to VenueCaps::UNSUPPORTED,
which offers nothing. The per-venue table this reads is described on Venues.
Elite: the liquidity heatmap
In Elite mode the region splits — the heatmap strip takes the left 42% and the ladder the rest,
sharing row geometry. DomHeatmap is a fixed-capacity ring buffer of per-row intensity columns
(180 columns by default), pushed on a throttled cadence — every sixth repaint — and normalised
against a running peak. The header describes it as the modest, egui-painter form of the surface: O(rows)
per push, rendered as rectangles, with a GPU or texture upgrade left as a later, feature-gated
change that would read the same ring buffer.
Cost to fill
DomState::cost_to_fill is an opt-in footer readout, off by default so the render path is unchanged:
for a hypothetical market order of cost_qty (which follows the toolbar quantity unless set) it
walks both sides of the displayed book and shows the projected average fill and slippage versus mid.
cost_to_fill is L2Book::simulate_fill verbatim — the same walk vike_exec::impact_veto performs
— so the basis points a trader reads here are the ones a max_slippage_bps gate compares to its
budget. cost_label states the two known divergences: an incomplete walk renders ∞ where the
slippage would go (the displayed book cannot cover the size, and the gate rejects exactly that case
as not fillable), and the gate rounds size to the venue lot grid while the readout walks the size as
typed. A one-sided book shows no slippage number rather than a fabricated zero.
What happens after the click
Every DomAction drains through crates/vike-app-core/src/order_dispatch.rs, the one place a UI
intent becomes a command. A Place is SubmitSource::Dom and a Close or Reverse is
SubmitSource::DomExit; both go through Planner::admit, the one chokepoint where the local
preview runs before anything reaches the command lane. What that preview can measure differs by
shape: a priced Place is capped on notional, computed with the instrument's contract multiplier
so the UI measures the same quantity RiskGate does; a Close or Reverse is a market leg carrying
no price, so no notional is measured for it at all and only the qty bounds apply.
OrderIntent::Modify — the drag-to-reprice — is a declared residual: it carries only the order id
and the new price, so it is not capped, and the exemption is named in an exhaustive classification
test rather than left implicit. The venue-side RiskGate remains the authority either way; see
Risk and arming and The trade panel
for the rest of that chokepoint.
The chart
The vike-chart engine — twenty styles, draggable panes, streaming indicators, price-scale modes, compare series, microstructure studies and timestamp-keyed cross-window sync.
The cockpit
The Polymarket scalp cockpit — the rolling-window chain rail, the Price-to-Beat header, the one-click ticket with its arm switch, and the probability ladder over integer-cent rungs.