Fix options tape replay formatting
This commit is contained in:
parent
af328f1b32
commit
4a22fcc635
1 changed files with 29 additions and 6 deletions
|
|
@ -232,7 +232,13 @@ const buildApiUrl = (path: string): string => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatPrice = (price: number): 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 => {
|
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 formatDateTime = (ts: number): string => {
|
||||||
const date = new Date(ts);
|
const date = new Date(ts);
|
||||||
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
|
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
|
||||||
|
|
@ -2032,13 +2051,14 @@ export default function HomePage() {
|
||||||
const nbboMap = useMemo(() => {
|
const nbboMap = useMemo(() => {
|
||||||
const map = new Map<string, OptionNBBO>();
|
const map = new Map<string, OptionNBBO>();
|
||||||
for (const quote of nbbo.items) {
|
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 (
|
if (
|
||||||
!existing ||
|
!existing ||
|
||||||
quote.ts > existing.ts ||
|
quote.ts > existing.ts ||
|
||||||
(quote.ts === existing.ts && quote.seq >= existing.seq)
|
(quote.ts === existing.ts && quote.seq >= existing.seq)
|
||||||
) {
|
) {
|
||||||
map.set(quote.option_contract_id, quote);
|
map.set(contractId, quote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
|
|
@ -2196,7 +2216,7 @@ export default function HomePage() {
|
||||||
return options.items;
|
return options.items;
|
||||||
}
|
}
|
||||||
return options.items.filter((print) =>
|
return options.items.filter((print) =>
|
||||||
matchesTicker(extractUnderlying(print.option_contract_id))
|
matchesTicker(extractUnderlying(normalizeContractId(print.option_contract_id)))
|
||||||
);
|
);
|
||||||
}, [options.items, matchesTicker, tickerSet]);
|
}, [options.items, matchesTicker, tickerSet]);
|
||||||
|
|
||||||
|
|
@ -2386,20 +2406,23 @@ export default function HomePage() {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
filteredOptions.map((print) => {
|
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 nbboAge = quote ? Math.abs(print.ts - quote.ts) : null;
|
||||||
const nbboStale = nbboAge !== null && nbboAge > NBBO_MAX_AGE_MS_SAFE;
|
const nbboStale = nbboAge !== null && nbboAge > NBBO_MAX_AGE_MS_SAFE;
|
||||||
const nbboMid = quote ? (quote.bid + quote.ask) / 2 : null;
|
const nbboMid = quote ? (quote.bid + quote.ask) / 2 : null;
|
||||||
const nbboSide = classifyNbboSide(print.price, quote);
|
const nbboSide = classifyNbboSide(print.price, quote);
|
||||||
|
const notional = print.price * print.size * 100;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row" key={`${print.trace_id}-${print.seq}`}>
|
<div className="row" key={`${print.trace_id}-${print.seq}`}>
|
||||||
<div>
|
<div>
|
||||||
<div className="contract">{print.option_contract_id}</div>
|
<div className="contract">{formatContractLabel(contractId)}</div>
|
||||||
<div className="meta">
|
<div className="meta">
|
||||||
<span>${formatPrice(print.price)}</span>
|
<span>${formatPrice(print.price)}</span>
|
||||||
<span>{formatSize(print.size)}x</span>
|
<span>{formatSize(print.size)}x</span>
|
||||||
<span>{print.exchange}</span>
|
<span>{print.exchange}</span>
|
||||||
|
<span>Notional ${formatUsd(notional)}</span>
|
||||||
{print.conditions?.length ? (
|
{print.conditions?.length ? (
|
||||||
<span>{print.conditions.join(", ")}</span>
|
<span>{print.conditions.join(", ")}</span>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue