From 375584174fb7191a57c5423fea45924ad6d812d5 Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Fri, 18 Sep 2026 15:49:44 +0800 Subject: [变更性质] feat(frontend) [新增功能] round5 主题基线重置:shadcn preset b6t6C6CTw CLI init、app.css 仅保留 tailwind + shadcn 主题变量层 [实现方案] 删除 round3 自定义 token/布局原语/legacy 别名;theme.ts 删除;mobileCss 守门测试重写 [影响范围] src/app.css、components.json、lib/utils.ts、lib/theme.ts、测试 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/ProjectResultsTab.svelte | 165 ++++++++++++++++------------ 1 file changed, 95 insertions(+), 70 deletions(-) (limited to 'frontend/src/pages/ProjectResultsTab.svelte') diff --git a/frontend/src/pages/ProjectResultsTab.svelte b/frontend/src/pages/ProjectResultsTab.svelte index 82a7009..181d6a4 100644 --- a/frontend/src/pages/ProjectResultsTab.svelte +++ b/frontend/src/pages/ProjectResultsTab.svelte @@ -19,6 +19,8 @@ import { Badge } from '$lib/components/ui/badge'; import * as Card from '$lib/components/ui/card'; import * as Table from '$lib/components/ui/table'; + import * as Select from '$lib/components/ui/select'; + import * as Tabs from '$lib/components/ui/tabs'; import type { Run, BacktestResult } from '../lib/types'; interface Props { @@ -113,14 +115,19 @@ const mr = $derived(result ? metricsRow(result.metrics) : []); // 投入口径 reporting(任务 A):投入/持仓估值/回报,口径注明不含闲置现金 const cap = $derived(result ? capitalReporting(result) : null); + + const tile = 'gap-1 min-w-0'; + const tileLabel = 'text-xs text-muted-foreground'; + const tileValue = 'text-2xl font-bold tabular-nums text-foreground leading-tight break-all'; + const metricValueProps = 'data-testid="metric-value"'; -
-
-

回测结果

+
+
+

回测结果

{#if run} - - Run {run.id.slice(0, 8)}… + + Run {run.id.slice(0, 8)}… {runStatusLabel[run.status]} {/if} @@ -134,53 +141,66 @@ {#if run && !busy && !error} {#if history.length > 1} -
- - +
+ 查看其他回测: + switchToRun(v)} + > + + {#snippet children()} + + {history.find((h) => h.id === run?.id)?.created_at && fmtDateTime(history.find((h) => h.id === run?.id)!.created_at)} · {history.find((h) => h.id === run?.id) && runStatusLabel[history.find((h) => h.id === run?.id)!.status]} + + {/snippet} + + + {#each history as h (h.id)} + {fmtDateTime(h.created_at)} · {runStatusLabel[h.status]} + {/each} + +
{/if} {#if run.error} - {run.error} + {run.error} {/if} {#if !result} {:else} {#if result.warnings?.length} - + -
    +
      {#each result.warnings as w, i (i)}
    • {w}
    • {/each}
    {/if} - + {#if result.metrics} {@const mrow = result.metrics} -
    -
    总收益率
    {fmtPct(mrow.total_return)}
    -
    年化收益率
    {fmtPct(mrow.annual_return)}
    -
    最大回撤
    {fmtPct(mrow.max_drawdown)}
    -
    夏普比率
    {fmtNum(mrow.sharpe)}
    -
    平仓回合数
    {mrow.trade_count ?? "—"}
    -
    期末权益
    {formatMoney(mrow.final_equity)}
    -
    +
    +
    总收益率
    {fmtPct(mrow.total_return)}
    +
    年化收益率
    {fmtPct(mrow.annual_return)}
    +
    最大回撤
    {fmtPct(mrow.max_drawdown)}
    +
    夏普比率
    {fmtNum(mrow.sharpe)}
    +
    平仓回合数
    {mrow.trade_count ?? "—"}
    +
    期末权益
    {formatMoney(mrow.final_equity)}
    +
    {/if} {#if cap} -
    -
    累计投入
    {formatMoney(cap.invested)}
    -
    最终持仓估值
    {formatMoney(cap.holdingValue)}
    -
    投入回报率
    {cap.returnPct ?? '—'}
    +
    +
    累计投入
    {formatMoney(cap.invested)}
    +
    最终持仓估值
    {formatMoney(cap.holdingValue)}
    +
    投入回报率
    {cap.returnPct ?? '—'}
    -

    投入口径不含初始账户闲置现金:累计投入 = 首日现金 − 末日现金;持仓估值 = 末日持仓 × 最新收盘价。

    +

    投入口径不含初始账户闲置现金:累计投入 = 首日现金 − 末日现金;持仓估值 = 末日持仓 × 最新收盘价。

    {/if} -

    +

    平仓回合数为已完成的开仓并全部平仓的完整回合(1 个回合 = 1 次平仓),不含撤单与未平仓的单笔成交;成交记录中的“金额”为真实成交额(数量 × 成交价),非持仓成本。结果非投资建议;未完全模拟流动性/涨跌停等限制。 引擎 {result.engine?.name} {result.engine?.version} {#if result.elapsed_ms} · 耗时 {(result.elapsed_ms / 1000).toFixed(1)}s{/if} @@ -188,11 +208,13 @@

    - -
    - - -
    + + (chartMode = v as 'equity' | 'drawdown')} class="w-fit"> + + 权益曲线({result.equity.length} 点) + 回撤曲线 + + {#if chartMode === "equity"} {:else} @@ -200,59 +222,62 @@ {/if} - -

    订单与持仓记录

    -
    + +

    订单与持仓记录

    +
    -

    成交记录 ({result.trades.length})

    +

    成交记录 ({result.trades.length})

    {#if result.trades.length > 0} - - - - 日期 - 标的 - 方向 - 数量 - 价格 - 金额 - 佣金 - - - - {#each result.trades.slice(0, 80) as t, i (i)} +
    + + - {t.date} - {t.symbol} - {t.side === "buy" ? "买入" : "卖出"} - {t.quantity} - {fmtNum(t.price, 3)} - {fmtNum(t.value)} - {fmtNum(t.commission, 4)} + 日期 + 标的 + 方向 + 数量 + 价格 + 金额 + 佣金 - {/each} - - + + + {#each result.trades.slice(0, 80) as t, i (i)} + + {t.date} + {t.symbol} + {t.side === "buy" ? "买入" : "卖出"} + {t.quantity} + {fmtNum(t.price, 3)} + {fmtNum(t.value)} + {fmtNum(t.commission, 4)} + + {/each} + + +
    {#if result.trades.length > 80} -

    仅显示前 80 条,共 {result.trades.length} 条

    +

    仅显示前 80 条,共 {result.trades.length} 条

    {/if} {:else} -

    本区间未发生成交

    +

    本区间未发生成交

    {/if}
    -

    策略日志

    +

    策略日志

    {#if logsOpen} -
    {result.logs.join("\n")}
    +
    {result.logs.join("\n")}
    {/if}
    -

    数据与引擎 - 本轮使用的引擎版本、耗时与消耗内存均在上方备注。 +

    + 数据与引擎 + 本轮使用的引擎版本、耗时与消耗内存均在上方备注。

    -

    +

    结果由对应策略代码、配置、数据清单(数据哈希 {result.data_manifest_hash?.slice(0, 12)})以及当时引擎共同决定。

    -- cgit v1.2.3