import type { BestQuote, ExchangeId } from "../types"; import { Card } from "./Card"; import { clsx, usd } from "../format"; interface Props { quotes: BestQuote[]; } const LABELS: Record = { kraken: "Kraken", bybit: "Bybit", okx: "OKX", binance: "Binance", }; function statusDot(status: BestQuote["status"]): string { switch (status) { case "live": return "bg-profit"; case "stale": return "bg-warn"; case "down": return "bg-loss"; case "connecting": return "bg-slate-500"; default: { const _exhaustive: never = status; return _exhaustive; } } } export function PriceMatrix({ quotes }: Props): JSX.Element { // Highlight the best (lowest) ask and best (highest) bid across venues. const asks = quotes.map((q) => q.ask).filter((v): v is number => v !== null); const bids = quotes.map((q) => q.bid).filter((v): v is number => v !== null); const minAsk = asks.length ? Math.min(...asks) : null; const maxBid = bids.length ? Math.max(...bids) : null; const crossed = minAsk !== null && maxBid !== null && minAsk < maxBid; return ( DIVERGENCE ) : undefined } >
{quotes.map((q) => { const spread = q.ask !== null && q.bid !== null ? q.ask - q.bid : null; return ( ); })}
Exchange Bid Bid Qty Ask Ask Qty Spread
{LABELS[q.exchange]} {q.bid !== null ? usd(q.bid) : "—"} {q.bidQty?.toFixed(3) ?? "—"} {q.ask !== null ? usd(q.ask) : "—"} {q.askQty?.toFixed(3) ?? "—"} {spread !== null ? usd(spread) : "—"}
); }