- 4 期愿景:投研→回测→模拟→实盘(国金QMT),本期 B=投研+回测 - 对齐 vnpy client 回测模块 + 投研自有 - 技术栈 Vue3+Vite+TS+ElementPlus+ECharts+Pinia - 部署:8000 切 sanguo_api,Vue 静态挂 FastAPI,不动端口/反代 - 含后端补 5 类接口(资金曲线/每日盈亏/成交/K线/报告) - 4 切片 S0→S1→S2→S3
14 KiB
Phase 3b:投研 + 回测 Web 控制台(Vue 前端)设计
日期:2026-07-07 阶段:Phase 3b(B 期) 状态:设计待审阅 维护:Main Agent
1. 背景与目标
已交付:
- Phase 1 数据层(A 股 K 线 / SQLite 读取)
- Phase 2 因子 + 回测引擎(
sanguo_factor/sanguo_backtest,真数据跑通) - Phase 3a 研究 API(
sanguo_api:JWT / 异步任务 / WebSocket / 结果查询),本机 + 容器 pytest 通过
两个缺口:
- 没有前端——只有 API,用户无法在网页上操作。
sanguo_api未挂公网——实机查证:公网vnpy.mysanguo.top→ 容器:8000 现在跑的是旧sanguo_web(实盘交易 API,44 路由),没有回测/因子接口;Phase 3a 的sanguo_api只在容器里 pytest 跑过。
本期目标:建一个 Vue 前端控制台,对齐 vnpy 桌面 client 的回测模块功能 + 投研(因子)自有模块,并把 sanguo_api 切到公网 8000,使整条链路从 vnpy.mysanguo.top 可用。
2. 范围
完整愿景(用户确认,4 期递进):投研 → 回测 → 模拟 → 实盘(实盘最后,走国金证券 QMT / xtquant)。
本期 B(= B1)范围:
| 类别 | 内容 |
|---|---|
| ✅ 投研 | 因子分析(多标的 / 多因子 / 日期)→ IC 表 + tears 报告 |
| ✅ 回测 | CTA 策略回测(对齐 vnpy client 回测模块:统计全表 / 资金曲线 / 每日盈亏 / 成交记录 / K线+买卖点)+ 参数优化 |
| ✅ 前端 | Vue 3 SPA |
| ✅ 后端补 | 5 类新接口 + 现有接口扩展 |
| ✅ 部署 | 切 sanguo_api 到 8000,Vue 静态挂 FastAPI |
不在本期(out of scope):
- ❌ 模拟盘(C 期,后端模拟引擎尚未建)
- ❌ 实盘交易(D 期,国金 QMT;旧
sanguo_web交易路由本期下线,D 期合并回来) - 导航预留 4 入口,模拟/实盘灰显"敬请期待",避免日后重写布局。
3. 整体架构
浏览器 (Vue 3 SPA)
↕ HTTPS vnpy.mysanguo.top ← 外网链路不动(frpc/socat/Caddy 不碰)
FastAPI sanguo_api (容器:8000,从 sanguo_web 切过来)
├─ / → Vue 静态文件 (StaticFiles,SPA history fallback)
├─ /api/v1/* → 研究 API(auth / backtest / factor / task / ws)
└─ 调后端引擎 → sanguo_backtest / sanguo_factor / sanguo_data
↕
SQLite + A 股 K 线 (NAS /volume1/stock)
4. 前端技术栈
| 层 | 选型 | 备注 |
|---|---|---|
| 框架 | Vue 3 + <script setup> + Composition API |
用户指定 Vue |
| 语言 | TypeScript | 控制台体量需要,利维护 |
| 构建 | Vite | 快、标准 |
| UI 库 | Element Plus | 中文量化圈最常用,表格/表单/弹窗齐全 |
| 图表 | ECharts | K线 candlestick + markPoint(买卖点)/ 折线(资金曲线)/ 柱状(每日盈亏)/ 热力图(优化) |
| 状态 | Pinia | Vue 3 标准 |
| 路由 | Vue Router | 标准 |
| HTTP | Axios + JWT 拦截器 | 自动附 Authorization,401 回登录 |
| 实时 | 原生 WebSocket | 对接已有 /api/v1/ws/task/{id} |
前端代码目录:新建 frontend/(仓库根),与 Python 包并列。npm run build 产物输出到 FastAPI 可挂载的静态目录。
5. 部署方案(守住红线)
红线(用户多次强调):
- 不改容器端口(8000 不变)
- 不动
vnpy.mysanguo.top反向代理 / 转发 - 不碰 frpc / socat / Caddy
本期改动(只动 NAS 容器内部):
- 容器 uvicorn 目标:
sanguo_web.api:app→sanguo_api.app:create_app(用--factory,传 db_path / file_dir / auth_config / max_workers)- 入口脚本:
docker/entrypoint.sh:283(改 uvicorn 目标)
- 入口脚本:
- Vue 打包静态 → FastAPI
StaticFiles(directory=..., html=True)挂在/,配 SPA history fallback(catch-all 回index.html) - 开发期:本地 Vite dev server(5173)+
vite.config.tsproxy/api、/ws→ 容器/本地 FastAPI
部署流程(沿用项目约定):本机改代码 → rsync 到 NAS 安装目录 → docker restart sanguo_vnpy_v2。
已知问题:本 session rsync/scp 到 NAS 不稳(status 43 / Connection closed)。临时用
ssh sanguo-nas "cat > /path" < local重定向;排期修 sftp 子系统。
6. 页面设计
6.1 页面地图
登录页 /login
└ 主控制台(左侧栏 4 入口)
├ 回测 ✅ (S1 / S3)
│ ├ 新建回测 /backtest/new
│ ├ 任务进度 /backtest/task/:id (WS 实时阶段)
│ ├ 结果页 /backtest/result/:id (统计/曲线/盈亏/成交/K线买卖点)
│ ├ 参数优化 /backtest/optimize (S3)
│ └ 历史任务 /backtest/history (S3)
├ 投研 ✅ (S2)
│ ├ 新建因子分析 /factor/new
│ └ 结果页 /factor/result/:id (IC 表 / tears 报告)
├ 模拟 ⬜ 敬请期待(C 期)
└ 实盘 ⬜ 敬请期待(D 期 · 国金 QMT)
6.2 页面详情
登录页:用户名 + 密码 → POST /api/v1/auth/login → 存 JWT(localStorage)→ 跳主控制台。
主控制台 shell:顶栏(系统名 / 用户 / 登出)+ 左侧栏 4 入口(回测/投研点亮,模拟/实盘灰显)+ <router-view>。
回测-新建:
- 策略下拉(
GET /strategy/list)→ 选中后按GET /strategy/{name}/params渲染动态参数表单 - 标的输入(如 600000)+ 日期区间 +(S3)费率/滑点/资金
- 提交 →
POST /api/v1/backtest/cta→ 拿 task_id → 跳进度页
回测-进度:GET /task/{id} + WS /ws/task/{id},显示状态(pending/running/done/failed)+ 中文阶段("排队中/回测中/完成")。done → 跳结果页。
回测-结果(对齐 vnpy client 回测模块):
- 统计全表(sharpe / total_return / max_drawdown / win_rate / …,来自
GET /task/{id}/result) - 资金曲线(
GET /task/{id}/equity-curve→ ECharts 折线) - 每日盈亏(
GET /task/{id}/daily-pnl→ ECharts 柱状) - 成交记录表(
GET /task/{id}/trades→ Element Table) - K线 + 买卖点(
GET /kline?symbol&start&end+ 成交点 → ECharts candlestick + markPoint)
回测-优化(S3):策略 + 参数网格 → POST /api/v1/backtest/optimize → 结果表 + 热力图(GET /task/{id}/optimization-results)。
回测-历史(S3):GET /task?type=cta → 任务列表,可点回看结果。
投研-新建:因子下拉(GET /factor/list,如 ma5/ma10/ma20/vol_ma5)+ 多标的(多选,如 600000/000001/300750)+ 日期 → POST /api/v1/factor/analyze → 进度。
投研-结果:
- IC 表(
GET /task/{id}/ic-summary:各周期 mean/std/icir/t_stat/count) - tears 报告内嵌(
GET /task/{id}/report/{factor}返回 HTML → iframe)
7. 核心流程
7.1 回测流程
选策略(DoubleMaStrategy)→ 填参数(fast_window/slow_window)→ 选标的(600000)+ 日期 → 提交 → 看进度"回测中" → 完成 → 结果页:统计全表 / 资金曲线 / 每日盈亏 / 成交表 / K线带买卖箭头。体感对齐 vnpy client 回测模块。
7.2 因子分析流程
选因子(ma5)+ 多标的(600000/000001/300750,alphalens 横截面需 ≥2)+ 日期 → 提交 → 进度 → 结果页:IC 表(1D/5D/10D mean/icir/t_stat)+ tears 报告。
8. 后端 API
8.1 现有(Phase 3a,复用)
| 方法 | 路径 | 用途 |
|---|---|---|
| POST | /api/v1/auth/login |
登录取 JWT |
| POST | /api/v1/backtest/cta |
提交 CTA 回测 → task_id |
| POST | /api/v1/backtest/optimize |
提交参数优化 → task_id |
| POST | /api/v1/factor/analyze |
提交因子分析 → task_id |
| GET | /api/v1/task/{id} |
任务状态 + 阶段 |
| GET | /api/v1/task/{id}/result |
统计 statistics |
| WS | /api/v1/ws/task/{id}?token= |
实时阶段推送 |
8.2 本期新增(按切片)
| 切片 | 方法 | 路径 | 返回 | 说明 |
|---|---|---|---|---|
| S1 | GET | /api/v1/strategy/list |
[{name, class_name}] |
枚举 vnpy_ctastrategy 可用策略 |
| S1 | GET | /api/v1/strategy/{name}/params |
{parameters:[...], defaults:{}} |
读策略类 .parameters 渲染表单 |
| S1 | GET | /api/v1/task/{id}/equity-curve |
[{date, balance}] |
暴露 BacktestResult.equity_curve |
| S1 | GET | /api/v1/task/{id}/daily-pnl |
[{date, pnl}] |
每日盈亏 |
| S1 | GET | /api/v1/task/{id}/trades |
[{datetime, direction, offset, price, volume}] |
cta_engine 需实现成交记录(现为 None) |
| S1 | GET | /api/v1/kline?symbol&start&end |
[{datetime, open, high, low, close, volume}] |
历史 K 线(读 A 股 DB;评估能否复用旧 sanguo_web /market/kline) |
| S2 | GET | /api/v1/factor/list |
[{name, desc}] |
枚举已注册因子(ma5/ma10/ma20/vol_ma5) |
| S2 | GET | /api/v1/task/{id}/ic-summary |
{factor:{periodD:{mean,std,icir,t_stat,count}}} |
暴露 FactorReport.ic_summary |
| S2 | GET | /api/v1/task/{id}/report/{factor} |
HTML | tears 报告服务(StaticFiles 或 FileResponse) |
| S3 | 扩展 | POST /api/v1/backtest/cta |
— | schema 加 rate/slippage/capital 字段;cta_engine 接收 |
| S3 | GET | /api/v1/task/{id}/optimization-results |
[{params, statistics}] |
优化结果结构化 |
| S3 | GET | /api/v1/task?type=&status= |
[task 摘要] |
任务历史列表 |
9. 数据契约
9.1 BacktestResult(现有,sanguo_backtest/result_store.py)
task_id, type, status, strategy, symbol, params, start, end, statistics, equity_curve, trades, error_msg
9.2 新增返回结构
- equity-curve:
[{date: "YYYY-MM-DD", balance: number}] - daily-pnl:
[{date, pnl: number}] - trades:
[{datetime, direction: "多/空", offset: "开/平", price, volume, commission, ...}](对齐 vnpy TradeData) - kline:
[{datetime, open, high, low, close, volume}] - ic-summary:
{factor: {"1D"|"5D"|"10D": {mean, std, icir, t_stat, count}}} - optimization-results:
[{params: {...}, statistics: {...}}]
所有接口返回 JSON 安全值(Timestamp→str,已在 cta_engine statistics 处理过同样问题)。
10. 切片交付计划
每片独立可演示、可验收。S1 最重(vnpy client 对齐主战场)。
S0 脚手架
- 前端:Vite + Vue3 + TS + Element Plus + ECharts + Pinia + Router + Axios 项目骨架;登录页 + JWT 拦截器;4 入口侧栏 shell(回测/投研点亮,模拟/实盘灰显);路由 + history fallback
- 后端:容器 uvicorn 切
sanguo_api;FastAPI 挂 SPA 静态 - 验收:从 vnpy.mysanguo.top 能登录、看到空壳控制台
S1 回测核心(对齐 vnpy client 回测)
- 前端:新建回测 / 进度 / 结果页(统计全表 + 资金曲线 + 每日盈亏 + 成交表 + K线买卖点)
- 后端:
strategy/list、strategy/{name}/params、task/{id}/equity-curve、/daily-pnl、/trades、/kline;cta_engine 实现成交记录 - 验收:跑 DoubleMaStrategy on 600000,结果页与 vnpy client 回测模块一致
S2 投研核心
- 前端:新建因子分析 / 结果页(IC 表 + tears 报告内嵌)
- 后端:
factor/list、task/{id}/ic-summary、task/{id}/report/{factor} - 验收:跑 ma5(多标的),看 IC 表 + tears 报告
S3 优化 + 收尾
- 前端:参数优化(热力图)/ 历史任务 / 回测费率·滑点·资金可调
- 后端:
backtest/cta加参数;optimization-results;GET /task列表 - 验收:跑优化看热力图、查历史、费率可调
11. 非功能
- 安全:JWT(已有);SPA 用 localStorage 存 token,Axios 拦截器附
Authorization: Bearer;401 → 清 token 回登录;HTTPS 由外网链路保证 - 错误处理:API 错误统一 Element Plus
ElMessage;任务 failed 展示error_msg - 测试:
- 前端:Vitest + Vue Test Utils(工具函数 / 关键组件)
- 后端:pytest(新接口单测 + 复用现有容器冒烟模式)
- 容器:
scripts/smoke_phase3b.py(端到端:登录 → 提交回测 → WS 进度 → 结果页接口齐)
- 代码风格:前端遵循 ECC coding-style(小文件、不可变、早返回、命名);后端沿用现有 sanguo_* 风格
12. 风险与约束
| 风险 / 约束 | 处理 |
|---|---|
| 切 8000 到 sanguo_api 会下线旧交易路由 | 已确认(A 方案);D 期合并回来 |
两套 auth 都占 /api/v1/auth/login |
本期只用 sanguo_api JWT;sanguo_web 下线,无冲突 |
| rsync/scp 到 NAS 不稳 | ssh-exec 重定向;排期修 sftp 子系统 |
| 容器 Python 3.10 vs 本机 3.14 | 前端 Node 工具链独立;后端接口在容器测(沿用 Phase 3a 模式) |
| vnpy 零修改原则 | 不改 vnpy_v4.4.0/;策略/参数从类属性读 |
| NAS CPU 弱(J4125 无 AVX2) | 已有 POLARS_SKIP_CPU_CHECK;前端构建在 Mac,产物部署 |
13. 未来(C / D 期,预留)
- C 模拟盘:新建模拟引擎(forward 纸面交易)+ 任务类型
paper;前端点亮"模拟"入口 - D 实盘:合并
sanguo_web交易路由(需统一 auth,解决/api/v1/auth/login冲突)+ 接国金 QMT(xtquant);前端点亮"实盘"入口 - 导航骨架已预留,C/D 无需重写布局
14. 开放项(实现阶段确认)
/kline是否复用旧sanguo_web的/api/v1/market/kline(依赖行情网关 vs 历史 DB)—— S1 评估- token 存 localStorage(简便)vs httpOnly cookie(更安全)—— S0 默认 localStorage,可调
- 策略参数表单的复杂参数类型(范围/枚举)支持深度 —— S1 按需
参考文档
- Phase 3a 设计:
docs/superpowers/specs/2026-07-06-phase3a-web-api-design.md - 部署实况:
docs/deployment/nas-deploy-plan.md - 旧 Web 部署设计:
docs/design/deployment/docker-web-deployment.md