summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--frontend/src/lib/resultsAccounting.test.ts6
-rw-r--r--frontend/src/pages/ProjectResultsTab.svelte20
-rw-r--r--frontend/src/pages/RunsPage.svelte6
3 files changed, 31 insertions, 1 deletions
diff --git a/frontend/src/lib/resultsAccounting.test.ts b/frontend/src/lib/resultsAccounting.test.ts
index cccb7ed..b695713 100644
--- a/frontend/src/lib/resultsAccounting.test.ts
+++ b/frontend/src/lib/resultsAccounting.test.ts
@@ -70,7 +70,11 @@ describe('results accounting labels + values (live browser accounting)', () => {
expect(text).toContain('已完成的开仓并全部平仓的完整回合');
expect(text).not.toContain('成交次数(不含撤单)');
// numeric trade_count shows through: equity div reached rendering
- expect(host.querySelectorAll('.metric').length).toBe(6);
+ // 投入口径 reporting(任务 A)追加 3 张卡:累计投入/持仓估值/回报率 → 9
+ expect(host.querySelectorAll('.metric').length).toBe(9);
+ expect(host.querySelectorAll('[data-testid="capital-reporting"]').length).toBe(1);
+ expect(text).toContain('累计投入');
+ expect(text).toContain('投入口径不含初始账户闲置现金');
// turnover: two fills with distinct values (buy vs sell prices differ)
const rows = [...host.querySelectorAll('td.num')].map((td) => td.textContent.trim());
const hasSell = [...host.children].join('').includes('卖出');
diff --git a/frontend/src/pages/ProjectResultsTab.svelte b/frontend/src/pages/ProjectResultsTab.svelte
index f479116..c08bf3f 100644
--- a/frontend/src/pages/ProjectResultsTab.svelte
+++ b/frontend/src/pages/ProjectResultsTab.svelte
@@ -14,6 +14,7 @@
metricsLabels,
metricsRow
} from '../lib/format';
+ import { capitalReporting } from '../lib/capitalMetrics';
import type { Run, BacktestResult } from '../lib/types';
interface Props {
@@ -106,6 +107,8 @@
const ml = $derived(metricsLabels());
const mr = $derived(result ? metricsRow(result.metrics) : []);
+ // 投入口径 reporting(任务 A):投入/持仓估值/回报,口径注明不含闲置现金
+ const cap = $derived(result ? capitalReporting(result) : null);
</script>
<div class="stack">
@@ -185,6 +188,23 @@
</div>
</div>
{/if}
+ {#if cap}
+ <div class="metric-grid" data-testid="capital-reporting">
+ <div class="metric">
+ <div class="mlabel">累计投入</div>
+ <div class="mvalue">{formatMoney(cap.invested)}</div>
+ </div>
+ <div class="metric">
+ <div class="mlabel">最终持仓估值</div>
+ <div class="mvalue">{formatMoney(cap.holdingValue)}</div>
+ </div>
+ <div class="metric">
+ <div class="mlabel">投入回报率</div>
+ <div class="mvalue">{cap.returnPct ?? '—'}</div>
+ </div>
+ </div>
+ <p class="hint">投入口径不含初始账户闲置现金:累计投入 = 首日现金 − 末日现金;持仓估值 = 末日持仓 × 最新收盘价。</p>
+ {/if}
<p class="hint">
平仓回合数为已完成的开仓并全部平仓的完整回合(1 个回合 = 1 次平仓),不含撤单与未平仓的单笔成交;成交记录中的“金额”为真实成交额(数量 × 成交价),非持仓成本。结果非投资建议;未完全模拟流动性/涨跌停等限制。
引擎 {result.engine?.name} {result.engine?.version}
diff --git a/frontend/src/pages/RunsPage.svelte b/frontend/src/pages/RunsPage.svelte
index 154fd67..ad72b5d 100644
--- a/frontend/src/pages/RunsPage.svelte
+++ b/frontend/src/pages/RunsPage.svelte
@@ -6,6 +6,7 @@
import { listRuns } from '../lib/client';
import { extractStatusMessage } from '../lib/state';
import { fmtDateTime, runStatusLabel, runStatusBadge, fmtPct, fmtNum, formatMoney } from '../lib/format';
+import { capitalReporting } from '../lib/capitalMetrics';
import type { Run } from '../lib/types';
let runs: Run[] = $state([]);
@@ -88,6 +89,11 @@
}
mk('状态', selected.map((r) => runStatusLabel[r.status]));
mk('时间', selected.map((r) => r.created_at));
+ // 投入口径 reporting(任务 A):与结果页同口径,不含初始闲置现金
+ const caps = selected.map((r) => (r.result ? capitalReporting(r.result) : null));
+ mk('累计投入', caps.map((c) => (c ? formatMoney(c.invested) : '—')));
+ mk('持仓估值', caps.map((c) => (c ? formatMoney(c.holdingValue) : '—')));
+ mk('投入回报率', caps.map((c) => (c ? (c.returnPct ?? '—') : '—')));
return rows;
});
</script>