From 51461a25bcb461d64bfe3f0c7a4a02ac31e18977 Mon Sep 17 00:00:00 2001 From: philipp Date: Tue, 14 Apr 2026 10:07:00 +0200 Subject: [PATCH] Show proven trade gross edge total Proof: successful trade summary now aggregates gross edge estimates only from completed lifecycle rows with linked settlement evidence; tests prove completed-without-delta rows are excluded. Assumptions: gross edge estimate is useful operator evidence but remains pre-fee and not venue-native realized PnL. Still fake: fee-complete realized trade PnL and venue-native terminal fill events remain unavailable. --- src/core/operator-dashboard.mjs | 21 +++++++++++++++++++ .../static/pages/StrategyPage.jsx | 7 +++++++ test/operator-dashboard-ui-static.test.mjs | 3 +++ test/operator-dashboard.test.mjs | 6 ++++++ 4 files changed, 37 insertions(+) diff --git a/src/core/operator-dashboard.mjs b/src/core/operator-dashboard.mjs index b09ace2..33fb751 100644 --- a/src/core/operator-dashboard.mjs +++ b/src/core/operator-dashboard.mjs @@ -1341,8 +1341,12 @@ function buildTradeFunnelSummary(lifecycleRows = []) { } } + const grossEdgeEstimate = summarizeGrossEdgeEstimate(successfulTrades); + return { successful_trade_count: successfulTrades.length, + successful_trade_gross_edge_estimate_eure: grossEdgeEstimate.total_eure, + successful_trade_gross_edge_estimate_count: grossEdgeEstimate.count, unresolved_submission_count: unresolvedSubmissions.length, no_trade_count: noTradeRows.length, successful_trades: successfulTrades, @@ -1356,6 +1360,23 @@ function buildTradeFunnelSummary(lifecycleRows = []) { }; } +function summarizeGrossEdgeEstimate(rows = []) { + let total = 0n; + let count = 0; + + for (const row of rows || []) { + const value = row?.gross_edge_value_eure || estimateGrossEdgeValueEure(row); + if (value == null) continue; + total += parseScaledDecimal(value); + count += 1; + } + + return { + count, + total_eure: count > 0 ? formatScaledDecimal(total) : null, + }; +} + function buildSystemSummary({ servicesByName, activeAlerts, recentAlerts }) { const historyWriterState = servicesByName['history-writer']?.state || {}; void activeAlerts; diff --git a/src/operator-dashboard/static/pages/StrategyPage.jsx b/src/operator-dashboard/static/pages/StrategyPage.jsx index b9a82be..005348d 100644 --- a/src/operator-dashboard/static/pages/StrategyPage.jsx +++ b/src/operator-dashboard/static/pages/StrategyPage.jsx @@ -293,6 +293,12 @@ export default function StrategyPage({ strategy }) {
+ @@ -312,6 +318,7 @@ export default function StrategyPage({ strategy }) {
0 ? 'healthy' : 'unknown'} /> + 0 ? 'warning' : 'unknown'} />
diff --git a/test/operator-dashboard-ui-static.test.mjs b/test/operator-dashboard-ui-static.test.mjs index 06b0b25..c0beb47 100644 --- a/test/operator-dashboard-ui-static.test.mjs +++ b/test/operator-dashboard-ui-static.test.mjs @@ -11,6 +11,9 @@ test('strategy page owns consolidated quote lifecycle and successful trade table assert.match(strategySource, /Incoming quotes and what happened next/); assert.match(strategySource, /Responded\?/); assert.match(strategySource, /Successful trades only/); + assert.match(strategySource, /Gross edge est\./); + assert.match(strategySource, /successful_trade_gross_edge_estimate_eure/); + assert.match(strategySource, /before fees/); assert.match(strategySource, /Show lifecycle/); assert.match(strategySource, /Submitted means the relay accepted the response; it does not prove a trade\./); assert.doesNotMatch(strategySource, /Actionable|actionable/); diff --git a/test/operator-dashboard.test.mjs b/test/operator-dashboard.test.mjs index 8838806..ef0aa44 100644 --- a/test/operator-dashboard.test.mjs +++ b/test/operator-dashboard.test.mjs @@ -752,6 +752,8 @@ test('successful trade rows require completed outcome with linked settled invent command_id: 'cmd-completed', quote_id: 'quote-completed', pair: config.activePair, + gross_edge_pct: '0.49', + eure_notional: '50', outcome_status: 'completed', outcome_reason: 'matched_inventory_delta', outcome_observed_at: '2026-04-09T09:01:00.000Z', @@ -770,6 +772,8 @@ test('successful trade rows require completed outcome with linked settled invent command_id: 'cmd-completed-no-delta', quote_id: 'quote-completed-no-delta', pair: config.activePair, + gross_edge_pct: '99', + eure_notional: '100', outcome_status: 'completed', outcome_reason: 'settled', outcome_observed_at: '2026-04-09T09:02:00.000Z', @@ -786,6 +790,8 @@ test('successful trade rows require completed outcome with linked settled invent const funnel = bootstrap.strategy.strategy_state.trade_funnel; assert.equal(funnel.successful_trade_count, 1); assert.equal(funnel.successful_trades[0].quote_id, 'quote-completed'); + assert.equal(funnel.successful_trade_gross_edge_estimate_eure, '0.245'); + assert.equal(funnel.successful_trade_gross_edge_estimate_count, 1); assert.match(funnel.successful_trades[0].settlement_summary.text, /\+0\.00037014 BTC/); assert.equal(funnel.counts.submitted, 1); assert.equal(funnel.counts.completed, 2);