diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 8e182bb..ce8fe40 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -232,7 +232,13 @@ const buildApiUrl = (path: string): string => { }; const formatPrice = (price: number): string => { - return price.toFixed(2); + if (!Number.isFinite(price)) { + return "0.00"; + } + return price.toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); }; const formatSize = (size: number): string => { @@ -257,6 +263,19 @@ const formatUsd = (value: number): string => { }); }; +const normalizeContractId = (value: string): string => value.trim(); + +const formatContractLabel = (value: string): string => { + const normalized = normalizeContractId(value); + if (!normalized) { + return "Unknown contract"; + } + if (/^\d+$/.test(normalized)) { + return `Instrument ${normalized}`; + } + return normalized; +}; + const formatDateTime = (ts: number): string => { const date = new Date(ts); return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; @@ -2032,13 +2051,14 @@ export default function HomePage() { const nbboMap = useMemo(() => { const map = new Map(); for (const quote of nbbo.items) { - const existing = map.get(quote.option_contract_id); + const contractId = normalizeContractId(quote.option_contract_id); + const existing = map.get(contractId); if ( !existing || quote.ts > existing.ts || (quote.ts === existing.ts && quote.seq >= existing.seq) ) { - map.set(quote.option_contract_id, quote); + map.set(contractId, quote); } } return map; @@ -2196,7 +2216,7 @@ export default function HomePage() { return options.items; } return options.items.filter((print) => - matchesTicker(extractUnderlying(print.option_contract_id)) + matchesTicker(extractUnderlying(normalizeContractId(print.option_contract_id))) ); }, [options.items, matchesTicker, tickerSet]); @@ -2386,20 +2406,23 @@ export default function HomePage() { ) : ( filteredOptions.map((print) => { - const quote = nbboMap.get(print.option_contract_id); + const contractId = normalizeContractId(print.option_contract_id); + const quote = nbboMap.get(contractId); const nbboAge = quote ? Math.abs(print.ts - quote.ts) : null; const nbboStale = nbboAge !== null && nbboAge > NBBO_MAX_AGE_MS_SAFE; const nbboMid = quote ? (quote.bid + quote.ask) / 2 : null; const nbboSide = classifyNbboSide(print.price, quote); + const notional = print.price * print.size * 100; return (
-
{print.option_contract_id}
+
{formatContractLabel(contractId)}
${formatPrice(print.price)} {formatSize(print.size)}x {print.exchange} + Notional ${formatUsd(notional)} {print.conditions?.length ? ( {print.conditions.join(", ")} ) : null}