From 2a158334bf3e9188e5775655febb3bbbfe278a33 Mon Sep 17 00:00:00 2001 From: u1 Date: Sat, 10 Jan 2026 23:01:36 +0000 Subject: [PATCH] feat(visualizer): add DLOB dashboard UI --- .../src/features/market/DlobDashboard.tsx | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 apps/visualizer/src/features/market/DlobDashboard.tsx diff --git a/apps/visualizer/src/features/market/DlobDashboard.tsx b/apps/visualizer/src/features/market/DlobDashboard.tsx new file mode 100644 index 0000000..969c58c --- /dev/null +++ b/apps/visualizer/src/features/market/DlobDashboard.tsx @@ -0,0 +1,136 @@ +import type { ReactNode } from 'react'; +import type { DlobStats } from './useDlobStats'; +import type { DlobDepthBandRow } from './useDlobDepthBands'; +import type { DlobSlippageRow } from './useDlobSlippage'; +import DlobDepthBandsPanel from './DlobDepthBandsPanel'; +import DlobSlippageChart from './DlobSlippageChart'; + +function formatUsd(v: number | null | undefined): string { + if (v == null || !Number.isFinite(v)) return '—'; + if (v >= 1_000_000) return `$${(v / 1_000_000).toFixed(2)}M`; + if (v >= 1000) return `$${(v / 1000).toFixed(0)}K`; + if (v >= 1) return `$${v.toFixed(2)}`; + return `$${v.toPrecision(4)}`; +} + +function formatBps(v: number | null | undefined): string { + if (v == null || !Number.isFinite(v)) return '—'; + return `${v.toFixed(1)} bps`; +} + +function formatPct(v: number | null | undefined): string { + if (v == null || !Number.isFinite(v)) return '—'; + return `${(v * 100).toFixed(0)}%`; +} + +function statusLabel(connected: boolean, error: string | null): ReactNode { + if (error) return {error}; + return connected ? live : offline; +} + +export default function DlobDashboard({ + market, + stats, + statsConnected, + statsError, + depthBands, + depthBandsConnected, + depthBandsError, + slippageRows, + slippageConnected, + slippageError, +}: { + market: string; + stats: DlobStats | null; + statsConnected: boolean; + statsError: string | null; + depthBands: DlobDepthBandRow[]; + depthBandsConnected: boolean; + depthBandsError: string | null; + slippageRows: DlobSlippageRow[]; + slippageConnected: boolean; + slippageError: string | null; +}) { + const updatedAt = stats?.updatedAt || depthBands[0]?.updatedAt || slippageRows[0]?.updatedAt || null; + + return ( +
+
+
DLOB
+
+ {market} + {updatedAt ? `updated ${updatedAt}` : '—'} +
+
+ +
+
+ stats + {statusLabel(statsConnected, statsError)} +
+
+ depth bands + {statusLabel(depthBandsConnected, depthBandsError)} +
+
+ slippage + {statusLabel(slippageConnected, slippageError)} +
+
+ +
+
+
Bid
+
{formatUsd(stats?.bestBid ?? null)}
+
+
+
Ask
+
{formatUsd(stats?.bestAsk ?? null)}
+
+
+
Mid
+
{formatUsd(stats?.mid ?? null)}
+
+
+
Spread
+
{formatBps(stats?.spreadBps ?? null)}
+
{formatUsd(stats?.spreadAbs ?? null)}
+
+
+
Depth (bid/ask)
+
+ {formatUsd(stats?.depthBidUsd ?? null)}{' '} + / {formatUsd(stats?.depthAskUsd ?? null)} +
+
+
+
Imbalance
+
{formatPct(stats?.imbalance ?? null)}
+
[-1..1]
+
+
+ +
+
+ +
+ +
+
+
+
Slippage (impact bps)
+
by size (USD)
+
+ {slippageRows.length ? ( +
+ +
+ ) : ( +
No slippage rows yet.
+ )} +
+
+
+
+ ); +}