diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-18 10:36:17 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-18 10:36:17 +0800 |
| commit | cad7b02266c6fc582f4ea70422f0128fd0178f02 (patch) | |
| tree | f6c7bcfe601b9e004d60cbd3ec7ba3b47771fd0e /frontend/src | |
| parent | f3831e6cc62938c94b398e93e9f25e6f22164266 (diff) | |
| download | strategy-lab-cad7b02266c6fc582f4ea70422f0128fd0178f02.tar.gz | |
feat(frontend): 回测结果页与对比表接入投入口径一行三项
[变更性质] 页面集成,任务 A1/A2 前端口径统一。
[新增功能] 结果页 metric 区新增累计投入/最终持仓估值/投入回报率三卡(data-testid=capital-reporting,注明"不含初始账户闲置现金"口径),复用现有 .metric 与 formatMoney 数字格式、不加新字色;实验记录页条件差异表新增同口径三行(逐 run 对照,动作同步深化到 status/time 之后)。
[实现方案] 共享 capitalReporting 推导;resultsAccounting.test 断言更新为 9 张 metric 卡并新增三卡 DOM 实测断言。
[影响范围] ProjectResultsTab、RunsPage、resultsAccounting.test;vitest 84/84。
Diffstat (limited to 'frontend/src')
| -rw-r--r-- | frontend/src/lib/resultsAccounting.test.ts | 6 | ||||
| -rw-r--r-- | frontend/src/pages/ProjectResultsTab.svelte | 20 | ||||
| -rw-r--r-- | frontend/src/pages/RunsPage.svelte | 6 |
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> |
