feat(api): 回测参数校验—5提交入口统一拦截(2029结束日期可提交根治)——用户实况portfolio_ef8b655a零校验跑垃圾结果;sanguo_api/validation.py:L1静态(格式/先后/未来/区间≥30天/资金/费率0~1%)+L2数据最新日(600000日线锚定MAX(datetime),24h模块缓存,查库失败退化仅L1);接线CTA/组合/优化/因子/模拟盘回放5入口,400中文业务提示;前端5页日期控件禁选未来日期(disableFutureDate共享);+10测试含2029回归,API 115绿,前端build绿 [vps]
CI/CD / test (push) Successful in 19s
CI/CD / nas-deploy (push) Successful in 28s
CI/CD / nas-verify (push) Successful in 10s

This commit is contained in:
2026-08-15 21:32:32 +08:00
parent 1c6bdf6a89
commit 5615b11640
11 changed files with 236 additions and 10 deletions
+3 -2
View File
@@ -4,6 +4,7 @@ import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getStrategies, getParams, type StrategyItem } from '@/api/strategy'
import { submitCta, getTaskParams } from '@/api/backtest'
import { disableFutureDate } from '@/utils/dates'
import { apiClient } from '@/api/client'
interface InstLike {
@@ -214,10 +215,10 @@ async function onSubmit(): Promise<void> {
<span class="muted form-hint">A 股代码无需交易所后缀</span>
</el-form-item>
<el-form-item label="开始日期">
<el-date-picker v-model="form.start" type="date" value-format="YYYY-MM-DD" style="width: 220px" />
<el-date-picker v-model="form.start" type="date" value-format="YYYY-MM-DD" :disabled-date="disableFutureDate" style="width: 220px" />
</el-form-item>
<el-form-item label="结束日期">
<el-date-picker v-model="form.end" type="date" value-format="YYYY-MM-DD" style="width: 220px" />
<el-date-picker v-model="form.end" type="date" value-format="YYYY-MM-DD" :disabled-date="disableFutureDate" style="width: 220px" />
</el-form-item>
<el-form-item label="K 线周期">
<el-radio-group v-model="form.interval">
+3 -2
View File
@@ -4,6 +4,7 @@ import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getStrategies, getParams, type StrategyItem } from '@/api/strategy'
import { submitOptimize } from '@/api/backtest'
import { disableFutureDate } from '@/utils/dates'
const router = useRouter()
const strategies = ref<StrategyItem[]>([])
@@ -117,10 +118,10 @@ async function onSubmit(): Promise<void> {
<span class="muted form-hint">每行参数名,起始,结束,步长</span>
</el-form-item>
<el-form-item label="开始日期">
<el-date-picker v-model="form.start" type="date" value-format="YYYY-MM-DD" style="width: 220px" />
<el-date-picker v-model="form.start" type="date" value-format="YYYY-MM-DD" :disabled-date="disableFutureDate" style="width: 220px" />
</el-form-item>
<el-form-item label="结束日期">
<el-date-picker v-model="form.end" type="date" value-format="YYYY-MM-DD" style="width: 220px" />
<el-date-picker v-model="form.end" type="date" value-format="YYYY-MM-DD" :disabled-date="disableFutureDate" style="width: 220px" />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="submitting" @click="onSubmit">提交优化</el-button>
@@ -6,6 +6,7 @@ import type { EChartsCoreOption } from 'echarts'
import { useChart } from '@/composables/useChart'
import { darkTitle, darkTooltip, darkGrid, darkAxis } from '@/utils/echartsDark'
import { getTaskParams } from '@/api/backtest'
import { disableFutureDate } from '@/utils/dates'
import { INTERVAL_OPTIONS } from '@/constants/intervals'
import {
postPortfolioBacktest,
@@ -470,10 +471,10 @@ function fmtNum(v: number | null | undefined, digits = 2): string {
<template #header><span class="section-title">时间与资金</span></template>
<el-form :model="form" label-width="120px">
<el-form-item label="开始日期">
<el-date-picker v-model="form.start" type="date" value-format="YYYY-MM-DD" style="width: 220px" />
<el-date-picker v-model="form.start" type="date" value-format="YYYY-MM-DD" :disabled-date="disableFutureDate" style="width: 220px" />
</el-form-item>
<el-form-item label="结束日期">
<el-date-picker v-model="form.end" type="date" value-format="YYYY-MM-DD" style="width: 220px" />
<el-date-picker v-model="form.end" type="date" value-format="YYYY-MM-DD" :disabled-date="disableFutureDate" style="width: 220px" />
</el-form-item>
<el-form-item label="初始资金">
<el-input-number v-model="form.cash" :min="10000" :step="100000" :controls="false" style="width: 220px" />