unrip/src/operator-dashboard/static/pages/StrategyPage.jsx
philipp 7c006ac6a2
All checks were successful
deploy / deploy (push) Successful in 1m3s
Clarify maker inventory direction
Proof: Strategy tests now cover USDC -> BTC maker responses using BTC inventory with zero USDC, pending outbound units are subtracted before approval, lifecycle rows expose maker send/receive terms and inventory check details, targeted dashboard tests pass, full npm test passes, and the operator dashboard bundle builds.

Assumptions: pending_outbound in inventory snapshots represents units unavailable for new maker commitments; this change does not skip quotes because of relay-error risk and does not loosen edge, notional, arming, pair enablement, stale price, or stale inventory checks.

Still fake: relay acceptance is still only submission evidence; venue-native terminal fill ids and fee-complete realized PnL remain unavailable.
2026-05-19 18:36:42 +02:00

1442 lines
62 KiB
JavaScript

import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
import EmptyState from '../components/EmptyState.jsx';
import MetricCard from '../components/MetricCard.jsx';
import Pill from '../components/Pill.jsx';
import TableFrame from '../components/TableFrame.jsx';
import { formatAgeFromTimestamp, formatBoolean, formatEur, formatTimestamp, truncateMiddle } from '../lib/format.js';
const RESPONDED_STATES = new Set(['submitted', 'awaiting_outcome', 'not_filled', 'completed']);
const TRADING_PAIR_MODES = new Set(['maker', 'taker', 'both']);
const COMPETITIVENESS_GROUP_ROW_COUNT = 12;
const COMPETITIVENESS_DETAIL_ROW_COUNT = 8;
const COMPETITIVENESS_LATENCY_ROW_COUNT = 6;
const QUOTE_LIFECYCLE_ROW_COUNT = 20;
async function copyIdentifier(value) {
if (!value || !navigator?.clipboard?.writeText) return;
try {
await navigator.clipboard.writeText(value);
} catch {
// Best-effort copy affordance; keep the full identifier visible regardless.
}
}
function useNow(intervalMs = 1000) {
const [now, setNow] = useState(() => Date.now());
useEffect(() => {
const timer = window.setInterval(() => setNow(Date.now()), intervalMs);
return () => window.clearInterval(timer);
}, [intervalMs]);
return now;
}
function formatRelativeAge(value, now) {
const age = formatAgeFromTimestamp(value, now);
return age === 'Unavailable' ? 'Age unavailable' : `${age} ago`;
}
function formatTimingMs(value) {
const number = Number(value);
if (!Number.isFinite(number)) return null;
return `${number < 10 ? number.toFixed(1) : number.toFixed(0)} ms`;
}
function formatRate(value) {
const number = Number(value);
if (!Number.isFinite(number)) return 'Unavailable';
return `${(number * 100).toFixed(1)}%`;
}
function stageLabel(value) {
return plainCodeLabel(value).replace(/\bms\b/i, '').trim();
}
function formatExecutionTiming(timing) {
if (!timing) return null;
const saltMs = formatTimingMs(timing.current_salt_ms);
const saltAgeMs = formatTimingMs(timing.current_salt_age_ms);
const saltSource = timing.current_salt_source ? ` ${plainCodeLabel(timing.current_salt_source).toLowerCase()}` : '';
const parts = [
['total', timing.executor_total_ms],
['cmd age', timing.command_event_age_ms],
['sign', timing.sign_ms],
['relay', timing.relay_response_ms],
]
.map(([label, value]) => {
const formatted = formatTimingMs(value);
return formatted ? `${label} ${formatted}` : null;
})
.filter(Boolean);
if (saltMs) {
parts.splice(2, 0, `salt ${saltMs}${saltSource}${saltAgeMs ? ` age ${saltAgeMs}` : ''}`);
}
return parts.length ? `Timing: ${parts.join(', ')}` : null;
}
function IdentifierRow({ label, value }) {
if (!value) return <div className="status-subtle">{`${label}: unavailable`}</div>;
return (
<div className="trace-row">
<span className="status-subtle">{`${label}:`}</span>
<span className="mono trace-id">{value}</span>
<button className="button secondary trace-copy-button" onClick={() => copyIdentifier(value)} type="button">
Copy
</button>
</div>
);
}
function formatTerms(terms) {
if (!terms) return 'Unavailable';
const input = terms.amount_in
? `${terms.amount_in} ${terms.asset_in_symbol || ''}`.trim()
: terms.asset_in_symbol || terms.asset_in || 'input unavailable';
const output = terms.amount_out
? `${terms.amount_out} ${terms.asset_out_symbol || ''}`.trim()
: terms.asset_out_symbol || terms.asset_out || 'output unavailable';
return `${input} -> ${output}`;
}
function formatMakerTerms(terms) {
if (!terms) return null;
const send = terms.send_amount
? `${terms.send_amount} ${terms.send_asset_symbol || ''}`.trim()
: terms.send_asset_symbol || terms.send_asset || 'send unavailable';
const receive = terms.receive_amount
? `${terms.receive_amount} ${terms.receive_asset_symbol || ''}`.trim()
: terms.receive_asset_symbol || terms.receive_asset || 'receive unavailable';
return `Maker sends ${send}; receives ${receive}`;
}
function formatInventoryCheck(check) {
if (!check) return null;
const required = check.required == null ? 'required unavailable' : `${check.required} ${check.asset_symbol || ''}`.trim();
const available = check.available == null ? 'available unavailable' : `${check.available} available`;
const spendable = check.spendable == null ? null : `${check.spendable} spendable`;
const pendingOutbound = Number(check.pending_outbound_units || 0) > 0
? `${check.pending_outbound} pending outbound`
: null;
return [`Inventory ${required}`, available, spendable, pendingOutbound].filter(Boolean).join(', ');
}
function responseLabel(item) {
if (RESPONDED_STATES.has(item.lifecycle_state)) return 'Yes';
if (item.lifecycle_state === 'failed') return 'Attempt failed';
if (item.lifecycle_state === 'blocked' && item.reason_code?.startsWith('maker_')) return 'No - policy skip';
if (item.lifecycle_state === 'blocked') return 'No - blocked';
if (item.lifecycle_state === 'rejected') return 'No - strategy rejected';
if (item.lifecycle_state === 'command_emitted') return 'Pending executor';
if (item.lifecycle_state === 'evaluated') return 'Approved, not sent';
return 'No decision yet';
}
function grossEdgeEstimate(item) {
if (!item.gross_edge_value) return 'Unavailable';
const symbol = item.notional_symbol || (item.eure_notional ? 'EURe' : null);
if (symbol === 'EURe') return formatEur(item.gross_edge_value);
return symbol ? `${item.gross_edge_value} ${symbol}` : item.gross_edge_value;
}
function formatGrossEdgePct(value) {
if (value == null || value === '') return 'Gross edge unavailable';
return `Gross edge ${value}%`;
}
function formatConfiguredEdgeBps(value, { prefix = true } = {}) {
const number = Number(value);
if (!Number.isFinite(number)) return prefix ? 'Configured edge unavailable' : 'Unavailable';
const label = `${value} bps (${(number / 100).toFixed(2)}%)`;
return prefix ? `Configured edge ${label}` : label;
}
function notionalLabel(item) {
if (item.notional_display) return item.notional_display;
if (item.notional != null) return `${item.notional}${item.notional_symbol ? ` ${item.notional_symbol}` : ''}`;
return item.eure_notional ? formatEur(item.eure_notional) : 'Notional unavailable';
}
function plainCodeLabel(value, fallback = 'Unavailable') {
const text = String(value || '').trim();
if (!text) return fallback;
return text.replaceAll('_', ' ');
}
function strategyDecisionStatus(decision) {
if (decision?.decision === 'approved') return 'Strategy approved';
if (decision?.decision === 'rejected') return 'Strategy rejected';
return plainCodeLabel(decision?.decision, 'No strategy decision');
}
function isStrategyRejected(item) {
return item?.lifecycle_state === 'rejected'
|| item?.decision?.decision === 'rejected'
|| String(item?.lifecycle_label || '').toLowerCase() === 'rejected by strategy';
}
function StageCard({ title, at, status, children }) {
return (
<div className="lifecycle-stage-card">
<div className="stage-title">{title}</div>
<div className="stage-meta">{formatTimestamp(at)}</div>
<div className="stage-status">{status || 'Not recorded'}</div>
{children ? <div className="stage-body">{children}</div> : null}
</div>
);
}
function TimingWaterfall({ timing }) {
if (!timing) return null;
const rows = [
['Quote observed', timing.quote_observed_at],
['Quote received', timing.quote_received_at],
['Normalized', timing.quote_normalized_at],
['Published', timing.quote_published_at],
['Strategy received', timing.strategy_received_at],
['Strategy decided', timing.strategy_decided_at, timing.quote_to_decision_ms],
['Command published', timing.command_published_at, timing.decision_to_command_ms],
['Executor received', timing.executor_received_at, timing.command_to_executor_ms],
['Relay result', timing.relay_result_at, timing.executor_to_relay_result_ms],
['Outcome observed', timing.outcome_observed_at, timing.quote_to_outcome_ms],
];
const hasEvidence = rows.some(([, at, duration]) => at || duration != null);
if (!hasEvidence) return null;
return (
<TableFrame>
<table className="timing-waterfall-table">
<thead>
<tr>
<th>Stage</th>
<th>Timestamp</th>
<th>Step</th>
<th>From quote</th>
</tr>
</thead>
<tbody>
{rows.map(([label, at, duration]) => (
<tr key={label}>
<td>{label}</td>
<td>{formatTimestamp(at)}</td>
<td>{formatTimingMs(duration) || 'Unavailable'}</td>
<td>
{label === 'Strategy decided' ? formatTimingMs(timing.quote_age_at_decision_ms)
: label === 'Executor received' ? formatTimingMs(timing.quote_age_at_executor_receipt_ms)
: label === 'Relay result' ? formatTimingMs(timing.quote_age_at_relay_result_ms)
: label === 'Outcome observed' ? formatTimingMs(timing.quote_to_outcome_ms)
: 'Unavailable'}
</td>
</tr>
))}
</tbody>
</table>
</TableFrame>
);
}
function LifecycleDetails({ item }) {
const executionTiming = formatExecutionTiming(item.execution?.timing);
const makerTerms = formatMakerTerms(item.maker_terms);
const inventoryCheck = formatInventoryCheck(item.inventory_check);
return (
<div className="lifecycle-detail-panel">
<div className="lifecycle-stage-grid">
<StageCard at={item.quote_observed_at} status={item.quote_observed_at ? 'Quote observed' : 'Missing quote event'} title="1. Quote came in">
<div>{formatTerms(item.request_terms)}</div>
<div className="status-subtle mono">{item.pair || 'pair unavailable'}</div>
</StageCard>
<StageCard at={item.decision_at} status={strategyDecisionStatus(item.decision)} title="2. Strategy decided">
<div>{plainCodeLabel(item.decision?.decision_reason || item.reason_code, 'No decision reason recorded')}</div>
<div className="status-subtle">{formatGrossEdgePct(item.gross_edge_pct)}</div>
<div className="status-subtle">{formatConfiguredEdgeBps(item.edge_bps)}</div>
<div className="status-subtle">{notionalLabel(item)}</div>
{inventoryCheck ? <div className="status-subtle">{inventoryCheck}</div> : null}
</StageCard>
<StageCard at={item.command_at} status={item.command_id ? 'Command recorded' : 'No command'} title="3. Executor command">
<IdentifierRow label="Command" value={item.command_id} />
<div>{makerTerms || formatTerms(item.submitted_terms)}</div>
{makerTerms ? <div className="status-subtle">{formatTerms(item.submitted_terms)}</div> : null}
</StageCard>
<StageCard at={item.execution_result_at} status={item.execution?.status || 'No relay result'} title="4. Relay response">
<div>{item.execution?.result_code || 'No executor result code stored'}</div>
{item.execution?.error_message ? <div className="status-subtle">{item.execution.error_message}</div> : null}
{!item.execution?.error_message && item.execution?.note ? <div className="status-subtle">{item.execution.note}</div> : null}
{executionTiming ? <div className="status-subtle">{executionTiming}</div> : null}
{item.execution?.status === 'submitted' ? (
<div className="status-subtle">Submitted means the relay accepted the response; it does not prove a trade.</div>
) : null}
</StageCard>
<StageCard at={item.outcome_observed_at} status={item.outcome_status || item.lifecycle_state} title="5. Outcome and settlement">
<div>{item.reason_text}</div>
<div className="status-subtle">{item.settlement_summary?.text || 'No settled inventory delta is linked to this quote.'}</div>
{item.settlement_summary?.caveat ? <div className="status-subtle">{item.settlement_summary.caveat}</div> : null}
</StageCard>
</div>
<div className="trace-block">
<IdentifierRow label="Quote" value={item.quote_id} />
<IdentifierRow label="Decision" value={item.decision_id} />
<IdentifierRow label="Command" value={item.command_id} />
</div>
<TimingWaterfall timing={item.maker_timing} />
</div>
);
}
function pairDisplayLabel(pairId, pairConfig) {
const pair = (pairConfig?.pairs || []).find((entry) => (
(entry.pair_id || entry.pairId || entry.pair) === pairId
));
if (!pair) return truncateMiddle(pairId || 'Unknown pair', 42);
return `${pair.asset_in_symbol || pair.asset_in || pair.assetIn} -> ${pair.asset_out_symbol || pair.asset_out || pair.assetOut}`;
}
function fixedRows(items, count) {
const rows = (items || []).slice(0, count);
while (rows.length < count) rows.push(null);
return rows;
}
function MakerCompetitivenessSection({ summary, pairConfig }) {
const latestSummaryRef = useRef(summary || {});
const [displaySummary, setDisplaySummary] = useState(() => summary || {});
const [updatesPaused, setUpdatesPaused] = useState(false);
const total = displaySummary?.total || {};
const groups = displaySummary?.groups || [];
const ageBuckets = displaySummary?.age_buckets || [];
const latestErrors = displaySummary?.latest_errors || [];
const policySkips = displaySummary?.policy_skips || [];
const latencyStages = displaySummary?.latency_stages || [];
const groupRows = fixedRows(groups, COMPETITIVENESS_GROUP_ROW_COUNT);
const ageBucketRows = fixedRows(ageBuckets, COMPETITIVENESS_GROUP_ROW_COUNT);
const latestErrorRows = fixedRows(latestErrors, COMPETITIVENESS_DETAIL_ROW_COUNT);
const policySkipRows = fixedRows(policySkips, COMPETITIVENESS_DETAIL_ROW_COUNT);
const latencyStageRows = fixedRows(latencyStages, COMPETITIVENESS_LATENCY_ROW_COUNT);
useEffect(() => {
latestSummaryRef.current = summary || {};
if (!updatesPaused) setDisplaySummary(summary || {});
}, [summary, updatesPaused]);
function toggleUpdatesPaused() {
setUpdatesPaused((current) => {
const nextPaused = !current;
if (current) {
setDisplaySummary(latestSummaryRef.current || {});
}
return nextPaused;
});
}
return (
<section className="panel">
<div className="panel-head">
<div>
<div className="eyebrow">Maker competitiveness</div>
<h3>Response timing and quote-age outcomes</h3>
<div className="panel-subtitle">
Pair-native response evidence from durable quote, decision, command, executor result, and outcome rows.
</div>
</div>
<div className="pills">
<Pill label={`${total.count || 0} rows`} stateLabel="info" />
<Pill label={`${total.quote_not_found_or_finished_count || 0} stale/finished`} stateLabel={(total.quote_not_found_or_finished_count || 0) > 0 ? 'warning' : 'unknown'} />
<Pill label={updatesPaused ? 'Updates paused' : 'Live updates'} stateLabel={updatesPaused ? 'warning' : 'healthy'} />
<button
aria-pressed={updatesPaused}
className="button secondary trace-copy-button"
onClick={toggleUpdatesPaused}
type="button"
>
{updatesPaused ? 'Resume updates' : 'Pause updates'}
</button>
</div>
</div>
<div className="status-subtle competitiveness-snapshot-note">
Live rows update as they arrive. Fixed row slots and clamped cells keep the table height stable.
</div>
<div className="metric-stack">
<MetricCard label="Accepted" meta={formatRate(total.accepted_rate)} value={String(total.accepted_count || 0)} />
<MetricCard label="Relay failed" meta="Executor reached result" value={String(total.relay_failed_count || 0)} />
<MetricCard label="Already finished" meta={formatRate(total.stale_or_finished_rate)} value={String(total.quote_not_found_or_finished_count || 0)} />
<MetricCard label="Policy skips" meta="No relay submission" value={String(total.policy_skip_count || 0)} />
</div>
<TableFrame className="competitiveness-frame">
<table className="competitiveness-table competitiveness-groups-table">
<thead>
<tr>
<th>Pair</th>
<th>Direction</th>
<th>Request</th>
<th>Edge</th>
<th>Result</th>
<th>Age / notional</th>
<th>Outcome</th>
<th>Counts</th>
<th>Quote to relay</th>
</tr>
</thead>
<tbody>
{groupRows.map((group, index) => {
if (!group) {
return (
<tr className="competitiveness-placeholder-row" key={`group-placeholder:${index}`}>
<td colSpan={9}>{index === 0 && !groups.length ? 'No competitiveness rows are available yet.' : ''}</td>
</tr>
);
}
const quoteToRelay = group.latency_stages?.find((stage) => stage.stage === 'quote_to_relay_result_ms');
return (
<tr key={`${group.pair}:${group.direction}:${group.request_kind}:${group.edge_bps ?? 'edge'}:${group.result_code}:${group.quote_age_bucket}:${group.notional_bucket}:${group.outcome_status}`}>
<td>
<div>{pairDisplayLabel(group.pair, pairConfig)}</div>
<div className="status-subtle mono">{truncateMiddle(group.pair || '', 42)}</div>
</td>
<td>{plainCodeLabel(group.direction)}</td>
<td>{plainCodeLabel(group.request_kind)}</td>
<td>{group.edge_bps == null ? 'Unavailable' : `${group.edge_bps} bps`}</td>
<td>
<div>{plainCodeLabel(group.result_code)}</div>
{group.failure_category ? <div className="status-subtle">{plainCodeLabel(group.failure_category)}</div> : null}
</td>
<td>
<div>{group.quote_age_bucket}</div>
<div className="status-subtle">{group.notional_bucket}</div>
</td>
<td>{plainCodeLabel(group.outcome_status)}</td>
<td>
<div>{group.count}</div>
<div className="status-subtle">{`${group.accepted_count || 0} accepted / ${group.policy_skip_count || 0} skipped`}</div>
</td>
<td>
<div>{formatTimingMs(quoteToRelay?.p50_ms) || 'Unavailable'}</div>
<div className="status-subtle">{`p90 ${formatTimingMs(quoteToRelay?.p90_ms) || 'Unavailable'}`}</div>
</td>
</tr>
);
})}
</tbody>
</table>
</TableFrame>
<div className="stack-grid competitiveness-table-stack">
<TableFrame className="competitiveness-frame">
<table className="competitiveness-table competitiveness-latency-table">
<thead>
<tr>
<th>Latency stage</th>
<th>p50</th>
<th>p90</th>
<th>p99</th>
</tr>
</thead>
<tbody>
{latencyStageRows.map((stage, index) => {
if (!stage) {
return (
<tr className="competitiveness-placeholder-row" key={`latency-stage-placeholder:${index}`}>
<td colSpan={4}>{index === 0 && !latencyStages.length ? 'No stage timing percentiles are available yet.' : ''}</td>
</tr>
);
}
return (
<tr key={stage.stage}>
<td>{stageLabel(stage.stage)}</td>
<td>{formatTimingMs(stage.p50_ms)}</td>
<td>{formatTimingMs(stage.p90_ms)}</td>
<td>{formatTimingMs(stage.p99_ms)}</td>
</tr>
);
})}
</tbody>
</table>
</TableFrame>
<TableFrame className="competitiveness-frame">
<table className="competitiveness-table competitiveness-age-table">
<thead>
<tr>
<th>Age bucket</th>
<th>Outcome</th>
<th>Count</th>
<th>Accepted</th>
</tr>
</thead>
<tbody>
{ageBucketRows.map((bucket, index) => {
if (!bucket) {
return (
<tr className="competitiveness-placeholder-row" key={`age-bucket-placeholder:${index}`}>
<td colSpan={4}>{index === 0 && !ageBuckets.length ? 'No quote-age buckets are available yet.' : ''}</td>
</tr>
);
}
return (
<tr key={`${bucket.pair}:${bucket.quote_age_bucket}:${bucket.outcome_status}:${bucket.notional_bucket || ''}`}>
<td>
<div>{bucket.quote_age_bucket}</div>
<div className="status-subtle">{pairDisplayLabel(bucket.pair, pairConfig)}</div>
</td>
<td>{plainCodeLabel(bucket.outcome_status)}</td>
<td>{bucket.count}</td>
<td>{bucket.accepted_count || 0}</td>
</tr>
);
})}
</tbody>
</table>
</TableFrame>
</div>
<div className="stack-grid competitiveness-table-stack">
<TableFrame className="competitiveness-frame">
<table className="competitiveness-table competitiveness-detail-table">
<thead>
<tr>
<th>Latest relay errors</th>
<th>Quote age</th>
<th>Error</th>
</tr>
</thead>
<tbody>
{latestErrorRows.map((error, index) => {
if (!error) {
return (
<tr className="competitiveness-placeholder-row" key={`latest-error-placeholder:${index}`}>
<td colSpan={3}>{index === 0 && !latestErrors.length ? 'No relay errors are available yet.' : ''}</td>
</tr>
);
}
return (
<tr key={`${error.quote_id}:${error.result_at}`}>
<td>
<IdentifierRow label="Quote" value={error.quote_id} />
<div className="status-subtle">{pairDisplayLabel(error.pair, pairConfig)}</div>
<div className="status-subtle">{plainCodeLabel(error.failure_category || error.result_code)}</div>
</td>
<td>
<div>{formatTimingMs(error.quote_age_ms) || 'Unavailable'}</div>
<div className="status-subtle">{error.quote_age_bucket}</div>
</td>
<td>
<div className="competitiveness-error-text" title={error.error_message || ''}>
{error.error_message || 'Error text unavailable'}
</div>
</td>
</tr>
);
})}
</tbody>
</table>
</TableFrame>
<TableFrame className="competitiveness-frame">
<table className="competitiveness-table competitiveness-detail-table">
<thead>
<tr>
<th>Policy skips</th>
<th>Age</th>
<th>Config</th>
</tr>
</thead>
<tbody>
{policySkipRows.map((skip, index) => {
if (!skip) {
return (
<tr className="competitiveness-placeholder-row" key={`policy-skip-placeholder:${index}`}>
<td colSpan={3}>{index === 0 && !policySkips.length ? 'No policy skips are available yet.' : ''}</td>
</tr>
);
}
return (
<tr key={`${skip.quote_id}:${skip.decision_at}`}>
<td>
<IdentifierRow label="Quote" value={skip.quote_id} />
<div className="status-subtle">{plainCodeLabel(skip.reason_code)}</div>
</td>
<td>
<div>{formatTimingMs(skip.quote_age_ms) || 'Unavailable'}</div>
<div className="status-subtle">{`max ${formatTimingMs(skip.max_quote_age_ms) || 'Unavailable'}`}</div>
</td>
<td>
<div>{skip.pair_config_version ? `v${skip.pair_config_version}` : 'Version unavailable'}</div>
<div className="status-subtle mono">{truncateMiddle(skip.pair_config_id || '', 36)}</div>
</td>
</tr>
);
})}
</tbody>
</table>
</TableFrame>
</div>
</section>
);
}
function QuoteLifecycleTable({ items }) {
const [expanded, setExpanded] = useState(() => new Set());
const [showStrategyRejected, setShowStrategyRejected] = useState(true);
const latestItemsRef = useRef(items || []);
const [quoteDisplayPaused, setQuoteDisplayPaused] = useState(false);
const [displayItems, setDisplayItems] = useState(() => items || []);
const liveNow = useNow();
const [displayNow, setDisplayNow] = useState(() => Date.now());
useEffect(() => {
latestItemsRef.current = items || [];
if (!quoteDisplayPaused) setDisplayItems(items || []);
}, [items, quoteDisplayPaused]);
useEffect(() => {
if (!quoteDisplayPaused) setDisplayNow(liveNow);
}, [liveNow, quoteDisplayPaused]);
const rejectedCount = useMemo(
() => displayItems.filter((item) => isStrategyRejected(item)).length,
[displayItems],
);
const visibleItems = useMemo(
() => (showStrategyRejected ? displayItems : displayItems.filter((item) => !isStrategyRejected(item))),
[displayItems, showStrategyRejected],
);
const visibleRows = fixedRows(visibleItems, QUOTE_LIFECYCLE_ROW_COUNT);
const emptyRowsMessage = !displayItems.length
? 'No quote lifecycle evidence has been observed yet.'
: !visibleItems.length
? 'No quote lifecycle rows match the current filters.'
: '';
function toggle(rowKey) {
setExpanded((current) => {
const next = new Set(current);
if (next.has(rowKey)) next.delete(rowKey);
else next.add(rowKey);
return next;
});
}
function applyLatestLifecycleDisplay() {
setDisplayItems(latestItemsRef.current || []);
setDisplayNow(Date.now());
}
function toggleQuoteDisplayPaused() {
if (quoteDisplayPaused) applyLatestLifecycleDisplay();
setQuoteDisplayPaused((paused) => !paused);
}
return (
<>
<div className="quote-lifecycle-controls">
<label className="toggle-field">
<input
checked={showStrategyRejected}
onChange={(event) => setShowStrategyRejected(event.target.checked)}
type="checkbox"
/>
<span>{`Rejected by strategy (${rejectedCount})`}</span>
</label>
<button
aria-pressed={quoteDisplayPaused}
className="button secondary"
onClick={toggleQuoteDisplayPaused}
type="button"
>
{quoteDisplayPaused ? 'Resume display' : 'Pause display'}
</button>
<Pill label={quoteDisplayPaused ? 'Display paused' : 'Live updates'} stateLabel={quoteDisplayPaused ? 'warning' : 'healthy'} />
</div>
<div className="status-subtle quote-lifecycle-snapshot-note">
Live rows update as they arrive. Fixed row slots and clamped cells keep the table height stable.
</div>
<TableFrame className="quote-lifecycle-frame">
<table className="quote-lifecycle-table">
<thead>
<tr>
<th>Quote time</th>
<th>Quote id</th>
<th>Request</th>
<th>Responded?</th>
<th>Result</th>
<th>Reason</th>
<th>Gross edge / notional</th>
<th>Lifecycle</th>
</tr>
</thead>
<tbody>
{visibleRows.map((item, index) => {
if (!item) {
return (
<tr className="quote-lifecycle-placeholder-row" key={`quote-lifecycle-placeholder:${index}`}>
<td colSpan={8}>{index === 0 ? emptyRowsMessage : ''}</td>
</tr>
);
}
const rowKey = item.quote_id || item.decision_id || item.command_id || item.latest_stage_at || String(index);
const isExpanded = expanded.has(rowKey);
const quoteTime = item.quote_activity_at || item.latest_stage_at;
const updatedText = item.latest_stage_at && item.latest_stage_at !== item.quote_activity_at
? `Updated ${formatTimestamp(item.latest_stage_at)} - ${formatRelativeAge(item.latest_stage_at, displayNow)}`
: '';
return (
<Fragment key={rowKey}>
<tr className={`quote-lifecycle-row${item.live_flash_at ? ' quote-row-flash' : ''}`} key={`${rowKey}:row`}>
<td>
<div className="quote-lifecycle-cell">
<div className="lifecycle-line lifecycle-clamp-one">{formatTimestamp(quoteTime)}</div>
<div className="status-subtle quote-age lifecycle-line lifecycle-clamp-one">{formatRelativeAge(quoteTime, displayNow)}</div>
<div className="status-subtle lifecycle-line lifecycle-clamp-two">{updatedText}</div>
</div>
</td>
<td><IdentifierRow label="Quote" value={item.quote_id} /></td>
<td>
<div className="quote-lifecycle-cell">
<div className="lifecycle-line lifecycle-clamp-two">{formatTerms(item.request_terms || item.submitted_terms)}</div>
<div className="status-subtle mono lifecycle-line lifecycle-clamp-one">{truncateMiddle(item.pair || '', 34)}</div>
</div>
</td>
<td>{responseLabel(item)}</td>
<td><Pill label={item.lifecycle_label} stateLabel={item.lifecycle_tone} /></td>
<td>
<div className="quote-lifecycle-cell">
<div className="lifecycle-line lifecycle-clamp-two">{item.reason_text}</div>
<div className="status-subtle mono lifecycle-line lifecycle-clamp-one">{item.reason_code || 'reason_unknown'}</div>
</div>
</td>
<td>
<div className="quote-lifecycle-cell">
<div className={`lifecycle-line lifecycle-clamp-one ${Number(item.gross_edge_pct) > 0 ? 'value-positive' : Number(item.gross_edge_pct) < 0 ? 'value-negative' : ''}`}>{formatGrossEdgePct(item.gross_edge_pct)}</div>
<div className="status-subtle lifecycle-line lifecycle-clamp-one">{formatConfiguredEdgeBps(item.edge_bps)}</div>
<div className="status-subtle lifecycle-line lifecycle-clamp-one">{notionalLabel(item)}</div>
</div>
</td>
<td>
<button className="button secondary" onClick={() => toggle(rowKey)} type="button">
{isExpanded ? 'Hide lifecycle' : 'Show lifecycle'}
</button>
</td>
</tr>
{isExpanded ? (
<tr className="lifecycle-expanded-row" key={`${rowKey}:details`}>
<td colSpan={8}><LifecycleDetails item={item} /></td>
</tr>
) : null}
</Fragment>
);
})}
</tbody>
</table>
</TableFrame>
</>
);
}
function SuccessfulTradesTable({ items }) {
const [expanded, setExpanded] = useState(() => new Set());
if (!items?.length) {
return (
<EmptyState>
No successful trades with linked settlement evidence yet. A submitted quote response is not counted here until a durable terminal outcome and settled asset movement are linked to the quote.
</EmptyState>
);
}
function toggle(rowKey) {
setExpanded((current) => {
const next = new Set(current);
if (next.has(rowKey)) next.delete(rowKey);
else next.add(rowKey);
return next;
});
}
return (
<TableFrame>
<table className="successful-trades-table">
<thead>
<tr>
<th>Completed</th>
<th>Quote id</th>
<th>Gross edge</th>
<th>Gross edge est.</th>
<th>Settlement</th>
<th>Realized PnL</th>
<th>Lifecycle</th>
</tr>
</thead>
<tbody>
{items.map((item, index) => {
const rowKey = item.quote_id || item.command_id || item.latest_stage_at || String(index);
const isExpanded = expanded.has(rowKey);
return (
<Fragment key={rowKey}>
<tr key={`${rowKey}:trade`}>
<td>{formatTimestamp(item.latest_stage_at)}</td>
<td><IdentifierRow label="Quote" value={item.quote_id} /></td>
<td>
<div>{formatGrossEdgePct(item.gross_edge_pct)}</div>
<div className="status-subtle">{formatConfiguredEdgeBps(item.edge_bps)}</div>
<div className="status-subtle">{notionalLabel(item)}</div>
</td>
<td>
<div>{grossEdgeEstimate(item)}</div>
<div className="status-subtle">Estimate from edge x notional, not realized PnL.</div>
</td>
<td>
<div>{item.settlement_summary?.text || 'No settled inventory delta is linked to this quote.'}</div>
{item.settlement_summary?.method ? <div className="status-subtle mono">{item.settlement_summary.method}</div> : null}
</td>
<td>
<div>Unavailable</div>
<div className="status-subtle">Fees and venue-native terminal fill are not stored.</div>
</td>
<td>
<button className="button secondary" onClick={() => toggle(rowKey)} type="button">
{isExpanded ? 'Hide lifecycle' : 'Show lifecycle'}
</button>
</td>
</tr>
{isExpanded ? (
<tr className="lifecycle-expanded-row" key={`${rowKey}:trade-details`}>
<td colSpan={7}><LifecycleDetails item={item} /></td>
</tr>
) : null}
</Fragment>
);
})}
</tbody>
</table>
</TableFrame>
);
}
function AssetCatalogSection({ assetCatalog, onControl }) {
const latest = assetCatalog?.latest_import || null;
const counts = assetCatalog?.counts || {};
const items = assetCatalog?.items || [];
return (
<section className="panel">
<div className="panel-head">
<div>
<div className="eyebrow">Asset registry</div>
<h3>Supported-token import status</h3>
<div className="panel-subtitle">
Last import {latest?.fetched_at ? formatTimestamp(latest.fetched_at) : 'not run'}
</div>
</div>
<div className="pills">
<Pill label={latest?.status || 'not imported'} stateLabel={latest?.status === 'success' ? 'healthy' : 'warning'} />
<button className="button secondary" onClick={() => onControl?.('operator-dashboard', 'import-supported-assets')} type="button">
Import assets
</button>
</div>
</div>
<div className="metric-grid">
<MetricCard label="Known assets" meta={`${counts.inventory_enabled || 0} inventory tracked`} value={String(counts.known || 0)} />
<MetricCard label="Supported now" meta={`${latest?.token_count || 0} tokens in latest run`} value={String(counts.supported || 0)} />
<MetricCard label="Retired" meta="Kept for balances and history" value={String(counts.retired || 0)} />
</div>
<TableFrame>
<table>
<thead>
<tr>
<th>Asset</th>
<th>Decimals</th>
<th>Chain</th>
<th>Deposit</th>
<th>Price</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{items.length ? items.map((asset) => (
<tr key={asset.asset_id || asset.assetId}>
<td>
<div>{asset.label || asset.symbol}</div>
<div className="status-subtle mono">{truncateMiddle(asset.asset_id || asset.assetId, 42)}</div>
</td>
<td>{asset.decimals}</td>
<td>{asset.blockchain || asset.chain || 'Unavailable'}</td>
<td>
{asset.deposit_address || asset.depositAddress ? (
<>
<div className="trace-row">
<span
className="mono trace-id"
title={asset.deposit_address || asset.depositAddress}
>
{truncateMiddle(asset.deposit_address || asset.depositAddress, 34)}
</span>
<button
className="button secondary trace-copy-button"
onClick={() => copyIdentifier(asset.deposit_address || asset.depositAddress)}
type="button"
>
Copy
</button>
</div>
<div className="status-subtle">
{asset.deposit_memo || asset.depositMemo ? `Memo ${asset.deposit_memo || asset.depositMemo}` : asset.deposit_chain || asset.depositChain || 'Deposit handle'}
</div>
</>
) : (
<div className="status-subtle">Unavailable</div>
)}
</td>
<td>{asset.latest_price || asset.latestPrice || 'Unavailable'}</td>
<td>
<Pill
label={asset.supported ? 'supported' : 'retired'}
stateLabel={asset.supported ? 'healthy' : 'warning'}
/>
</td>
</tr>
)) : (
<tr><td colSpan={6}>No DB asset registry rows are available.</td></tr>
)}
</tbody>
</table>
</TableFrame>
</section>
);
}
function assetOptionLabel(asset) {
return `${asset.label || asset.symbol || asset.asset_id || asset.assetId} - ${truncateMiddle(asset.asset_id || asset.assetId, 34)}`;
}
function PairConfigSection({ assetCatalog, pairConfig, onControl }) {
const pairs = pairConfig?.pairs || [];
const assets = useMemo(() => (assetCatalog?.items || [])
.filter((asset) => asset.asset_id || asset.assetId)
.sort((left, right) => String(left.label || left.symbol || left.asset_id || '').localeCompare(
String(right.label || right.symbol || right.asset_id || ''),
)), [assetCatalog?.items]);
const [pairForm, setPairForm] = useState({
asset_in: '',
asset_out: '',
mode: 'observe_only',
edge_bps: '49',
min_notional: '0',
max_notional: '150',
});
const [edgeDrafts, setEdgeDrafts] = useState({});
const [minNotionalDrafts, setMinNotionalDrafts] = useState({});
const [maxNotionalDrafts, setMaxNotionalDrafts] = useState({});
const [policyEnabledDrafts, setPolicyEnabledDrafts] = useState({});
const [maxQuoteAgeDrafts, setMaxQuoteAgeDrafts] = useState({});
useEffect(() => {
if (!assets.length) return;
setPairForm((current) => ({
...current,
asset_in: current.asset_in || assets[0]?.asset_id || assets[0]?.assetId || '',
asset_out: current.asset_out || assets[1]?.asset_id || assets[1]?.assetId || assets[0]?.asset_id || assets[0]?.assetId || '',
}));
}, [assets]);
useEffect(() => {
setEdgeDrafts(Object.fromEntries(pairs.map((pair) => {
const pairId = pair.pair_id || pair.pairId;
const strategyConfig = pair.strategyConfig || pair.strategy_config || {};
const tradingMode = TRADING_PAIR_MODES.has(pair.mode);
return [pairId, String(strategyConfig.edge_bps ?? pair.edge_bps ?? (tradingMode ? '49' : ''))];
})));
setMaxNotionalDrafts(Object.fromEntries(pairs.map((pair) => {
const pairId = pair.pair_id || pair.pairId;
const strategyConfig = pair.strategyConfig || pair.strategy_config || {};
const tradingMode = TRADING_PAIR_MODES.has(pair.mode);
return [pairId, String(strategyConfig.max_notional ?? pair.max_notional ?? (tradingMode ? '150' : ''))];
})));
setMinNotionalDrafts(Object.fromEntries(pairs.map((pair) => {
const pairId = pair.pair_id || pair.pairId;
const strategyConfig = pair.strategyConfig || pair.strategy_config || {};
const tradingMode = TRADING_PAIR_MODES.has(pair.mode);
return [pairId, String(strategyConfig.min_notional ?? pair.min_notional ?? (tradingMode ? '0' : ''))];
})));
setPolicyEnabledDrafts(Object.fromEntries(pairs.map((pair) => {
const pairId = pair.pair_id || pair.pairId;
const strategyConfig = pair.strategyConfig || pair.strategy_config || {};
return [pairId, Boolean(
strategyConfig.maker_max_quote_age_enabled ?? strategyConfig.makerMaxQuoteAgeEnabled,
)];
})));
setMaxQuoteAgeDrafts(Object.fromEntries(pairs.map((pair) => {
const pairId = pair.pair_id || pair.pairId;
const strategyConfig = pair.strategyConfig || pair.strategy_config || {};
return [pairId, String(
strategyConfig.maker_max_quote_age_ms ?? strategyConfig.makerMaxQuoteAgeMs ?? '',
)];
})));
}, [pairs]);
async function updatePairConfig(pair) {
const pairId = pair.pair_id || pair.pairId;
const strategyConfig = pair.strategyConfig || pair.strategy_config || {};
const hasStrategyConfig = Boolean(strategyConfig.config_id || strategyConfig.configId);
const edgeBps = edgeDrafts[pairId];
const maxNotional = maxNotionalDrafts[pairId];
const minNotional = minNotionalDrafts[pairId];
const policyEnabled = policyEnabledDrafts[pairId] === true;
const maxQuoteAgeMs = maxQuoteAgeDrafts[pairId];
if (!edgeBps || !maxNotional || minNotional === undefined || minNotional === '') return;
if (policyEnabled && !maxQuoteAgeMs) return;
if (!hasStrategyConfig) {
const mode = pair.mode || pair.status || 'observe_only';
if (
TRADING_PAIR_MODES.has(mode)
&& !window.confirm('Initialize strategy config for this trading pair?')
) {
return;
}
await onControl?.('operator-dashboard', 'set-pair-mode', {
pair_id: pairId,
mode,
edge_bps: Number(edgeBps),
max_notional: maxNotional,
min_notional: minNotional,
maker_max_quote_age_enabled: policyEnabled,
maker_max_quote_age_ms: policyEnabled ? Number(maxQuoteAgeMs) : null,
maker_latency_policy_reason: policyEnabled ? 'operator dashboard maker response-age policy' : null,
});
return;
}
await onControl?.('operator-dashboard', 'update-pair-edge', {
pair_id: pairId,
edge_bps: Number(edgeBps),
max_notional: maxNotional,
min_notional: minNotional,
maker_max_quote_age_enabled: policyEnabled,
maker_max_quote_age_ms: policyEnabled ? Number(maxQuoteAgeMs) : null,
maker_latency_policy_reason: policyEnabled ? 'operator dashboard maker response-age policy' : null,
});
}
async function applyPairMode(event) {
event.preventDefault();
if (!pairForm.asset_in || !pairForm.asset_out || pairForm.asset_in === pairForm.asset_out) return;
if (
TRADING_PAIR_MODES.has(pairForm.mode)
&& !window.confirm('Activate trading mode for this directed pair?')
) {
return;
}
await onControl?.('operator-dashboard', 'set-pair-mode', {
asset_in: pairForm.asset_in,
asset_out: pairForm.asset_out,
mode: pairForm.mode,
edge_bps: Number(pairForm.edge_bps),
max_notional: pairForm.max_notional,
min_notional: pairForm.min_notional,
});
}
async function pausePair(pair) {
await onControl?.('operator-dashboard', 'pause-pair', {
pair_id: pair.pair_id || pair.pairId,
});
}
async function activatePair(pair) {
const pairId = pair.pair_id || pair.pairId;
const nextMode = ['maker', 'taker', 'both'].includes(pair.mode) ? pair.mode : 'observe_only';
if (
TRADING_PAIR_MODES.has(nextMode)
&& !window.confirm('Reactivate trading mode for this directed pair?')
) {
return;
}
await onControl?.('operator-dashboard', 'set-pair-mode', {
pair_id: pairId,
mode: nextMode,
});
}
const tradingModeSelected = TRADING_PAIR_MODES.has(pairForm.mode);
const pairFormDisabled = !assets.length
|| pairForm.asset_in === pairForm.asset_out
|| (tradingModeSelected && (!pairForm.edge_bps || !pairForm.max_notional || pairForm.min_notional === ''));
return (
<section className="panel">
<div className="panel-head">
<div>
<div className="eyebrow">Pair config</div>
<h3>Add, pause, and tune directed pairs</h3>
<div className="panel-subtitle">
Loaded {pairConfig?.loaded_at ? formatTimestamp(pairConfig.loaded_at) : 'unavailable'}
</div>
</div>
<div className="pills">
<Pill label={pairConfig?.ok ? 'config loaded' : pairConfig?.block_reason || 'blocked'} stateLabel={pairConfig?.ok ? 'healthy' : 'warning'} />
</div>
</div>
<form onSubmit={applyPairMode}>
<div className="form-grid">
<div className="field">
<label htmlFor="pair-asset-in">Asset in</label>
<select
id="pair-asset-in"
onChange={(event) => setPairForm((current) => ({ ...current, asset_in: event.target.value }))}
value={pairForm.asset_in}
>
{assets.map((asset) => {
const assetId = asset.asset_id || asset.assetId;
return <option key={assetId} value={assetId}>{assetOptionLabel(asset)}</option>;
})}
</select>
</div>
<div className="field">
<label htmlFor="pair-asset-out">Asset out</label>
<select
id="pair-asset-out"
onChange={(event) => setPairForm((current) => ({ ...current, asset_out: event.target.value }))}
value={pairForm.asset_out}
>
{assets.map((asset) => {
const assetId = asset.asset_id || asset.assetId;
return <option key={assetId} value={assetId}>{assetOptionLabel(asset)}</option>;
})}
</select>
</div>
<div className="field">
<label htmlFor="pair-mode">Mode</label>
<select
id="pair-mode"
onChange={(event) => setPairForm((current) => ({ ...current, mode: event.target.value }))}
value={pairForm.mode}
>
<option value="observe_only">Observe only</option>
<option value="maker">Maker</option>
<option value="taker">Taker</option>
<option value="both">Maker and taker</option>
</select>
</div>
<div className="field">
<label htmlFor="pair-edge-bps">Edge bps</label>
<input
disabled={!tradingModeSelected}
id="pair-edge-bps"
min="1"
onChange={(event) => setPairForm((current) => ({ ...current, edge_bps: event.target.value }))}
required={tradingModeSelected}
step="1"
type="number"
value={pairForm.edge_bps}
/>
</div>
<div className="field">
<label htmlFor="pair-min-notional">Min notional</label>
<input
disabled={!tradingModeSelected}
id="pair-min-notional"
min="0"
onChange={(event) => setPairForm((current) => ({ ...current, min_notional: event.target.value }))}
required={tradingModeSelected}
step="0.00000001"
type="number"
value={pairForm.min_notional}
/>
</div>
<div className="field">
<label htmlFor="pair-max-notional">Max notional</label>
<input
disabled={!tradingModeSelected}
id="pair-max-notional"
min="0.00000001"
onChange={(event) => setPairForm((current) => ({ ...current, max_notional: event.target.value }))}
required={tradingModeSelected}
step="0.00000001"
type="number"
value={pairForm.max_notional}
/>
</div>
</div>
<div className="button-row">
<button className="button" disabled={pairFormDisabled} type="submit">
Add / activate pair
</button>
</div>
</form>
<TableFrame>
<table>
<thead>
<tr>
<th>Pair</th>
<th>Mode</th>
<th>Configured edge</th>
<th>Limits</th>
<th>Route</th>
<th>Blocked</th>
<th>Config</th>
<th>Controls</th>
</tr>
</thead>
<tbody>
{pairs.length ? pairs.map((pair) => {
const pairId = pair.pair_id || pair.pairId;
const strategyConfig = pair.strategyConfig || pair.strategy_config || {};
const route = pair.priceRoute || pair.price_route || {};
const hasStrategyConfig = Boolean(strategyConfig.config_id || strategyConfig.configId);
const tradingMode = TRADING_PAIR_MODES.has(pair.mode);
const policyEnabled = policyEnabledDrafts[pairId] === true;
const configButtonDisabled = !edgeDrafts[pairId]
|| minNotionalDrafts[pairId] === undefined
|| minNotionalDrafts[pairId] === ''
|| !maxNotionalDrafts[pairId]
|| (policyEnabled && !maxQuoteAgeDrafts[pairId])
|| (!hasStrategyConfig && !tradingMode);
return (
<tr key={pairId}>
<td>
<div>{pair.asset_in_symbol || pair.asset_in} {'->'} {pair.asset_out_symbol || pair.asset_out}</div>
<div className="status-subtle mono">{truncateMiddle(pairId, 42)}</div>
</td>
<td><Pill label={pair.mode || pair.status} stateLabel={pair.canTrade || pair.can_trade ? 'healthy' : 'warning'} /></td>
<td>{formatConfiguredEdgeBps(strategyConfig.edge_bps, { prefix: false })}</td>
<td>
<div>{strategyConfig.min_notional ?? '0'} min</div>
<div>{strategyConfig.max_notional || 'Unavailable'} max</div>
<div className="status-subtle">
{strategyConfig.request_max_notional == null
? 'No request cap'
: `${strategyConfig.request_max_notional} request max`}
</div>
<div className="status-subtle">
{strategyConfig.request_max_slippage_bps == null
? 'No slippage cap'
: `${strategyConfig.request_max_slippage_bps} bps slippage max`}
</div>
<div className="status-subtle">{strategyConfig.price_max_age_ms || 'Unavailable'} ms price max age</div>
<div className="status-subtle">
{strategyConfig.maker_max_quote_age_enabled || strategyConfig.makerMaxQuoteAgeEnabled
? `${strategyConfig.maker_max_quote_age_ms ?? strategyConfig.makerMaxQuoteAgeMs} ms response max age`
: 'Response age policy disabled'}
</div>
</td>
<td>{route.source || 'Unavailable'}</td>
<td>{pair.blockReason || pair.block_reason || 'No'}</td>
<td>
<div>v{strategyConfig.version || 'Unavailable'}</div>
<div className="trace-row">
<span className="status-subtle">Edge</span>
<input
aria-label={`Edge bps for ${pairId}`}
min="1"
onChange={(event) => setEdgeDrafts((current) => ({
...current,
[pairId]: event.target.value,
}))}
step="1"
style={{ maxWidth: 92 }}
type="number"
value={edgeDrafts[pairId] ?? ''}
/>
</div>
<div className="trace-row">
<span className="status-subtle">Min</span>
<input
aria-label={`Min notional for ${pairId}`}
min="0"
onChange={(event) => setMinNotionalDrafts((current) => ({
...current,
[pairId]: event.target.value,
}))}
step="0.00000001"
style={{ maxWidth: 112 }}
type="number"
value={minNotionalDrafts[pairId] ?? ''}
/>
</div>
<div className="trace-row">
<span className="status-subtle">Max</span>
<input
aria-label={`Max notional for ${pairId}`}
min="0.00000001"
onChange={(event) => setMaxNotionalDrafts((current) => ({
...current,
[pairId]: event.target.value,
}))}
step="0.00000001"
style={{ maxWidth: 112 }}
type="number"
value={maxNotionalDrafts[pairId] ?? ''}
/>
</div>
<div className="trace-row">
<button
className="button secondary trace-copy-button"
disabled={configButtonDisabled}
onClick={() => updatePairConfig(pair)}
type="button"
>
{hasStrategyConfig ? 'Save' : 'Init'}
</button>
</div>
<div className="trace-row">
<label className="checkbox-row">
<input
aria-label={`Enable response age policy for ${pairId}`}
checked={policyEnabled}
onChange={(event) => setPolicyEnabledDrafts((current) => ({
...current,
[pairId]: event.target.checked,
}))}
type="checkbox"
/>
<span className="status-subtle">Age policy</span>
</label>
</div>
<div className="trace-row">
<span className="status-subtle">Max age</span>
<input
aria-label={`Max quote response age milliseconds for ${pairId}`}
disabled={!policyEnabled}
min="1"
onChange={(event) => setMaxQuoteAgeDrafts((current) => ({
...current,
[pairId]: event.target.value,
}))}
step="1"
style={{ maxWidth: 112 }}
type="number"
value={maxQuoteAgeDrafts[pairId] ?? ''}
/>
</div>
</td>
<td>
<div className="button-row">
{pair.enabled && pair.status !== 'disabled' ? (
<button className="button secondary trace-copy-button" onClick={() => pausePair(pair)} type="button">
Pause
</button>
) : (
<button className="button secondary trace-copy-button" onClick={() => activatePair(pair)} type="button">
Activate
</button>
)}
</div>
</td>
</tr>
);
}) : (
<tr><td colSpan={8}>No directed pairs are configured.</td></tr>
)}
</tbody>
</table>
</TableFrame>
</section>
);
}
function StrategyOverviewSection({ strategy }) {
const funnel = strategy.strategy_state.trade_funnel || {};
const counts = funnel.counts || {};
return (
<section className="panel">
<div className="panel-head">
<div>
<div className="eyebrow">Trading evidence</div>
<h2>Quotes, responses, and proven trades</h2>
<div className="panel-subtitle">
One place for quote truth: every row starts at the incoming quote, then shows whether we responded, why not, and whether any asset movement was proven.
</div>
</div>
</div>
<div className="metric-grid">
<MetricCard label="Successful trades" meta="Requires linked terminal outcome and settlement" value={String(funnel.successful_trade_count || 0)} />
<MetricCard
label="Gross edge est."
meta={`${funnel.successful_trade_gross_edge_estimate_count || 0} proven trades, before fees`}
signedValue={funnel.successful_trade_gross_edge_estimate_eure}
value={formatEur(funnel.successful_trade_gross_edge_estimate_eure)}
/>
<MetricCard label="Not filled" meta="Submitted but no settled inventory delta" value={String(counts.not_filled || 0)} />
<MetricCard label="Awaiting outcome" meta="Submitted, no durable terminal result yet" value={String(funnel.unresolved_submission_count || 0)} />
<MetricCard label="Rejected / blocked" meta="Strategy rejection or executor block" value={String((counts.rejected || 0) + (counts.blocked || 0))} />
<MetricCard label="Strategy armed" meta={`Paused ${formatBoolean(strategy.strategy_state.paused)}`} value={formatBoolean(strategy.strategy_state.armed)} />
<MetricCard label="Executor armed" meta={`Paused ${formatBoolean(strategy.executor_state.paused)}`} value={formatBoolean(strategy.executor_state.armed)} />
</div>
</section>
);
}
function SuccessfulTradesSection({ funnel, counts }) {
return (
<section className="panel">
<div className="panel-head">
<div>
<div className="eyebrow">Successful trades only</div>
<h3>Trades with proven asset movement</h3>
<div className="panel-subtitle">
This table excludes submitted-only quote responses. Realized PnL remains unavailable until fees and venue-native terminal fills are stored.
</div>
</div>
<div className="pills">
<Pill label={`${counts.completed || 0} completed`} stateLabel={(counts.completed || 0) > 0 ? 'healthy' : 'unknown'} />
<Pill label={`${formatEur(funnel.successful_trade_gross_edge_estimate_eure)} gross edge est.`} stateLabel={funnel.successful_trade_gross_edge_estimate_eure ? 'healthy' : 'unknown'} />
<Pill label={`${counts.not_filled || 0} not filled`} stateLabel={(counts.not_filled || 0) > 0 ? 'warning' : 'unknown'} />
</div>
</div>
<SuccessfulTradesTable items={funnel.successful_trades} />
</section>
);
}
function QuoteLifecycleSection({ items }) {
return (
<section className="panel full-width-evidence-panel">
<div className="panel-head">
<div>
<div className="eyebrow">Quote lifecycle</div>
<h3>Incoming quotes and what happened next</h3>
<div className="panel-subtitle">
Full-width quote table: incoming quote, response decision, result, decisive reason, and expandable lifecycle stages.
</div>
</div>
</div>
<QuoteLifecycleTable items={items} />
</section>
);
}
export default function StrategyPage({ strategy, onControl, page = 'strategy' }) {
const funnel = strategy.strategy_state.trade_funnel || {};
const counts = funnel.counts || {};
switch (page) {
case 'strategy-pairs':
return <PairConfigSection assetCatalog={strategy.asset_catalog} pairConfig={strategy.pair_config} onControl={onControl} />;
case 'strategy-competitiveness':
return (
<MakerCompetitivenessSection
pairConfig={strategy.pair_config}
summary={strategy.strategy_state.maker_competitiveness}
/>
);
case 'strategy-assets':
return <AssetCatalogSection assetCatalog={strategy.asset_catalog} onControl={onControl} />;
case 'strategy-trades':
return <SuccessfulTradesSection counts={counts} funnel={funnel} />;
case 'strategy-lifecycle':
return <QuoteLifecycleSection items={strategy.strategy_state.recent_lifecycle_rows} />;
case 'strategy':
default:
return <StrategyOverviewSection strategy={strategy} />;
}
}