unrip/src/operator-dashboard/static/pages/StrategyPage.jsx
philipp 686b922342
All checks were successful
deploy / deploy (push) Successful in 58s
Split strategy dashboard sections
Proof: operator dashboard Strategy panels now render as separate sidebar menu destinations for overview, pair config, competitiveness, asset registry, successful trades, and quote lifecycle; static UI coverage and the dashboard bundle verify the routing.

Assumptions: this is a UI-only operator cleanup inside the active maker timing and competitiveness turn; it does not change strategy decisions, pair config, execution, persistence, live funds, or response policy.

Still fake: venue-native terminal fill ids and fee-complete realized PnL remain unavailable.
2026-05-19 17:42:10 +02:00

1302 lines
54 KiB
JavaScript

import { Fragment, useEffect, useMemo, 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']);
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 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);
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>
</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>{formatTerms(item.submitted_terms)}</div>
</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 MakerCompetitivenessSection({ summary, pairConfig }) {
const total = summary?.total || {};
const groups = summary?.groups || [];
const ageBuckets = summary?.age_buckets || [];
const latestErrors = summary?.latest_errors || [];
const policySkips = summary?.policy_skips || [];
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'} />
</div>
</div>
<div className="metric-grid">
<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>
<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>
{groups.length ? groups.slice(0, 12).map((group, index) => {
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}:${index}`}>
<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>
);
}) : (
<tr><td colSpan={9}>No competitiveness rows are available yet.</td></tr>
)}
</tbody>
</table>
</TableFrame>
<div className="two-column-grid">
<TableFrame>
<table>
<thead>
<tr>
<th>Latency stage</th>
<th>p50</th>
<th>p90</th>
<th>p99</th>
</tr>
</thead>
<tbody>
{(summary?.latency_stages || []).length ? summary.latency_stages.map((stage) => (
<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>
)) : (
<tr><td colSpan={4}>No stage timing percentiles are available yet.</td></tr>
)}
</tbody>
</table>
</TableFrame>
<TableFrame>
<table>
<thead>
<tr>
<th>Age bucket</th>
<th>Outcome</th>
<th>Count</th>
<th>Accepted</th>
</tr>
</thead>
<tbody>
{ageBuckets.length ? ageBuckets.slice(0, 12).map((bucket, index) => (
<tr key={`${bucket.pair}:${bucket.quote_age_bucket}:${bucket.outcome_status}:${index}`}>
<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>
)) : (
<tr><td colSpan={4}>No quote-age buckets are available yet.</td></tr>
)}
</tbody>
</table>
</TableFrame>
</div>
<div className="two-column-grid">
<TableFrame>
<table>
<thead>
<tr>
<th>Latest relay errors</th>
<th>Quote age</th>
<th>Error</th>
</tr>
</thead>
<tbody>
{latestErrors.length ? latestErrors.map((error) => (
<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>{error.error_message || 'Error text unavailable'}</td>
</tr>
)) : (
<tr><td colSpan={3}>No relay errors are available yet.</td></tr>
)}
</tbody>
</table>
</TableFrame>
<TableFrame>
<table>
<thead>
<tr>
<th>Policy skips</th>
<th>Age</th>
<th>Config</th>
</tr>
</thead>
<tbody>
{policySkips.length ? policySkips.map((skip) => (
<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>
)) : (
<tr><td colSpan={3}>No policy skips are available yet.</td></tr>
)}
</tbody>
</table>
</TableFrame>
</div>
</section>
);
}
function QuoteLifecycleTable({ items }) {
const [expanded, setExpanded] = useState(() => new Set());
const [showStrategyRejected, setShowStrategyRejected] = useState(true);
const [quoteDisplayPaused, setQuoteDisplayPaused] = useState(false);
const [displayItems, setDisplayItems] = useState(() => items || []);
const liveNow = useNow();
const [displayNow, setDisplayNow] = useState(() => Date.now());
useEffect(() => {
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],
);
function toggle(rowKey) {
setExpanded((current) => {
const next = new Set(current);
if (next.has(rowKey)) next.delete(rowKey);
else next.add(rowKey);
return next;
});
}
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={() => setQuoteDisplayPaused((paused) => !paused)}
type="button"
>
{quoteDisplayPaused ? 'Resume display' : 'Pause display'}
</button>
{quoteDisplayPaused ? <Pill label="Display paused" stateLabel="warning" /> : null}
</div>
{!displayItems.length ? (
<EmptyState>No quote lifecycle evidence has been observed yet.</EmptyState>
) : !visibleItems.length ? (
<EmptyState>No quote lifecycle rows match the current filters.</EmptyState>
) : (
<TableFrame>
<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>
{visibleItems.map((item, index) => {
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;
return (
<Fragment key={rowKey}>
<tr className={item.live_flash_at ? 'quote-row-flash' : undefined} key={`${rowKey}:row`}>
<td>
<div>{formatTimestamp(quoteTime)}</div>
<div className="status-subtle quote-age">{formatRelativeAge(quoteTime, displayNow)}</div>
{item.latest_stage_at && item.latest_stage_at !== item.quote_activity_at ? (
<div className="status-subtle">Updated {formatTimestamp(item.latest_stage_at)} · {formatRelativeAge(item.latest_stage_at, displayNow)}</div>
) : null}
</td>
<td><IdentifierRow label="Quote" value={item.quote_id} /></td>
<td>
<div>{formatTerms(item.request_terms || item.submitted_terms)}</div>
<div className="status-subtle mono">{truncateMiddle(item.pair || '', 34)}</div>
</td>
<td>{responseLabel(item)}</td>
<td><Pill label={item.lifecycle_label} stateLabel={item.lifecycle_tone} /></td>
<td>
<div>{item.reason_text}</div>
<div className="status-subtle mono">{item.reason_code || 'reason_unknown'}</div>
</td>
<td>
<div className={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">{formatConfiguredEdgeBps(item.edge_bps)}</div>
<div className="status-subtle">{notionalLabel(item)}</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} />;
}
}