diff --git a/frontend/src/views/backtest/PortfolioBacktest.vue b/frontend/src/views/backtest/PortfolioBacktest.vue index afa5d8a..71bb8bd 100644 --- a/frontend/src/views/backtest/PortfolioBacktest.vue +++ b/frontend/src/views/backtest/PortfolioBacktest.vue @@ -55,7 +55,7 @@ const dr = loadDateRange() // §12.6 选档案(跳转带入或页面下拉),提交带 instance_id 回写四格 const selectedInstanceId = ref(null) const form = reactive({ - pool: 'hs300_subset', + pool: 'all', strategy: 'all_weather', max_pool: 30, start: dr.start, @@ -81,7 +81,7 @@ watch( const poolOptions = [ { label: 'HS300 子集(小范围验证)', value: 'hs300_subset' }, - { label: '全市场(慢,非 MVP)', value: 'all' }, + { label: '全市场', value: 'all' }, ] const strategyOptions = [ { label: '全天候轮动', value: 'all_weather' }, diff --git a/frontend/src/views/live/List.vue b/frontend/src/views/live/List.vue index 6679869..d73cc6a 100644 --- a/frontend/src/views/live/List.vue +++ b/frontend/src/views/live/List.vue @@ -2,6 +2,8 @@ import { ref, reactive, computed, onMounted, onUnmounted } from 'vue' import { useRouter, useRoute } from 'vue-router' import CodeSnapshotDrawer from '@/views/strategy/CodeSnapshotDrawer.vue' +import { poolLabel } from '@/constants/strategy' +import { getInstances } from '@/api/strategy' import { ElMessage, ElMessageBox } from 'element-plus' import { listLives, startLive, stopLive, deleteLive, updateLive, @@ -73,6 +75,21 @@ function num(v: number | null | undefined): string { return Math.round(v).toLocaleString('zh-CN') } +// #94 实例名映射(instance_id → 实例名,对齐模拟盘列表口径;后端 list_lives 不填 instance 字段) +const instanceNames = ref>({}) +onMounted(async () => { + try { + const ins = await getInstances() + instanceNames.value = Object.fromEntries(ins.map((i) => [i.id, i.name])) + } catch { + /* 映射失败退化为 实例 #id */ + } +}) +function instanceNameOf(instanceId: number | null | undefined): string { + if (!instanceId) return '—' + return instanceNames.value[instanceId] || `实例 #${instanceId}` +} + function goMonitor(a: LiveAccount): void { router.push(`/live/monitor/${a.id}`) } @@ -253,7 +270,7 @@ async function onStop(a: LiveAccount): Promise { - + - - + + diff --git a/frontend/src/views/live/New.vue b/frontend/src/views/live/New.vue index 5081a2f..a8d10dd 100644 --- a/frontend/src/views/live/New.vue +++ b/frontend/src/views/live/New.vue @@ -19,10 +19,10 @@ const isPortfolio = computed(() => strategyType.value === 'portfolio') const portfolioOptions = ref([]) const portfolioStrategy = ref('all_weather') -const poolForm = ref({ pool: 'hs300_subset', max_pool: 30, benchmark: '000300.XSHG' }) +const poolForm = ref({ pool: 'all', max_pool: 30, benchmark: '000300.XSHG' }) const POOL_OPTIONS = [ { label: 'HS300 子集(小范围验证)', value: 'hs300_subset' }, - { label: '全市场(慢,非 MVP)', value: 'all' }, + { label: '全市场', value: 'all' }, ] const BENCH_OPTIONS = [ { label: '沪深300', value: '000300.XSHG' }, diff --git a/frontend/src/views/paper/New.vue b/frontend/src/views/paper/New.vue index 435ed80..bbe5088 100644 --- a/frontend/src/views/paper/New.vue +++ b/frontend/src/views/paper/New.vue @@ -27,10 +27,10 @@ const instancesOfCta = computed(() => { const file = classToFile.value[form.value.strategies[0]?.name] return file ? instanceOptions.value.filter((i) => i.code_file === file) : instanceOptions.value }) -const poolForm = reactive({ pool: 'hs300_subset', max_pool: 30, benchmark: '000300.XSHG' }) +const poolForm = reactive({ pool: 'all', max_pool: 30, benchmark: '000300.XSHG' }) const POOL_OPTIONS = [ { label: 'HS300 子集(小范围验证)', value: 'hs300_subset' }, - { label: '全市场(慢,非 MVP)', value: 'all' }, + { label: '全市场', value: 'all' }, ] const BENCH_OPTIONS = [ { label: '沪深300', value: '000300.XSHG' }, diff --git a/frontend/src/views/strategy/List.vue b/frontend/src/views/strategy/List.vue index f4c5520..408fd06 100644 --- a/frontend/src/views/strategy/List.vue +++ b/frontend/src/views/strategy/List.vue @@ -115,23 +115,6 @@ const lampOf = (s: string): string => { } const pct = (v: number | null | undefined): string => (v == null ? '—' : (v * 100).toFixed(2) + '%') const retClass = (v: number | null | undefined): string => (v == null ? '' : v >= 0 ? 'up' : 'down') -// #75 收益数值与标签同源:运行类 ret 优先(含其类型),否则回测/回放 run_returns -interface RetInfo { v: number | null; label: string } -function retInfoOf(i: Instance): RetInfo { - const runs = (i.running_accounts || []).filter((a) => a.ret != null) - if (runs.length) { - const last = runs[runs.length - 1] - const label = last.kind === 'live' ? '实盘 · 最新' : last.kind === 'shadow' ? '影子 · 最新' : '模拟实走 · 最新' - return { v: last.ret, label } - } - const rr = (i as Instance & { run_returns?: Record }).run_returns || {} - if (rr.backtest != null) return { v: rr.backtest, label: '回测 · 最新' } - if (rr.replay != null) return { v: rr.replay, label: '回放 · 最新' } - return { v: null, label: '未运行' } -} -function latestRet(i: Instance): number | null { - return retInfoOf(i).v -} const paramSummary = (p: Record): string => Object.entries(p).map(([k, v]) => `${k}=${v}`).join(' · ') @@ -327,8 +310,7 @@ const runningRows = computed(() => #{{ i.id }} · {{ i.interval }} · 更新 {{ i.updated_at }}
{{ paramSummary(i.params) }}
- -
{{ pct(latestRet(i)) }}{{ retInfoOf(i).label }}
+
diff --git a/sanguo_api/routes_live.py b/sanguo_api/routes_live.py index 1567d58..5042cfb 100644 --- a/sanguo_api/routes_live.py +++ b/sanguo_api/routes_live.py @@ -138,7 +138,7 @@ def create_live(req: LiveCreateRequest): # 组合实盘:vt_symbol 占位为池名;setting 存组合参数(supervisor 转发 env) if not payload.get("strategy_class"): raise HTTPException(400, "组合实盘需选择策略(strategy_class)") - payload.setdefault("pool", "hs300_subset") + payload.setdefault("pool", "all") payload.setdefault("max_pool", 30) payload.setdefault("benchmark", "000300.XSHG") payload["vt_symbol"] = payload["pool"] diff --git a/sanguo_api/routes_paper.py b/sanguo_api/routes_paper.py index ab2393a..cca218e 100644 --- a/sanguo_api/routes_paper.py +++ b/sanguo_api/routes_paper.py @@ -61,7 +61,7 @@ class PaperCreateRequest(BaseModel): strategy_type: str = "cta" # 撮合引擎(影子柜台 P1):eod_replay=日终回放(NAS 20:30) / shadow=影子柜台(VPS 盘中实时) engine: str = "eod_replay" - pool: str = "hs300_subset" + pool: str = "all" max_pool: int = 30 benchmark: str = "000300.XSHG" # §12.6 实例做实:账户绑档案;空=发起即建档(自动创建实例再发起) diff --git a/sanguo_api/routes_portfolio.py b/sanguo_api/routes_portfolio.py index cbd2765..3c43a1a 100644 --- a/sanguo_api/routes_portfolio.py +++ b/sanguo_api/routes_portfolio.py @@ -29,7 +29,7 @@ async def verify_token(authorization: str | None = Header(None)): class PortfolioBacktestRequest(BaseModel): - pool: str = Field(default="hs300_subset", description="标的池(占位,MVP 用默认)") + pool: str = Field(default="all", description="标的池(all=全市场)") start_date: str = Field(default="2024-01-01", description="YYYY-MM-DD") end_date: str = Field(default="2024-02-29", description="YYYY-MM-DD") initial_cash: float = Field(default=1_000_000.0, description="初始资金(元)") diff --git a/sanguo_orchestrator/runner.py b/sanguo_orchestrator/runner.py index 49f5d14..a9a7351 100644 --- a/sanguo_orchestrator/runner.py +++ b/sanguo_orchestrator/runner.py @@ -140,7 +140,7 @@ class Orchestrator: async def submit_portfolio(self, start: str, end: str, cash: float, benchmark: str, strategy: str = "all_weather", max_pool: int = 30, - pool: str = "hs300_subset", + pool: str = "all", provider_config=None, commission_rate: float = 0.0003, stamp_duty_rate: float = 0.001,