refactor(paper): 影子升级为第三种运行模式(回放/实走/影子,用户拍板CTA和组合都可走影子): 模式卡三选一替代组合卡内撮合引擎单选; engine由mode推导(shadow→shadow否则eod_replay,CTA/组合统一); 日终20:30 job只遍历mode=live天然隔离影子账户; 列表徽标mode=shadow亮'影子'+组合live标'日终'; 2新测试 [vps]
This commit is contained in:
@@ -44,7 +44,7 @@ const stats = computed(() => ({
|
||||
failed: accounts.value.filter((a) => a.status === 'failed').length,
|
||||
}))
|
||||
|
||||
const modeLabel: Record<string, string> = { replay: '回放', live: '实走' }
|
||||
const modeLabel: Record<string, string> = { replay: '回放', live: '实走', shadow: '影子' }
|
||||
const statusLabel: Record<string, string> = { running: '运行中', done: '完成', failed: '失败', created: '已创建', pending: '排队', stopped: '已停止' }
|
||||
|
||||
function pct(v: number | null | undefined): string {
|
||||
@@ -189,10 +189,8 @@ async function saveEdit(): Promise<void> {
|
||||
</el-table-column>
|
||||
<el-table-column label="模式" width="80">
|
||||
<template #default="{ row }">
|
||||
<span class="chip chip-paper">{{ modeLabel[row.mode] || row.mode }}</span>
|
||||
<span v-if="row.strategy_type === 'portfolio'" class="chip chip-shadow" title="影子柜台=盘中实时本地撮合 / 日终回放=每晚全量重放">
|
||||
{{ row.engine === 'shadow' ? '影子' : '日终' }}
|
||||
</span>
|
||||
<span class="chip chip-paper" :class="{ 'chip-shadow': row.mode === 'shadow' }">{{ modeLabel[row.mode] || row.mode }}</span>
|
||||
<span v-if="row.strategy_type === 'portfolio' && row.mode === 'live'" class="chip chip-shadow" title="日终回放=每晚 20:30 全量重放结算">日终</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="频率" width="70">
|
||||
|
||||
@@ -84,7 +84,8 @@ watch(
|
||||
|
||||
const modes = [
|
||||
{ value: 'replay', label: '回放', desc: '历史重放,立即出结果' },
|
||||
{ value: 'live', label: '实走', desc: '每日定时 step,长期跟踪' },
|
||||
{ value: 'live', label: '实走', desc: '每日 20:30 定时结算,长期跟踪' },
|
||||
{ value: 'shadow', label: '影子', desc: 'VPS 影子柜台盘中实时本地撮合' },
|
||||
]
|
||||
const sessions = [
|
||||
{ value: 'next_open', label: '次日开盘', desc: '收盘型信号,T+1 开盘撮合' },
|
||||
@@ -115,19 +116,17 @@ onMounted(async () => {
|
||||
|
||||
const isPortfolio = computed(() => strategyType.value === 'portfolio')
|
||||
const portfolioStrategy = ref('all_weather')
|
||||
// 撮合引擎:日终回放(NAS 每晚 20:30) / 影子柜台(VPS 盘中实时本地撮合)
|
||||
const engine = ref<'eod_replay' | 'shadow'>('eod_replay')
|
||||
|
||||
function setMode(m: string): void {
|
||||
// 组合类型锁定实走:回放卡片不可选(历史回放走「组合回测」页)
|
||||
// 组合类型不支持回放(历史回放走「组合回测」页)
|
||||
if (isPortfolio.value && m === 'replay') return
|
||||
form.value.mode = m
|
||||
}
|
||||
|
||||
// 组合类型锁定实走(历史回放走「组合回测」页)
|
||||
// 组合类型默认实走(历史回放走「组合回测」页)
|
||||
watch(strategyType, (t) => {
|
||||
if (t === 'portfolio') {
|
||||
form.value.mode = 'live'
|
||||
if (form.value.mode === 'replay') form.value.mode = 'live'
|
||||
if (!portfolioStrategy.value && portfolioOptions.value.length) {
|
||||
portfolioStrategy.value = portfolioOptions.value[0]
|
||||
}
|
||||
@@ -140,7 +139,6 @@ async function onSubmit(): Promise<void> {
|
||||
const payload: PaperCreate = { ...form.value }
|
||||
if (strategyType.value === 'portfolio') {
|
||||
payload.strategy_type = 'portfolio'
|
||||
payload.mode = 'live'
|
||||
payload.symbols = [poolForm.pool]
|
||||
payload.strategies = [{
|
||||
name: portfolioStrategy.value,
|
||||
@@ -151,13 +149,16 @@ async function onSubmit(): Promise<void> {
|
||||
payload.pool = poolForm.pool
|
||||
payload.max_pool = Number(poolForm.max_pool)
|
||||
payload.benchmark = poolForm.benchmark
|
||||
payload.engine = engine.value
|
||||
}
|
||||
// 影子模式:engine=shadow(VPS 柜台盘中实时撮合);其余 eod_replay(回放/日终)
|
||||
payload.engine = payload.mode === 'shadow' ? 'shadow' : 'eod_replay'
|
||||
const aid = await createPaper(payload)
|
||||
ElMessage.success(strategyType.value === 'portfolio' && engine.value === 'shadow'
|
||||
ElMessage.success(payload.mode === 'shadow'
|
||||
? `已创建影子柜台模拟盘 #${aid}(VPS 柜台运行期间盘中实时结算)`
|
||||
: `已创建模拟盘 #${aid}(今晚 20:30 起每日结算)`)
|
||||
router.push(payload.mode === 'live' ? `/paper/live/${aid}` : `/paper/result/${aid}`)
|
||||
: payload.mode === 'live'
|
||||
? `已创建模拟盘 #${aid}(今晚 20:30 起每日结算)`
|
||||
: `已创建回放模拟盘 #${aid}`)
|
||||
router.push(payload.mode === 'replay' ? `/paper/result/${aid}` : `/paper/live/${aid}`)
|
||||
} catch (e: unknown) {
|
||||
ElMessage.error(e instanceof Error ? e.message : '创建失败')
|
||||
} finally {
|
||||
@@ -250,17 +251,6 @@ function onSymbols(v: string): void {
|
||||
<el-option v-for="b in BENCH_OPTIONS" :key="b.value" :label="b.label" :value="b.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="撮合引擎">
|
||||
<el-radio-group v-model="engine">
|
||||
<el-radio-button value="eod_replay">日终回放</el-radio-button>
|
||||
<el-radio-button value="shadow">影子柜台</el-radio-button>
|
||||
</el-radio-group>
|
||||
<span class="muted form-hint">
|
||||
{{ engine === 'shadow'
|
||||
? 'VPS 盘中实时行情本地撮合(需 VPS 影子柜台进程运行中)'
|
||||
: '每晚 20:30 全量重放结算(NAS)' }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form v-else :model="form" label-width="120px">
|
||||
<el-form-item label="标的(逗号分隔)">
|
||||
|
||||
Reference in New Issue
Block a user