[sanguo_vnpy_v2] 实盘模拟(miniQMT跑策略)前后端实现 #5

Open
opened 2026-07-17 10:49:05 +00:00 by claude_dev · 8 comments
Member

背景

当前模拟盘用 parquet 收盘数据慢速回放(≈回测)。要做"实盘模拟":用 miniQMT 测试账户的真实行情驱动 vnpy 策略,真实下单跑 15min 策略。已确认:miniQMT 直连通、vnpy_qmt 网关代码全、策略是标准 CtaTemplate。

范围

前后端都要。风控不做(加仓限额/止损/熔断等跳过)。

架构

新建 sanguo_live/ 独立模块(不动现有模拟盘 sanguo_trader)。MainEngine+QmtGateway+CtaEngine+subscribe+BarGenerator(15min) → 策略 on_bar → 真实下单测试账户(66639661)。

工作清单

  • #3 后端:引擎核心(LiveTradingEngine+AShareCtaTemplate+入口) + 连通性6步
  • #4 后端:API(routes_live) + 持久化 + 配置
  • #5 前端:实盘模拟UI(New/List/Monitor) + router + api
  • #6 集成验收:前后端联调 + VPS连通性 + 交付

连通性6步(验收标准)

  1. connect 测试账户成功
  2. 收实时 tick
  3. 15min bar 合成
  4. 策略 on_bar 触发
  5. 真实下单测试账户成交
  6. 成交/持仓回读一致

状态表

任务 负责 状态
#3 引擎核心 Execute 进行中
#4 API+持久化 Execute blocked
#5 前端UI Execute blocked
#6 集成验收 Main blocked

完成标记约定

  • Execute 完成:@main-agent ✅ EXECUTE_DONE
  • Review 通过:@main-agent ✅ REVIEW_DONE verdict=approved
  • 验收通过:@main-agent ✅ VERIFICATION_PASSED
## 背景 当前模拟盘用 parquet 收盘数据慢速回放(≈回测)。要做"实盘模拟":用 miniQMT 测试账户的真实行情驱动 vnpy 策略,真实下单跑 15min 策略。已确认:miniQMT 直连通、vnpy_qmt 网关代码全、策略是标准 CtaTemplate。 ## 范围 前后端都要。**风控不做**(加仓限额/止损/熔断等跳过)。 ## 架构 新建 sanguo_live/ 独立模块(不动现有模拟盘 sanguo_trader)。`MainEngine+QmtGateway+CtaEngine+subscribe+BarGenerator(15min)` → 策略 on_bar → 真实下单测试账户(66639661)。 ## 工作清单 - [ ] #3 后端:引擎核心(LiveTradingEngine+AShareCtaTemplate+入口) + 连通性6步 - [ ] #4 后端:API(routes_live) + 持久化 + 配置 - [ ] #5 前端:实盘模拟UI(New/List/Monitor) + router + api - [ ] #6 集成验收:前后端联调 + VPS连通性 + 交付 ## 连通性6步(验收标准) 1. connect 测试账户成功 2. 收实时 tick 3. 15min bar 合成 4. 策略 on_bar 触发 5. 真实下单测试账户成交 6. 成交/持仓回读一致 ## 状态表 | 任务 | 负责 | 状态 | |---|---|---| | #3 引擎核心 | Execute | 进行中 | | #4 API+持久化 | Execute | blocked | | #5 前端UI | Execute | blocked | | #6 集成验收 | Main | blocked | ## 完成标记约定 - Execute 完成:`@main-agent ✅ EXECUTE_DONE` - Review 通过:`@main-agent ✅ REVIEW_DONE verdict=approved` - 验收通过:`@main-agent ✅ VERIFICATION_PASSED`
Author
Member

@main-agent EXECUTE_DONE

任务 #3 实盘模拟后端核心引擎 — 完成

新建文件清单(8 个文件,全部 < 300 行)

文件 行数 用途
sanguo_live/__init__.py 14 包入口
sanguo_live/__main__.py 8 入口 python -m sanguo_live [config]
sanguo_live/base_template.py 117 AShareCtaTemplate:定寸 buy/cover/sell ×= size(默认100) + 禁做空 short 返回 []
sanguo_live/strategies.py 118 AShareDoubleMaStrategy:15min 双均线(BarGenerator window=15),死叉只平多不开空
sanguo_live/engine.py 154 LiveTradingEngine:EventEngine + MainEngine + QmtGateway + CtaStrategyApp 封装
sanguo_live/runner.py 168 run(): connect → add → subscribe → init_all → start_all → 常驻,SIGINT/SIGTERM 优雅停
config/live.yaml 35 配置(账号 66639661 / 标的 600000.SSE / 15min / size=100)
tests/test_live_engine.py 252 单测(层 1 纯Py 7 项 + 层 2 依赖vnpy 8 项)

关键设计决策

  • 策略不直接复用 vnpy_ctastrategy.DoubleMaStrategy:其 BarGenerator(self.on_bar) 无 window 参数(仅 1min),且 parameters=["fast_window","slow_window"] 不暴露周期,无法通过 setting 切 15min。改写 AShareDoubleMaStrategyBarGenerator(self._on_1min_bar, window=15, on_window_bar=self.on_bar),on_bar 直接收 15min bar。
  • A股不可做空:基类 short() 返回 [] 拦截;AShareDoubleMaStrategy.on_bar 的死叉分支删除原 DoubleMa 的 pos==0 → shortpos<0 → cover+buy 分支,只保留 pos>0 → sell
  • 定寸:vnpy_qmt send_order 按"股数"直传 xtquant(不自动 ×size),策略 buy(1) 会下 1 股被拒。AShareCtaTemplate 在 buy/cover/sell 内部 ×= self.size(默认100)。
  • 模块 import 容错:本机 dev 视图没装 vnpy_ctastrategy/vnpy_qmt,所有 vnpy import try/except + fallback,模块加载不崩,运行时才校验。

单测结果

平台 结果 说明
Mac dev (venv Python 3.14) 7 passed, 8 skipped 层 1 纯Py 全 pass;层 2 依赖 vnpy_ctastrategy 自动 skip(Mac 没装),exit 0
VPS Windows (C:\Python310, vnpy 4.4.0 + vnpy_ctastrategy 1.4.1 + vnpy_qmt 0.3.3 vendor) 15 passed 全部 pass:定寸 (buy 1→100 / size=200 → buy 2 = 400) / 禁做空 / LiveTradingEngine 组装 (QMT gateway + CTA app 注册成功)
回归检查 test_strategy_registry.py(4) + test_cta_adapter.py(5) 9 passed,无回归

VPS 环境核实

  • vnpy_ctastrategy 1.4.1 装在 C:\Python310\lib\site-packages\(pip 安装)
  • vnpy 4.4.0 同上
  • vnpy_qmt 0.3.3 vendor 在 C:\sanguo_vnpy_v2\vnpy_qmt_v0.3.3\(非 pip,通过 sys.path.insert 引用,与 run_web.py 一致)
  • VPS 跑测试时 PYTHONPATH 设为 vnpy_v4.4.0;vnpy_qmt_v0.3.3;sanguo_live_test(生产由 run_web 风格的 bootstrap 注入,已在 runner.py 文档说明)

连通性状态

  • 代码层验证:LiveTradingEngine 装配(MainEngine + QmtGateway + CtaStrategyApp 三件一套)、策略实例化、定寸/禁做空逻辑全部 pass
  • 实盘下单链路:待盘中验证(非交易日/非盘中,且需 miniQMT 在线。按要求不强行跑。下次盘中跑 python -m sanguo_live 即可端到端验证 connect → subscribe tick → 15min bar → 策略 → 真实下单)

约束遵循

  • 未动 sanguo_trader / sanguo_api 任何代码
  • 风控未做(只做定寸 + 禁做空这两条必要的)
  • Type annotations + PEP8 + logging(不 print)+ 多小文件(最大 168 行)
  • vnpy import 全部容错(本机 import 不崩)
  • 未自己 git commit / 建 PR(等 Main Agent Review+合并)
@main-agent ✅ EXECUTE_DONE ## 任务 #3 实盘模拟后端核心引擎 — 完成 ### 新建文件清单(8 个文件,全部 < 300 行) | 文件 | 行数 | 用途 | |------|------|------| | `sanguo_live/__init__.py` | 14 | 包入口 | | `sanguo_live/__main__.py` | 8 | 入口 `python -m sanguo_live [config]` | | `sanguo_live/base_template.py` | 117 | **AShareCtaTemplate**:定寸 buy/cover/sell ×= size(默认100) + 禁做空 short 返回 [] | | `sanguo_live/strategies.py` | 118 | **AShareDoubleMaStrategy**:15min 双均线(BarGenerator window=15),死叉只平多不开空 | | `sanguo_live/engine.py` | 154 | **LiveTradingEngine**:EventEngine + MainEngine + QmtGateway + CtaStrategyApp 封装 | | `sanguo_live/runner.py` | 168 | run(): connect → add → subscribe → init_all → start_all → 常驻,SIGINT/SIGTERM 优雅停 | | `config/live.yaml` | 35 | 配置(账号 66639661 / 标的 600000.SSE / 15min / size=100) | | `tests/test_live_engine.py` | 252 | 单测(层 1 纯Py 7 项 + 层 2 依赖vnpy 8 项) | ### 关键设计决策 - **策略不直接复用 vnpy_ctastrategy.DoubleMaStrategy**:其 `BarGenerator(self.on_bar)` 无 window 参数(仅 1min),且 `parameters=["fast_window","slow_window"]` 不暴露周期,**无法通过 setting 切 15min**。改写 `AShareDoubleMaStrategy` 用 `BarGenerator(self._on_1min_bar, window=15, on_window_bar=self.on_bar)`,on_bar 直接收 15min bar。 - **A股不可做空**:基类 `short()` 返回 [] 拦截;`AShareDoubleMaStrategy.on_bar` 的死叉分支删除原 DoubleMa 的 `pos==0 → short` 和 `pos<0 → cover+buy` 分支,只保留 `pos>0 → sell`。 - **定寸**:vnpy_qmt send_order 按"股数"直传 xtquant(不自动 ×size),策略 `buy(1)` 会下 1 股被拒。AShareCtaTemplate 在 buy/cover/sell 内部 `×= self.size`(默认100)。 - **模块 import 容错**:本机 dev 视图没装 vnpy_ctastrategy/vnpy_qmt,所有 vnpy import try/except + fallback,模块加载不崩,运行时才校验。 ### 单测结果 | 平台 | 结果 | 说明 | |------|------|------| | Mac dev (`venv` Python 3.14) | **7 passed, 8 skipped** | 层 1 纯Py 全 pass;层 2 依赖 vnpy_ctastrategy 自动 skip(Mac 没装),exit 0 | | VPS Windows (`C:\Python310`, vnpy 4.4.0 + vnpy_ctastrategy 1.4.1 + vnpy_qmt 0.3.3 vendor) | **15 passed** | 全部 pass:定寸 (buy 1→100 / size=200 → buy 2 = 400) / 禁做空 / LiveTradingEngine 组装 (QMT gateway + CTA app 注册成功) | | 回归检查 | `test_strategy_registry.py`(4) + `test_cta_adapter.py`(5) | **9 passed**,无回归 | ### VPS 环境核实 - `vnpy_ctastrategy 1.4.1` 装在 `C:\Python310\lib\site-packages\`(pip 安装) ✅ - `vnpy 4.4.0` 同上 ✅ - `vnpy_qmt 0.3.3` vendor 在 `C:\sanguo_vnpy_v2\vnpy_qmt_v0.3.3\`(非 pip,通过 `sys.path.insert` 引用,与 `run_web.py` 一致) ✅ - VPS 跑测试时 PYTHONPATH 设为 `vnpy_v4.4.0;vnpy_qmt_v0.3.3;sanguo_live_test`(生产由 run_web 风格的 bootstrap 注入,已在 runner.py 文档说明) ### 连通性状态 - **代码层验证**:LiveTradingEngine 装配(MainEngine + QmtGateway + CtaStrategyApp 三件一套)、策略实例化、定寸/禁做空逻辑全部 pass - **实盘下单链路**:**待盘中验证**(非交易日/非盘中,且需 miniQMT 在线。按要求不强行跑。下次盘中跑 `python -m sanguo_live` 即可端到端验证 connect → subscribe tick → 15min bar → 策略 → 真实下单) ### 约束遵循 - ✅ 未动 sanguo_trader / sanguo_api 任何代码 - ✅ 风控未做(只做定寸 + 禁做空这两条必要的) - ✅ Type annotations + PEP8 + logging(不 print)+ 多小文件(最大 168 行) - ✅ vnpy import 全部容错(本机 import 不崩) - ✅ 未自己 git commit / 建 PR(等 Main Agent Review+合并)
Author
Member

@main-agent REVIEW_DONE verdict=approved (task #3 引擎核心)

Review 通过。定寸/禁做空/15min BarGenerator/引擎组装/runner流程全正确。单测 Mac 7pass+VPS 15pass+回归9pass。2个小点(OMS engine名/固定sleep)不影响MVP,盘中连通性验收时优化。连通性6步归 #6 盘中统一验。

推进 #4(后端API+持久化)。

@main-agent ✅ REVIEW_DONE verdict=approved (task #3 引擎核心) Review 通过。定寸/禁做空/15min BarGenerator/引擎组装/runner流程全正确。单测 Mac 7pass+VPS 15pass+回归9pass。2个小点(OMS engine名/固定sleep)不影响MVP,盘中连通性验收时优化。连通性6步归 #6 盘中统一验。 推进 #4(后端API+持久化)。
Author
Member

@main-agent EXECUTE_DONE

task #4 实盘模拟 API + 持久化 完成

文件清单(7 文件)

文件 类型 说明
sanguo_live/persistence.py 新建 4 表(live_accounts/trades/positions/balance) + 13 CRUD 函数,sqlite WAL,照搬 paper persistence 风格
sanguo_api/routes_live.py 新建 9 路由 FastAPI,照搬 routes_paper 风格(set_db_path + verify_token)
sanguo_api/app.py include live_router + 双 set_db_path(paper/live 各一,共用同 db_path)
sanguo_live/runner.py 扩展 run_supervisor() + 事件/快照辅助(run() 原签名不动)
sanguo_live/__main__.py --supervisor [db] 模式
config/data_platform.yaml live_trading: 段(enabled/db_path/poll/snapshot)
tests/test_live_api.py 新建 16 单测(persistence 8 + routes 8)

API 路由清单(prefix /api/v1)

  • POST /live/create — 建 live_account(status=stopped)
  • GET /live — 列表(带 latest_equity/total_return/position_count 摘要)
  • GET /live/{aid} — 详情
  • POST /live/{aid}/start — status=running(account 空 → 400)
  • POST /live/{aid}/stop — status=stopped
  • GET /live/{aid}/positions — 持仓快照
  • GET /live/{aid}/trades — 成交明细
  • GET /live/{aid}/account — 账户最新快照
  • GET /live/{aid}/status — 运行状态

supervisor 设计(API↔runner DB 解耦)

  • python -m sanguo_live --supervisor [db] 起 supervisor 常驻进程
  • 轮询 live_accounts.status(默认 5s):running → 起 LiveTradingEngine + 注册 EVENT_TRADE 回调(成交落 live_trades);stopped → stop+close engine
  • 定时(默认 30s)把 OMS get_positions()/get_all_accounts() 覆盖式落 live_positions/live_balance
  • 信号(SIGINT/SIGTERM)→ 停所有 engine 后退出
  • run()(config 驱动单实例)签名不动,#3 引擎代码 0 改动

单测结果

pytest tests/test_live_api.py -v → 16 passed (0.35s)
pytest tests/test_live_engine.py tests/api/test_paper_routes.py tests/api/test_main.py
  → 17 passed, 8 skipped(vnpy_cta 依赖,Mac skip,VPS 跑) — 0 回归

约束达成

  • 不破坏 #3 引擎接口(engine/base_template/strategies 公开方法 0 改动)
  • 风控不做
  • type annotations / PEP8 / logging(不 print)
  • 文件 <300 行(persistence 230 / routes_live 165 / runner 扩展 ~200)
  • Mac 单测跑通(vnpy 依赖只在 supervisor 运行时触发,单测纯 sqlite + TestClient)
  • 前端响应结构参考 routes_paper(accounts 列表 + total_return 摘要模式)

未 commit / 未建 PR(等 Main Agent Review)。

@main-agent ✅ EXECUTE_DONE ## task #4 实盘模拟 API + 持久化 完成 ### 文件清单(7 文件) | 文件 | 类型 | 说明 | |------|------|------| | `sanguo_live/persistence.py` | 新建 | 4 表(live_accounts/trades/positions/balance) + 13 CRUD 函数,sqlite WAL,照搬 paper persistence 风格 | | `sanguo_api/routes_live.py` | 新建 | 9 路由 FastAPI,照搬 routes_paper 风格(set_db_path + verify_token) | | `sanguo_api/app.py` | 改 | include live_router + 双 set_db_path(paper/live 各一,共用同 db_path) | | `sanguo_live/runner.py` | 扩展 | 加 `run_supervisor()` + 事件/快照辅助(`run()` 原签名不动) | | `sanguo_live/__main__.py` | 改 | 加 `--supervisor [db]` 模式 | | `config/data_platform.yaml` | 改 | 加 `live_trading:` 段(enabled/db_path/poll/snapshot) | | `tests/test_live_api.py` | 新建 | 16 单测(persistence 8 + routes 8) | ### API 路由清单(prefix `/api/v1`) - `POST /live/create` — 建 live_account(status=stopped) - `GET /live` — 列表(带 latest_equity/total_return/position_count 摘要) - `GET /live/{aid}` — 详情 - `POST /live/{aid}/start` — status=running(account 空 → 400) - `POST /live/{aid}/stop` — status=stopped - `GET /live/{aid}/positions` — 持仓快照 - `GET /live/{aid}/trades` — 成交明细 - `GET /live/{aid}/account` — 账户最新快照 - `GET /live/{aid}/status` — 运行状态 ### supervisor 设计(API↔runner DB 解耦) - `python -m sanguo_live --supervisor [db]` 起 supervisor 常驻进程 - 轮询 `live_accounts.status`(默认 5s):running → 起 LiveTradingEngine + 注册 EVENT_TRADE 回调(成交落 live_trades);stopped → stop+close engine - 定时(默认 30s)把 OMS `get_positions()`/`get_all_accounts()` 覆盖式落 live_positions/live_balance - 信号(SIGINT/SIGTERM)→ 停所有 engine 后退出 - `run()`(config 驱动单实例)签名不动,#3 引擎代码 0 改动 ### 单测结果 ``` pytest tests/test_live_api.py -v → 16 passed (0.35s) pytest tests/test_live_engine.py tests/api/test_paper_routes.py tests/api/test_main.py → 17 passed, 8 skipped(vnpy_cta 依赖,Mac skip,VPS 跑) — 0 回归 ``` ### 约束达成 - ✅ 不破坏 #3 引擎接口(engine/base_template/strategies 公开方法 0 改动) - ✅ 风控不做 - ✅ type annotations / PEP8 / logging(不 print) - ✅ 文件 <300 行(persistence 230 / routes_live 165 / runner 扩展 ~200) - ✅ Mac 单测跑通(vnpy 依赖只在 supervisor 运行时触发,单测纯 sqlite + TestClient) - ✅ 前端响应结构参考 routes_paper(accounts 列表 + total_return 摘要模式) 未 commit / 未建 PR(等 Main Agent Review)。
Author
Member

@main-agent REVIEW_DONE verdict=approved (task #4 API+持久化)

Review 通过。9路由全(auth照搬/查询全走DB不碰engine,解耦干净);supervisor 轮询status起停engine+EVENT_TRADE落库+30s快照,run()原签名保留(#3零改动);16单测+回归0。小点(:memory:边界/AccountData字段近似/trade strategy_name暂空)MVP可接受。

推进 #5 前端UI。

@main-agent ✅ REVIEW_DONE verdict=approved (task #4 API+持久化) Review 通过。9路由全(auth照搬/查询全走DB不碰engine,解耦干净);supervisor 轮询status起停engine+EVENT_TRADE落库+30s快照,run()原签名保留(#3零改动);16单测+回归0。小点(:memory:边界/AccountData字段近似/trade strategy_name暂空)MVP可接受。 推进 #5 前端UI。
Author
Member

@main-agent EXECUTE_DONE

实盘模拟前端 UI 实现完成

文件清单

新增 4 个文件:

  • frontend/src/api/live.ts — API 客户端(9 个接口:createLive/listLives/getLive/startLive/stopLive/getLivePositions/getLiveTrades/getLiveAccountBalance/getLiveStatus)
  • frontend/src/views/live/New.vue — 新建实盘(表单:实例名/交易账号/标的/策略类下拉/策略实例名/setting 参数 fast_window/slow_window/window/size/forbid_short/interval/initial_capital/connect_wait_sec/init_wait_sec/mini_path)
  • frontend/src/views/live/List.vue — 列表(统计卡总数/运行中/已停止、表格列含收益率/最新净值/持仓数/状态、启动/停止/监控操作、15s 自动刷新)
  • frontend/src/views/live/Monitor.vue — 实时监控(6 状态卡 + 净值三件套 cash/market_value/total + 持仓表 + 今日成交 + 全部成交 + 策略参数,10s 自动刷新,启动/停止按钮)

修改 2 个文件:

  • frontend/src/router/index.ts — 加 3 个路由(live-new / live-list / live-monitor)
  • frontend/src/views/Layout.vue — 侧边栏原 disabled "实盘" 改为启用 "实盘模拟" 子菜单(列表/新建),breadcrumb 加 3 条匹配

实现要点

  • 风格完全照搬 paper 前端(卡片/表格/chip/状态色 .st-running .st-pending 复用全局 chips.css)
  • 错误处理:所有接口失败有 ElMessage 提示,不静默
  • setting 字段后端是 JSON 字符串,Monitor.vue 用 computed JSON.parse 容错显示
  • 风控 UI 未做(按任务说明跳过)
  • 提示用户:New.vue 成功提示和顶部 info alert 都说明"创建后状态 stopped,需到列表点启动才会跑"

构建验证

cd frontend && npm run build  # vue-tsc -b && vite build
✓ built in 437ms

TypeScript 类型检查通过(vue-tsc -b 是 build 脚本的前置步骤,失败会中断)。仅有第三方 @vueuse/core 的 PURE annotation 警告(node_modules 内,非本次代码)和 echarts chunk size 警告(项目既有)。

未做

  • 未 git commit / 建 PR(等 Main Agent Review + 合并)
  • 后端起不来时无法端到端实测(只验证构建)
@main-agent ✅ EXECUTE_DONE ## 实盘模拟前端 UI 实现完成 ### 文件清单 **新增 4 个文件**: - `frontend/src/api/live.ts` — API 客户端(9 个接口:createLive/listLives/getLive/startLive/stopLive/getLivePositions/getLiveTrades/getLiveAccountBalance/getLiveStatus) - `frontend/src/views/live/New.vue` — 新建实盘(表单:实例名/交易账号/标的/策略类下拉/策略实例名/setting 参数 fast_window/slow_window/window/size/forbid_short/interval/initial_capital/connect_wait_sec/init_wait_sec/mini_path) - `frontend/src/views/live/List.vue` — 列表(统计卡总数/运行中/已停止、表格列含收益率/最新净值/持仓数/状态、启动/停止/监控操作、15s 自动刷新) - `frontend/src/views/live/Monitor.vue` — 实时监控(6 状态卡 + 净值三件套 cash/market_value/total + 持仓表 + 今日成交 + 全部成交 + 策略参数,10s 自动刷新,启动/停止按钮) **修改 2 个文件**: - `frontend/src/router/index.ts` — 加 3 个路由(live-new / live-list / live-monitor) - `frontend/src/views/Layout.vue` — 侧边栏原 disabled "实盘" 改为启用 "实盘模拟" 子菜单(列表/新建),breadcrumb 加 3 条匹配 ### 实现要点 - 风格完全照搬 paper 前端(卡片/表格/chip/状态色 .st-running .st-pending 复用全局 chips.css) - 错误处理:所有接口失败有 ElMessage 提示,不静默 - setting 字段后端是 JSON 字符串,Monitor.vue 用 computed JSON.parse 容错显示 - 风控 UI 未做(按任务说明跳过) - 提示用户:New.vue 成功提示和顶部 info alert 都说明"创建后状态 stopped,需到列表点启动才会跑" ### 构建验证 ``` cd frontend && npm run build # vue-tsc -b && vite build ✓ built in 437ms ``` TypeScript 类型检查通过(`vue-tsc -b` 是 build 脚本的前置步骤,失败会中断)。仅有第三方 @vueuse/core 的 PURE annotation 警告(node_modules 内,非本次代码)和 echarts chunk size 警告(项目既有)。 ### 未做 - 未 git commit / 建 PR(等 Main Agent Review + 合并) - 后端起不来时无法端到端实测(只验证构建)
Author
Member

@main-agent REVIEW_DONE verdict=approved (task #5 前端UI)

Review 通过。api/live.ts 9接口路径/方法/TS类型全匹配后端契约;List.vue 启停带确认+15s刷新+错误处理;vue-tsc+vite build 0错误;风格复用paper。前后端代码全部交付(#3/#4/#5 review全过)。

#6 集成验收。当前盘后(19:23),盘中真实下单6步要明天盘中。

@main-agent ✅ REVIEW_DONE verdict=approved (task #5 前端UI) Review 通过。api/live.ts 9接口路径/方法/TS类型全匹配后端契约;List.vue 启停带确认+15s刷新+错误处理;vue-tsc+vite build 0错误;风格复用paper。前后端代码全部交付(#3/#4/#5 review全过)。 进 #6 集成验收。当前盘后(19:23),盘中真实下单6步要明天盘中。
Author
Member

Task #6a — VPS 部署 + 非盘中冒烟 报告

@main-agent TEST_DONE result=smoke_passed (7/7 非盘中项;盘中 6 步待明天盘中补)

冒烟清单 7 项结果

# 结果 证据
1 API 通(GET /live) {accounts:[]}
2 创建实例(POST /live/create) {account_id:1, status:"stopped"}
3 supervisor 启动 log: [supervisor] 启动 (db=...backtest_results.db poll=5.0s snapshot=30.0s)
4 start → engine 起 → connect miniQMT 成功 (修一次) log: [td] 连接成功 / 订阅账户成功:0 / engine 已启动 (account=66639661 strategy=smoke_test)
5 snapshot 落库 + status/account /live/1/account total=9999929.51; /live/1/status running; /live/1/positions 2 只(000001.SZSE 100 股 + 600000.SSE 200 股)
6 前端列表+监控渲染 浏览器打开 /live 见 smoke_test #1, 9,999,930 净值, 2 持仓, 运行中; /live/monitor/1 完整
7 stop → supervisor 停 engine API {status:"stopped"} + log: [supervisor] 停止 engine (account=1) / LiveTradingEngine 已关闭

Item 4 修过的一次坑(冒烟定位+修复)

首次 start 时 [td] 连接失败:-1 / 订阅账户【失败】:-1根因: smoke_test 创建时 mini_path 留空(默认),td.py 不做 auto-scan(只有 md.py 做),XtQuantTrader(path="", ...) 连不上 miniQMT IPC。直接 sqlite3 把 live_accounts.mini_path 改为 C:\国金QMT交易端模拟\userdata_mini,stop+start 后 connect 一次成功。

遗留代码改进点(非阻断,建议下个迭代修):

  1. routes_live.LiveCreateRequest.mini_path 默认空导致 connect=-1:要么前端"新建实盘"表单强制要 mini_path,要么 td.py 仿 md.py 加 auto-scan,要么 LiveCreateRequest 在 supervisor 模式下用 env SANGUO_QMT_PATH 兜底。
  2. 收益率显示失真:routes_live.list_lives(last_total - initial_capital) / initial_capital。当用户配置 initial_capital=1_000_000 但账户实有 9.99M 时显示 899.99%。建议改为 (last_total - FIRST_snapshot_total) / FIRST_snapshot_total(首快照为基线)。
  3. vnpy.event import 失败 warning:[supervisor] 无 vnpy.event, EVENT_TRADE 回调未注册。vnpy 4.4.0 下事件模块路径可能变了,明天盘中下真实单前必须先修这个(否则成交不落 live_trades 表)。已确认 pip install vnpy_ctastrategy 装了但 vnpy.event 不可 import,需要排查。

VPS 部署方式摘要

资产 方式 路径
后端代码同步 本地 tar 打包 → ssh tar 解包到 VPS 项目根 C:\sanguo_vnpy_v2\sanguo_live\, sanguo_api\app.py, sanguo_api\routes_live.py, config\live.yaml
后端服务起法 沿用既有 sanguo-api schtask(schtasks /Run) run_api.ps1run_web.py → uvicorn:8000
前端构建 Mac 本地 npm run build frontend/dist/
前端部署 tar 打包 → ssh tar 解包(覆盖 dist) C:\sanguo_vnpy_v2\frontend\dist\(FastAPI StaticFiles 自动 mount /,无需重启)
外网入口 Caddy(已 disable),走 sanguo-api schtask + 防火墙+8889 -> 不,实际外网入口是 https://vnpy.mysanguo.top/(认证 Bearer JWT, secret 见 config/backtest.yaml) -

Supervisor 常驻配置状态

  • 当前:手动 Start-Process powershell -File run_supervisor.ps1 -WindowStyle Hidden,PID 6272,19:42:54 起,已稳定运行 25min+(stop/start API 循环 3 次都正常响应)
  • launcher: C:\sanguo_vnpy_v2\run_supervisor.ps1(显式传 DB 路径 C:\sanguo_vnpy_v2\data\backtest_results.db,因为 config/data_platform.yaml 默认指 NAS 路径,在 VPS 上会错)
  • log: C:\Users\Administrator\supervisor.log
  • 未做开机自启(任务约定可留待盘中验证后)。建议正式常驻用 schtasks /Create /tn sanguo-supervisor /sc onstart /tr "powershell -File C:\sanguo_vnpy_v2\run_supervisor.ps1"(仿 sanguo-api 模式),delayed start 30s 等 miniQMT 起来。

盘中真实下单 6 步(明天盘中补)

  1. connect 今天已验(/live/1/start 后 log [td] 连接成功)
  2. tick 收 待 9:30 开盘后验(supervisor log 应见 tick 推送;盘后无 tick 是预期)
  3. 15min bar 合成 待 9:45 第一根 15min bar 收盘
  4. on_bar 触发 log 应见 strategy.on_bar 调用
  5. 真实下单 order_stock_async 是否成交(测试账户 66639661 有 9.99M 可用,200 股 600000@9.27 约 1854 元,够)
  6. 回读一致 live_trades 表落库(⚠️ 必须先修上述遗留 #3vnpy.event import 问题,否则成交不落库)

约束遵守

  • 未破坏 bridge(disabled 不动)/sanguo-api/Caddy
  • 沿用现有 scp+tar 同步、schtasks+ps1 启动、FastAPI StaticFiles 部署
  • Python 一律 -X utf8
  • 未 git commit / 未建 PR
## Task #6a — VPS 部署 + 非盘中冒烟 报告 @main-agent ✅ TEST_DONE result=smoke_passed (7/7 非盘中项;盘中 6 步待明天盘中补) ### 冒烟清单 7 项结果 | # | 项 | 结果 | 证据 | |---|---|---|---| | 1 | API 通(GET /live) | ✅ | `{accounts:[]}` | | 2 | 创建实例(POST /live/create) | ✅ | `{account_id:1, status:"stopped"}` | | 3 | supervisor 启动 | ✅ | log: `[supervisor] 启动 (db=...backtest_results.db poll=5.0s snapshot=30.0s)` | | 4 | start → engine 起 → connect miniQMT 成功 | ✅(修一次) | log: `[td] 连接成功 / 订阅账户成功:0 / engine 已启动 (account=66639661 strategy=smoke_test)` | | 5 | snapshot 落库 + status/account | ✅ | `/live/1/account` total=9999929.51; `/live/1/status` running; `/live/1/positions` 2 只(000001.SZSE 100 股 + 600000.SSE 200 股) | | 6 | 前端列表+监控渲染 | ✅ | 浏览器打开 `/live` 见 smoke_test #1, 9,999,930 净值, 2 持仓, 运行中; `/live/monitor/1` 完整 | | 7 | stop → supervisor 停 engine | ✅ | API `{status:"stopped"}` + log: `[supervisor] 停止 engine (account=1) / LiveTradingEngine 已关闭` | ### Item 4 修过的一次坑(冒烟定位+修复) 首次 start 时 `[td] 连接失败:-1 / 订阅账户【失败】:-1`。**根因**: smoke_test 创建时 `mini_path` 留空(默认),`td.py` 不做 auto-scan(只有 `md.py` 做),`XtQuantTrader(path="", ...)` 连不上 miniQMT IPC。直接 sqlite3 把 `live_accounts.mini_path` 改为 `C:\国金QMT交易端模拟\userdata_mini`,stop+start 后 connect 一次成功。 > **遗留代码改进点**(非阻断,建议下个迭代修): > 1. **`routes_live.LiveCreateRequest.mini_path` 默认空导致 connect=-1**:要么前端"新建实盘"表单强制要 mini_path,要么 `td.py` 仿 `md.py` 加 auto-scan,要么 LiveCreateRequest 在 supervisor 模式下用 env `SANGUO_QMT_PATH` 兜底。 > 2. **收益率显示失真**:`routes_live.list_lives` 用 `(last_total - initial_capital) / initial_capital`。当用户配置 `initial_capital=1_000_000` 但账户实有 9.99M 时显示 899.99%。建议改为 `(last_total - FIRST_snapshot_total) / FIRST_snapshot_total`(首快照为基线)。 > 3. **`vnpy.event` import 失败 warning**:`[supervisor] 无 vnpy.event, EVENT_TRADE 回调未注册`。vnpy 4.4.0 下事件模块路径可能变了,明天盘中下真实单前必须先修这个(否则成交不落 `live_trades` 表)。已确认 `pip install vnpy_ctastrategy` 装了但 `vnpy.event` 不可 import,需要排查。 ### VPS 部署方式摘要 | 资产 | 方式 | 路径 | |---|---|---| | 后端代码同步 | 本地 tar 打包 → ssh tar 解包到 VPS 项目根 | `C:\sanguo_vnpy_v2\sanguo_live\`, `sanguo_api\app.py`, `sanguo_api\routes_live.py`, `config\live.yaml` | | 后端服务起法 | 沿用既有 `sanguo-api` schtask(schtasks /Run) | `run_api.ps1` → `run_web.py` → uvicorn:8000 | | 前端构建 | Mac 本地 `npm run build` | `frontend/dist/` | | 前端部署 | tar 打包 → ssh tar 解包(覆盖 dist) | `C:\sanguo_vnpy_v2\frontend\dist\`(FastAPI StaticFiles 自动 mount `/`,无需重启) | | 外网入口 | Caddy(已 disable),走 sanguo-api schtask + 防火墙+8889 -> 不,实际外网入口是 https://vnpy.mysanguo.top/(认证 Bearer JWT, secret 见 `config/backtest.yaml`) | - | ### Supervisor 常驻配置状态 - 当前:**手动 `Start-Process powershell -File run_supervisor.ps1 -WindowStyle Hidden`**,PID 6272,19:42:54 起,已稳定运行 25min+(stop/start API 循环 3 次都正常响应) - launcher: `C:\sanguo_vnpy_v2\run_supervisor.ps1`(显式传 DB 路径 `C:\sanguo_vnpy_v2\data\backtest_results.db`,因为 `config/data_platform.yaml` 默认指 NAS 路径,在 VPS 上会错) - log: `C:\Users\Administrator\supervisor.log` - **未做开机自启**(任务约定可留待盘中验证后)。建议正式常驻用 `schtasks /Create /tn sanguo-supervisor /sc onstart /tr "powershell -File C:\sanguo_vnpy_v2\run_supervisor.ps1"`(仿 sanguo-api 模式),delayed start 30s 等 miniQMT 起来。 ### 盘中真实下单 6 步(明天盘中补) 1. **connect** — ✅ 今天已验(`/live/1/start` 后 log `[td] 连接成功`) 2. **tick 收** — ⏳ 待 9:30 开盘后验(supervisor log 应见 tick 推送;盘后无 tick 是预期) 3. **15min bar 合成** — ⏳ 待 9:45 第一根 15min bar 收盘 4. **on_bar 触发** — ⏳ log 应见 strategy.on_bar 调用 5. **真实下单** — ⏳ `order_stock_async` 是否成交(测试账户 66639661 有 9.99M 可用,200 股 600000@9.27 约 1854 元,够) 6. **回读一致** — ⏳ `live_trades` 表落库(⚠️ 必须先修上述遗留 #3 的 `vnpy.event` import 问题,否则成交不落库) ### 约束遵守 - ✅ 未破坏 bridge(disabled 不动)/sanguo-api/Caddy - ✅ 沿用现有 scp+tar 同步、schtasks+ps1 启动、FastAPI StaticFiles 部署 - ✅ Python 一律 `-X utf8` - ✅ 未 git commit / 未建 PR
Author
Member

@main-agent EXECUTE_DONE fixes_local

3 点代码修复完成(仅 Mac 本地,未动 VPS/未重启/未杀进程)

1. mini_path 默认空 → connect=-1

sanguo_api/routes_live.py create_live:

  • req.mini_path 空 → os.environ.get("SANGUO_QMT_PATH") → 内置默认 C:\国金QMT交易端模拟\userdata_mini(三段兜底)
  • 模块顶部加常量 _DEFAULT_MINI_PATH

frontend/src/views/live/New.vue:

  • form.mini_path 默认值改为内置路径(原本是空字符串)
  • placeholder 改为实际路径 + 提示"空时后端用 env/内置默认"

2. EVENT_TRADE import 失败 → 成交不落 live_trades

只读排查(VPS ssh 验证,无写入/无重启/无杀进程):

  • C:\Python310\lib\site-packages\vnpy\event\__init__.py 只导出 Event / EventEngine / EVENT_TIMER,不含 EVENT_TRADE
  • from vnpy.event import EVENT_TRADEImportError(实证,runner.py:252 旧代码 bug)
  • from vnpy.trader.event import EVENT_TRADE → ok,返回 "eTrade."
  • EVENT_TRADE 定义在 vnpy/trader/event.py:8

修复 sanguo_live/runner.py _register_trade_handler:

  • from vnpy.event import EVENT_TRADEfrom vnpy.trader.event import EVENT_TRADE
  • docstring 补上事件常量实际位置说明,避免未来再踩
  • 字段映射(vt_symbol/price/volume/datetime/vt_tradeid/direction.name/offset.name)原样正确,未动

3. 收益率显示失真(initial_capital 兜底)

sanguo_live/persistence.py: 新增 get_first_balance(db, account_id)(ORDER BY id ASC LIMIT 1),加入 __all__
sanguo_api/routes_live.py list_lives:

  • baseline = 首快照 live_balance.total(该 account 最早一条)
  • 收益率 = (last_total - first_total) / first_total
  • 无快照 → total_return=None(不再兜底 initial_capital)

单测验证(Mac 本地)

pytest tests/test_live_api.py tests/test_live_engine.py -v
→ 26 passed, 8 skipped(vnpy_cta 层 Mac 没装,预期)

新增 3 个用例:

  • test_create_live_mini_path_default_when_empty — 不传 mini_path → 落库值含 userdata_mini
  • test_create_live_mini_path_env_fallback — env SANGUO_QMT_PATH 兜底
  • test_list_lives_total_return_uses_first_snapshot_baseline — initial_capital=6e5 + 首快照 5e5 + 末快照 5.5e5 → 收益率 0.1(按首快照,非 -0.0833 按 initial)

既有 test_routes_reflect_db_writes 单条快照场景: first==last → 0.0,仍通过(0 回归)。

前端构建

cd frontend && npm run build → ✓ built in 424ms

约束遵守

  • 只改 Mac 本地代码 + ssh VPS 只读查询
  • 无 VPS 写入/部署/重启/杀进程
  • 未 git commit/建 PR(留给 Main Agent)
@main-agent ✅ EXECUTE_DONE fixes_local ## 3 点代码修复完成(仅 Mac 本地,未动 VPS/未重启/未杀进程) ### 1. mini_path 默认空 → connect=-1 **`sanguo_api/routes_live.py`** `create_live`: - req.mini_path 空 → `os.environ.get("SANGUO_QMT_PATH")` → 内置默认 `C:\国金QMT交易端模拟\userdata_mini`(三段兜底) - 模块顶部加常量 `_DEFAULT_MINI_PATH` **`frontend/src/views/live/New.vue`**: - `form.mini_path` 默认值改为内置路径(原本是空字符串) - placeholder 改为实际路径 + 提示"空时后端用 env/内置默认" ### 2. EVENT_TRADE import 失败 → 成交不落 live_trades **只读排查(VPS ssh 验证,无写入/无重启/无杀进程):** - `C:\Python310\lib\site-packages\vnpy\event\__init__.py` 只导出 `Event / EventEngine / EVENT_TIMER`,**不含 EVENT_TRADE** - `from vnpy.event import EVENT_TRADE` → **ImportError**(实证,runner.py:252 旧代码 bug) - `from vnpy.trader.event import EVENT_TRADE` → ok,返回 `"eTrade."` - EVENT_TRADE 定义在 `vnpy/trader/event.py:8` **修复 `sanguo_live/runner.py`** `_register_trade_handler`: - `from vnpy.event import EVENT_TRADE` → `from vnpy.trader.event import EVENT_TRADE` - docstring 补上事件常量实际位置说明,避免未来再踩 - 字段映射(vt_symbol/price/volume/datetime/vt_tradeid/direction.name/offset.name)原样正确,未动 ### 3. 收益率显示失真(initial_capital 兜底) **`sanguo_live/persistence.py`**: 新增 `get_first_balance(db, account_id)`(ORDER BY id ASC LIMIT 1),加入 `__all__` **`sanguo_api/routes_live.py`** `list_lives`: - baseline = 首快照 `live_balance.total`(该 account 最早一条) - 收益率 = `(last_total - first_total) / first_total` - 无快照 → `total_return=None`(不再兜底 `initial_capital`) ## 单测验证(Mac 本地) ``` pytest tests/test_live_api.py tests/test_live_engine.py -v → 26 passed, 8 skipped(vnpy_cta 层 Mac 没装,预期) ``` 新增 3 个用例: - `test_create_live_mini_path_default_when_empty` — 不传 mini_path → 落库值含 `userdata_mini` - `test_create_live_mini_path_env_fallback` — env `SANGUO_QMT_PATH` 兜底 - `test_list_lives_total_return_uses_first_snapshot_baseline` — initial_capital=6e5 + 首快照 5e5 + 末快照 5.5e5 → 收益率 0.1(按首快照,非 -0.0833 按 initial) 既有 `test_routes_reflect_db_writes` 单条快照场景: first==last → 0.0,仍通过(0 回归)。 ## 前端构建 ``` cd frontend && npm run build → ✓ built in 424ms ``` ## 约束遵守 - ✅ 只改 Mac 本地代码 + ssh VPS 只读查询 - ✅ 无 VPS 写入/部署/重启/杀进程 - ✅ 未 git commit/建 PR(留给 Main Agent)
Sign in to join this conversation.