fix(backtest): 结果页垃圾值/无图表端到端修复(empyrical×numpy2.0根因)
根因: empyrical 0.5.5 引用 numpy2.0 已移除的 np.NINF → compute_metrics 静默崩 → _metrics.json 不生成 → 结果页回退 vnpy 原始字段(单位混乱: total_return当百分数、max_drawdown当元 → 前端×100显 3305%/-50M%)。 - metrics.py: 导入 empyrical 前补回 np 别名(NINF/Inf/PINF/NaN/NAN/infty) - routes.py: benchmark-curve/risk-series 缺 metrics 文件时返空200(不再404拖垮整页); get_result 从 statistics 抽 relative_metrics - cta_engine.py: bench_df 日期 strip tz 防 pct_change 崩; metrics 块加 traceback 日志 - Result.vue: onMounted 用 Promise.allSettled 隔离7端点, 单接口失败不拖垮整页 - result_store.py: _safe_read_json 容错迁移后残留 NAS 绝对路径, stale path 不崩 list_results - datareader.py: read_index_daily 改从 vnpy DB 读 + 前缀解析交易所(sh→SSE, 避免 000300 被 guess_exchange 误判 SZSE)
This commit is contained in:
@@ -110,40 +110,75 @@ const filteredBenchmarkCurve = computed(() => filterDataByTimeRange(benchmarkCur
|
||||
const filteredRiskSeries = computed(() => filterDataByTimeRange(riskSeries.value))
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const [info, relMetrics, benchCurve, riskSer, eq, p, tr] = await Promise.all([
|
||||
getResult(taskId),
|
||||
getRelativeMetrics(taskId),
|
||||
getBenchmarkCurve(taskId),
|
||||
getRiskSeries(taskId),
|
||||
getEquityCurve(taskId),
|
||||
getDailyPnl(taskId),
|
||||
getTrades(taskId),
|
||||
])
|
||||
// 请求隔离:任一接口失败(如 benchmark-curve/risk-series 数据缺失)不得阻塞
|
||||
// 其余请求。statistics/equity/trades 有数据时必须正常渲染。用 Promise.allSettled
|
||||
// 保留并发,逐个取值,失败项保留默认空值 + console.warn。
|
||||
const settled = await Promise.allSettled([
|
||||
getResult(taskId),
|
||||
getRelativeMetrics(taskId),
|
||||
getBenchmarkCurve(taskId),
|
||||
getRiskSeries(taskId),
|
||||
getEquityCurve(taskId),
|
||||
getDailyPnl(taskId),
|
||||
getTrades(taskId),
|
||||
])
|
||||
const [rInfo, rRel, rBench, rRisk, rEq, rPnl, rTr] = settled
|
||||
|
||||
statistics.value = info.statistics || {}
|
||||
relativeMetrics.value = relMetrics
|
||||
benchmarkCurve.value = benchCurve
|
||||
riskSeries.value = riskSer
|
||||
equity.value = eq
|
||||
pnl.value = p
|
||||
trades.value = tr
|
||||
|
||||
if (info.symbol && info.start && info.end) {
|
||||
try {
|
||||
kline.value = await getKline(info.symbol, info.start, info.end)
|
||||
} catch {
|
||||
kline.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
logText.value = await getLog(taskId)
|
||||
} catch {
|
||||
logText.value = ''
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
if (rInfo.status === 'fulfilled') {
|
||||
statistics.value = rInfo.value.statistics || {}
|
||||
} else {
|
||||
console.warn('[Result] getResult failed:', rInfo.reason)
|
||||
}
|
||||
if (rRel.status === 'fulfilled') {
|
||||
relativeMetrics.value = rRel.value
|
||||
} else {
|
||||
console.warn('[Result] getRelativeMetrics failed:', rRel.reason)
|
||||
}
|
||||
if (rBench.status === 'fulfilled') {
|
||||
benchmarkCurve.value = rBench.value
|
||||
} else {
|
||||
console.warn('[Result] getBenchmarkCurve failed:', rBench.reason)
|
||||
}
|
||||
if (rRisk.status === 'fulfilled') {
|
||||
riskSeries.value = rRisk.value
|
||||
} else {
|
||||
console.warn('[Result] getRiskSeries failed:', rRisk.reason)
|
||||
}
|
||||
if (rEq.status === 'fulfilled') {
|
||||
equity.value = rEq.value
|
||||
} else {
|
||||
console.warn('[Result] getEquityCurve failed:', rEq.reason)
|
||||
}
|
||||
if (rPnl.status === 'fulfilled') {
|
||||
pnl.value = rPnl.value
|
||||
} else {
|
||||
console.warn('[Result] getDailyPnl failed:', rPnl.reason)
|
||||
}
|
||||
if (rTr.status === 'fulfilled') {
|
||||
trades.value = rTr.value
|
||||
} else {
|
||||
console.warn('[Result] getTrades failed:', rTr.reason)
|
||||
}
|
||||
|
||||
// kline 依赖 getResult 返回的 symbol/start/end,单独隔离
|
||||
const info = rInfo.status === 'fulfilled' ? rInfo.value : null
|
||||
if (info?.symbol && info?.start && info?.end) {
|
||||
try {
|
||||
kline.value = await getKline(info.symbol, info.start, info.end)
|
||||
} catch (e) {
|
||||
console.warn('[Result] getKline failed:', e)
|
||||
kline.value = []
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
logText.value = await getLog(taskId)
|
||||
} catch (e) {
|
||||
console.warn('[Result] getLog failed:', e)
|
||||
logText.value = ''
|
||||
}
|
||||
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
// 每日收益格式化:浮点精度 → 2 位;日期去 00:00:00
|
||||
|
||||
Reference in New Issue
Block a user