mirror of
https://ghfast.top/https://github.com/aeroxw/easy-tdx.git
synced 2026-09-12 14:34:15 +08:00
fix(web-ui): 参数寻优「查看」用寻优时的标的快照,避免输入框/路由切换污染 URL
- OptimizeView「查看」拼 URL 前从输入框实时值取 code/startDate/endDate/category, 导致两个问题:(1) 寻优后改输入框代码再点查看,URL 指向没回测过的标的; (2) 切走再回 /optimize,组件 ref 丢失,URL 里 symbol/startDate/endDate 全空。 - 将标的上下文快照(取行情成功那一刻冻结)下沉到 Pinia store 的 optimizeContext, 与 optimizeResult/optimizeAllResult 同生命周期持久化,跨路由保留。 - buildBacktestQuery 改读 store.optimizeContext,输入框改动与组件卸载都不再污染。
This commit is contained in:
@@ -18,6 +18,7 @@ import type {
|
||||
BacktestRequest,
|
||||
BacktestResult,
|
||||
Bar,
|
||||
Category,
|
||||
MultiStrategyBacktestRequest,
|
||||
PortfolioBacktestRequest,
|
||||
PortfolioResult,
|
||||
@@ -162,6 +163,21 @@ export const useBacktestStore = defineStore('backtest', () => {
|
||||
const optimizeResult = ref<OptimizeResult | null>(null)
|
||||
const optimizeRunning = ref(false)
|
||||
|
||||
/** 寻优实际使用的标的上下文(取行情成功那一刻冻结)。
|
||||
* 放在 store 而非组件里,是为了在用户切走再回 /optimize 时,「查看」按钮仍能拼出正确 URL
|
||||
* —— 组件 ref 在卸载后丢失,而 store 与 optimizeResult 同生命周期保留。
|
||||
* 由 OptimizeView 在 loadBars() 成功后通过 setOptimizeContext() 写入。 */
|
||||
const optimizeContext = ref<{
|
||||
code: string
|
||||
category: Category
|
||||
startDate: string
|
||||
endDate: string
|
||||
} | null>(null)
|
||||
|
||||
function setOptimizeContext(ctx: { code: string; category: Category; startDate: string; endDate: string }) {
|
||||
optimizeContext.value = ctx
|
||||
}
|
||||
|
||||
/** 提交寻优后台任务并轮询直到完成。 */
|
||||
async function runOptimize(req: OptimizeBacktestRequest) {
|
||||
optimizeRunning.value = true
|
||||
@@ -240,6 +256,7 @@ export const useBacktestStore = defineStore('backtest', () => {
|
||||
multiStrategyRunning,
|
||||
optimizeResult,
|
||||
optimizeRunning,
|
||||
optimizeContext,
|
||||
optimizeAllResult,
|
||||
optimizeAllRunning,
|
||||
// getters
|
||||
@@ -255,5 +272,6 @@ export const useBacktestStore = defineStore('backtest', () => {
|
||||
clearMultiStrategy,
|
||||
runOptimize,
|
||||
runOptimizeAll,
|
||||
setOptimizeContext,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -66,6 +66,13 @@ async function onRun() {
|
||||
// 1. 先取行情
|
||||
const ok = await symbolPicker.value?.loadBars()
|
||||
if (!ok) return
|
||||
// 取行情成功 → 冻结本次寻优真正使用的标的上下文,供「查看」拼 URL(存 store,跨路由保留)
|
||||
store.setOptimizeContext({
|
||||
code: code.value,
|
||||
category: category.value,
|
||||
startDate: startDate.value,
|
||||
endDate: endDate.value,
|
||||
})
|
||||
// 2. 校验寻优参数
|
||||
if (Object.keys(paramGrid.value).length === 0) {
|
||||
store.error = '请勾选至少 1 个参数并填入取值'
|
||||
@@ -91,6 +98,13 @@ async function onRunAll() {
|
||||
// 1. 先取行情
|
||||
const ok = await symbolPicker.value?.loadBars()
|
||||
if (!ok) return
|
||||
// 取行情成功 → 冻结本次寻优真正使用的标的上下文,供「查看」拼 URL(存 store,跨路由保留)
|
||||
store.setOptimizeContext({
|
||||
code: code.value,
|
||||
category: category.value,
|
||||
startDate: startDate.value,
|
||||
endDate: endDate.value,
|
||||
})
|
||||
// 2. 一键寻优
|
||||
await store.runOptimizeAll({
|
||||
cash: cash.value,
|
||||
@@ -99,16 +113,20 @@ async function onRunAll() {
|
||||
})
|
||||
}
|
||||
|
||||
/** 「查看」跳转时,把当前标的 + 周期 + 日期范围一并塞进 query,
|
||||
* 让回测页能完整复现寻优时的行情(而非只带策略参数)。 */
|
||||
/** 「查看」跳转时,把本次寻优实际使用的标的 + 周期 + 日期范围一并塞进 query,
|
||||
* 让回测页能完整复现寻优时的行情(而非只带策略参数)。
|
||||
* 注意:必须读 store.optimizeContext(取行情成功时冻结),不能读输入框实时值 ——
|
||||
* 否则寻优完成后改了输入框代码,「查看」URL 会被污染,指向一个根本没被回测过的标的;
|
||||
* 且不能读组件 ref,否则切走再回 /optimize 时排名还在但上下文已丢失。 */
|
||||
function buildBacktestQuery(strategyName: string, params: Record<string, number | string>) {
|
||||
const ctx = store.optimizeContext
|
||||
return {
|
||||
strategy: strategyName,
|
||||
params: JSON.stringify(params),
|
||||
symbol: code.value,
|
||||
startDate: startDate.value,
|
||||
endDate: endDate.value,
|
||||
category: category.value,
|
||||
symbol: ctx?.code ?? '',
|
||||
startDate: ctx?.startDate ?? '',
|
||||
endDate: ctx?.endDate ?? '',
|
||||
category: ctx?.category ?? category.value,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user