feat: 参数寻优新增买入持有基准对比 — 两个寻优接口返回同口径 buy_hold(run_buy_hold_benchmark),全局最佳/最优结果总收益旁展示 [买入持有:xx.xx%],涨红跌绿

This commit is contained in:
GitHub
2026-09-04 22:42:13 +08:00
parent 9b9d123105
commit 5476ba0f33
4 changed files with 58 additions and 1 deletions
+14
View File
@@ -257,12 +257,24 @@ export interface OptimizeHeatmap {
data: Array<[number, number, number | null]>
}
/** 买入持有基准(同区间/同费率,首根买入持有到末根,与一条龙评估同口径) */
export interface BuyHoldBenchmark {
total_return: number
annual_return: number
max_drawdown: number
sharpe: number
calmar: number
volatility: number
}
export interface OptimizeResult {
strategy: string
param_names: string[]
results: GridPointResult[]
best: GridPointResult | null
heatmap: OptimizeHeatmap | null
/** 买入持有基准,供直观对比「策略 vs 买入不动」(老版本后端结果可能缺省) */
buy_hold?: BuyHoldBenchmark | null
}
// ── 一键寻优所有策略(Phase 6) ──────────────────────────────────────────────
@@ -299,6 +311,8 @@ export interface OptimizeAllResult {
best: OptimizeAllRankEntry | null
per_strategy: Record<string, OptimizeAllRankEntry>
total_grid_points: number
/** 买入持有基准,供直观对比「策略 vs 买入不动」(老版本后端结果可能缺省) */
buy_hold?: BuyHoldBenchmark | null
}
// ── 错误响应(后端 ApiErrorResponse) ─────────────────────────────────────────
+20
View File
@@ -196,6 +196,10 @@ function onViewAll(strategyName: string, params: Record<string, number | string>
function pct(v: number | null | undefined): string {
return v !== null && v !== undefined && Number.isFinite(v) ? `${(v * 100).toFixed(2)}%` : '-'
}
/** 买入持有的盈亏配色(A 股习惯:涨红跌绿;非数值不加色) */
function bhClass(v: number | null | undefined): string {
return v !== null && v !== undefined && Number.isFinite(v) ? (v >= 0 ? 'pos' : 'neg') : ''
}
function num(v: number | null | undefined, d = 2): string {
return v !== null && v !== undefined && Number.isFinite(v) ? v.toFixed(d) : '-'
}
@@ -316,6 +320,11 @@ const rankingGrades = computed<GradeResult[]>(() =>
<span class="best-return pos">
{{ (store.optimizeResult.best.total_return! * 100).toFixed(2) }}%
</span>
<span v-if="store.optimizeResult.buy_hold" class="best-bh">
[买入持有<span :class="bhClass(store.optimizeResult.buy_hold.total_return)">{{
pct(store.optimizeResult.buy_hold.total_return)
}}</span>]
</span>
<span class="best-meta">
夏普 {{ store.optimizeResult.best.sharpe?.toFixed(2) }} · 回撤
{{ (store.optimizeResult.best.max_drawdown! * 100).toFixed(2) }}%
@@ -351,6 +360,11 @@ const rankingGrades = computed<GradeResult[]>(() =>
<span class="best-return pos">
{{ (store.optimizeAllResult.best.total_return! * 100).toFixed(2) }}%
</span>
<span v-if="store.optimizeAllResult.buy_hold" class="best-bh">
[买入持有<span :class="bhClass(store.optimizeAllResult.buy_hold.total_return)">{{
pct(store.optimizeAllResult.buy_hold.total_return)
}}</span>]
</span>
<span class="best-meta">
夏普 {{ store.optimizeAllResult.best.sharpe?.toFixed(2) }} · 回撤
{{ (store.optimizeAllResult.best.max_drawdown! * 100).toFixed(2) }}% · 胜率
@@ -542,6 +556,12 @@ const rankingGrades = computed<GradeResult[]>(() =>
font-weight: 700;
font-family: var(--font-mono);
}
/* 买入持有对比项:标签/括号弱化不抢焦点,百分比按盈亏走 .pos/.neg 红绿 */
.best-bh {
color: var(--text-dim);
font-size: 13px;
font-family: var(--font-mono);
}
.best-meta {
color: var(--text-dim);
font-size: 12px;