feat(web): 因子工作台接线——eval API 客户端+3路由+投研组菜单/面包屑 [nas]

This commit is contained in:
2026-08-25 00:33:46 +08:00
parent f0e9860316
commit fa87135a44
3 changed files with 96 additions and 0 deletions
+86
View File
@@ -33,3 +33,89 @@ export function reportUrl(taskId: string, factor: string): string {
const auth = useAuthStore()
return `/api/v1/task/${taskId}/report/${factor}?token=${encodeURIComponent(auth.token ?? '')}`
}
// —— Factor Evaluation API ——
export interface EvalRun {
run_id: string
label: string
universe: string
symbols_count: number
factors_total: number
factors_done: number
start: string
end: string
status: string
created_at: string
}
export interface MonthlyIcPoint { month: string; ic: number }
export interface LeaderboardRow {
rank: number
factor: string
category: string
expression: string
ic_mean: number | null
icir: number | null
t_stat: number | null
win_rate: number | null
ls_annual: number | null
turnover: number | null
conclusion: string
monthly_ic: MonthlyIcPoint[]
error?: string
}
export interface LeaderboardTiles {
factors_total: number
effective: number
watch: number
top_ls_annual: number | null
top_ls_factor: string | null
}
export interface EvalDetail {
factor: string
category: string
expression: string
metrics: Record<string, unknown>
}
export interface BatchEvalSubmit {
categories: string[]
factors: string[]
symbols: string[]
start: string
end: string
label: string
}
export async function getEvalRuns(): Promise<EvalRun[]> {
const { data } = await apiClient.get<{ runs: EvalRun[] }>('/factor/eval/runs')
return data.runs
}
export async function getLeaderboard(params: {
run_id?: string
period?: string
category?: string
search?: string
sort?: string
order?: string
}): Promise<{ tiles: LeaderboardTiles; rows: LeaderboardRow[] }> {
const { data } = await apiClient.get('/factor/eval/leaderboard', { params })
return data
}
export async function getEvalDetail(factor: string, runId?: string): Promise<EvalDetail> {
const { data } = await apiClient.get<EvalDetail>('/factor/eval/detail', {
params: { factor, ...(runId ? { run_id: runId } : {}) },
})
return data
}
export async function submitBatchEval(req: BatchEvalSubmit): Promise<string> {
const { data } = await apiClient.post<{ task_id: string }>('/factor/eval/submit', req)
return data.task_id
}
+3
View File
@@ -22,6 +22,9 @@ const routes: RouteRecordRaw[] = [
{ path: 'backtest/optimize', name: 'bt-optimize', component: () => import('@/views/backtest/Optimize.vue') },
{ path: 'backtest/optimize-result/:id', name: 'bt-optimize-result', component: () => import('@/views/backtest/OptimizeResult.vue') },
{ path: 'backtest/history', name: 'bt-history', component: () => import('@/views/backtest/History.vue') },
{ path: 'factor/leaderboard', name: 'fc-leaderboard', component: () => import('@/views/factor/Leaderboard.vue') },
{ path: 'factor/leaderboard/:factor', name: 'fc-leaderboard-detail', component: () => import('@/views/factor/LeaderboardDetail.vue') },
{ path: 'factor/batch', name: 'fc-batch', component: () => import('@/views/factor/BatchEval.vue') },
{ path: 'factor/new', name: 'fc-new', component: () => import('@/views/factor/New.vue') },
{ path: 'factor/progress/:id', name: 'fc-progress', component: () => import('@/views/backtest/Progress.vue') },
{ path: 'factor/result/:id', name: 'fc-result', component: () => import('@/views/factor/Result.vue') },
+7
View File
@@ -31,6 +31,9 @@ const PAGE_TITLE: Array<{ match: RegExp; group: string; title: string }> = [
{ match: /^\/factor\/new$/, group: '投研', title: '因子分析' },
{ match: /^\/factor\/progress\//, group: '投研', title: '因子分析进度' },
{ match: /^\/factor\/result\//, group: '投研', title: '因子分析结果' },
{ match: /^\/factor\/leaderboard\/.+$/, group: '投研', title: '因子详情' },
{ match: /^\/factor\/leaderboard$/, group: '投研', title: 'IC 排行榜' },
{ match: /^\/factor\/batch$/, group: '投研', title: '批量评估' },
{ match: /^\/paper\/new$/, group: '模拟盘', title: '新建模拟盘' },
{ match: /^\/paper\/result\//, group: '模拟盘', title: '模拟盘结果' },
{ match: /^\/paper\/live\//, group: '模拟盘', title: '实走监控' },
@@ -66,6 +69,8 @@ const CMD_ITEMS: CmdItem[] = [
{ label: '组合回测', group: '回测', path: '/backtest/portfolio' },
{ label: '参数优化', group: '回测', path: '/backtest/optimize' },
{ label: '任务列表', group: '回测', path: '/backtest/history' },
{ label: 'IC 排行榜', group: '投研', path: '/factor/leaderboard' },
{ label: '批量评估', group: '投研', path: '/factor/batch' },
{ label: '因子分析', group: '投研', path: '/factor/new' },
{ label: '模拟盘列表', group: '模拟', path: '/paper' },
{ label: '双轨对账', group: '模拟', path: '/paper/reconcile' },
@@ -170,6 +175,8 @@ function onLogout(): void {
</el-sub-menu>
<el-sub-menu index="factor">
<template #title><span class="nav-label">投研</span></template>
<el-menu-item index="/factor/leaderboard">IC 排行榜</el-menu-item>
<el-menu-item index="/factor/batch">批量评估</el-menu-item>
<el-menu-item index="/factor/new">因子分析</el-menu-item>
</el-sub-menu>
<el-sub-menu index="paper">