release: v1.27.0 — 通达信公式解析器三通道 + 轮动组合引擎 + 回测页WF/评估开关 + Docker 部署

升级计划 P3 + P4(部分)。全量 1252 单测、ruff/mypy strict、前端 vue-tsc+vite build 全绿。

- 通达信公式解析器(formula.py):自建 tokenizer + 递归下降 AST + 30+ 函数白名单求值
  (不走 Python eval);命名布尔输出=信号列、数值输出=排名列;除零→NaN、预热期不出信号
- 公式三通道:CLI easy-tdx formula compute|screen|backtest;REST /formula/validate|compute|
  backtest|screen(run/async);Python API run_formula_backtest(买/卖列自动挑选)
- 轮动组合引擎(rotation.py):排名定期换仓(打分只用截至当日数据)、槽位等额、
  跌出排名自动补位、日/周/月刷新、槽内止盈止损;momentum_score/formula_score 打分;
  REST /backtest/rotation/run/async
- 回测页附加分析开关(Web UI):勾选后随回测并行跑 WF(逐窗红涨绿跌柱状图+汇总卡,
  窗口数 2~12)与一条龙评估(评分分项条/高适配徽标/买入持有对比/8 项适配检查);
  新增 WalkForwardPanel/EvaluatePanel 组件与 store runWalkforward/runEvaluate;
  WF 端点 ?n_windows= 透传;修复报告 numpy 标量 REST 400(源头清洗)
- Docker 部署(Dockerfile + docker-compose.yml,/data 卷 + 健康检查)与
  scripts/verify_ci.sh 一键门禁
- 升级计划文档 docs/upgrade-plan-2026H2.md(四阶段全部完成 + 诚实实测数据)
- 未做(独立排期):Playwright E2E、WebSocket 实时联动、引擎逐 bar 向量化
This commit is contained in:
GitHub
2026-09-01 22:17:57 +08:00
parent 9569b2653c
commit 917295edaf
23 changed files with 3135 additions and 5 deletions
+135
View File
@@ -0,0 +1,135 @@
# easy-tdx 升级开发计划(2026 H2
> **执行进度**2026-09-01 最终更新:全部阶段完成):
> - ✅ **P0 v1.24.0**——QFQ 对拍验证体系、回测任务 SQLite 持久化 + 导出、品种感知费率
> - ✅ **P1 v1.25.0**——Walk-Forward 引擎、适配性评估、一条龙评估、综合评分、评级后端化、多 seed 验证 + 晋级门槛、寻优两段式加速(指标缓存 + 进程并行)
> - ✅ **P2 v1.26.0**——DuckDB K 线仓库 + provisional 状态机 + 增量同步 + 健康自检 + CLI `warehouse` 命令组(P2-2 评级后端化已随 1.25.0 提前交付)
> - ✅ **P3 v1.27.0**——通达信公式解析器(tokenizer + AST + 白名单求值,无 Python eval+ 公式三通道(CLI `formula` / REST `/formula/*` / Python API+ 轮动组合引擎(排名换仓 + 槽位等额 + 自动补位 + 止盈止损,REST `/backtest/rotation/run/async`
> - ✅ **P1 前端补全(随 1.27.0)**——回测页「附加分析」开关:WF 逐窗柱状图 + 一条龙评估报告卡(评分分项/高适配徽标/买入持有基准对比/8 项适配检查),复用同一份内联行情并行执行
> - ✅ **P4(部分)v1.27.0**——Docker Compose 部署 + `scripts/verify_ci.sh` 一键门禁。**未做**Playwright E2E(需前端基建,独立排期)、WebSocket 实时推送联动 EventBusREADME 既有 TODO,与本计划无耦合)、引擎逐 bar 循环向量化(寻优加速的下一步方向)——三项已整理为独立排期提示词
>
> 实测备注(诚实数据):
> - 寻优加速——指标缓存命中率 41.7%(36 点网格)但墙钟 ~1.01x(本引擎指标层非瓶颈,逐 bar Python 循环才是);进程并行 4 workers 约 2x。后续更大加速的方向是引擎循环向量化。
> - 最终回归:1252 个单元测试全过(基线 1078),ruff / ruff format / mypy strict245 文件)全绿。
>
> 依据:对两个基于 easy-tdx 的下游项目的逆向调研
> - [mvpbaggio/backtest-system](https://github.com/mvpbaggio/backtest-system)v1.4MIT)— 回测框架,运行时依赖 easy-tdx(行情拉取、PerformanceAnalyzer、MyTT、Param 注册表思路)
> - [kendev93/indicator-lab](https://github.com/kendev93/indicator-lab)AGPL-3.0)— 指标实验室,参考改写了 easy-tdx 的 TDX 协议层与 `.day` 格式(见其 THIRD_PARTY_NOTICES.md),运行时不依赖
> 调研日期:2026-09-01,基线版本 v1.23.3
---
## 一、核心洞察
两个下游项目**独立地**在补 easy-tdx 的同一类空白,这比任何单个功能都更有信号价值:
1. **防过拟合验证是最大空白**。backtest-system 自研了严格 7 窗 Walk-Forwardindicator-lab 自研了「策略适配性评估」(train/val/test 三段 + 8 项检查)。两条路殊途同归——easy-tdx 的回测引擎很全(滑点/执行仿真/归因/寻优/组合),但**没有任何样本外验证工具**,下游只能自己造。
2. **统一 K 线落盘是第二空白**。easy-tdx 的缓存是碎片化的(股票列表缓存、best_host、进程内 XDXR 字典、扫描 JSON 增量缓存),没有统一磁盘 K 线层;indicator-lab 为此建了 DuckDB 仓库,backtest-system 为此自建 cache/ 目录 + 7 天更新 + 数据自检。
3. **QFQ 质量收到了直接差评**。backtest-system README 明确弃用 easy-tdx 的 QFQ,理由是「茅台出现负价、浦发除权方向算反」,随后自研了板块感知阈值的跳空检测前复权。本地兜底 `mac/adjust.py` 已存在,但缺少对拍验证体系,无法自证可靠。
4. **降低使用门槛有巨大空间**。indicator-lab 的通达信公式解析器(粘贴公式自动识别参数/命名信号)直接命中中国最大的量化用户群体——写惯通达信公式的股民,而 easy-tdx 目前要求写 Python。
---
## 二、借鉴点清单(按价值排序)
| # | 借鉴点 | 来源 | easy-tdx 现状 | 价值 |
|---|--------|------|--------------|------|
| 1 | Walk-Forward 样本外验证(7 窗、每窗独立开仓防跨窗重复计收益) | backtest-system `walkforward.py` | ❌ 无 | ★★★★★ |
| 2 | 策略适配性评估(60/20/20 三段独立回测 + 8 个可解释检查项 + 滚动适配过滤防未来泄漏) | indicator-lab strategy-fitness | ❌ 无 | ★★★★★ |
| 3 | 综合评分 + 一条龙评估(score:收益50/夏普15/回撤10/Sortino5/WF20evaluate:拉数/对齐/选模式/对比基准引擎) | backtest-system `benchmark.py` | ❌ 无 | ★★★★☆ |
| 4 | 通达信公式解析器(`名称:=数值` 参数识别、命名布尔输出作信号、命名数值用于排序/卖出) | indicator-lab | ❌ 无(34 指标需改源码新增) | ★★★★☆ |
| 5 | 本地数据仓库(增量导入、源只读、在线补缺不覆盖、provisional/completed 状态机) | indicator-labDuckDB | ❌ 无统一 K 线磁盘缓存 | ★★★★☆ |
| 6 | 动态组合轮动回测(按指标排序 + 固定槽位等额 + 卖出自动补位 + 日/周/月刷新 + 槽内止盈止损) | indicator-lab portfolio-backtest | ⚠️ 有组合回测/再平衡,但无「排名轮动」模式 | ★★★★☆ |
| 7 | 两段式引擎协议(指标计算缓存 与 信号组合 解耦,迭代快 10 倍) | backtest-system `register_two_stage` | ❌ 优化器每组参数全量重算 | ★★★☆☆ |
| 8 | 多 seed 验证 + 晋级门槛(正收益比例/夏普/WF/交易数四门槛) | backtest-system `engine_iter.py` | ❌ 无 | ★★★☆☆ |
| 9 | QFQ 互检:NONE 原始价 + 向下跳空检测(主板10%/双创20%/北交所30% 阈值) | backtest-system `data_source.py` | ⚠️ 有 XDXR 公式法本地兜底,无对拍 | ★★★☆☆(质量修复) |
| 10 | 真实出场模型:吊灯 ATR14×3 + 保本 BE + 移动止盈 TP、跳空按更差开盘成交 | backtest-system | ⚠️ 有订单/滑点/执行仿真,出场模式较简单 | ★★★☆☆ |
| 11 | 品种感知费率(股票 vs ETF/B 股:最低佣金、印花税差异) | indicator-lab | ⚠️ 有费率参数,非品种感知 | ★★☆☆☆ |
| 12 | 任务体验:进度、失败/跳过摘要、JSON/CSV 导出 | indicator-lab | ❌ 任务仅内存、重启即清、无导出 | ★★★☆☆ |
| 13 | Playwright E2Emock API、不依赖真实数据)+ verify_ci.sh + git hooks | indicator-lab | ❌ 前端无 E2E | ★★☆☆☆ |
| 14 | Docker Compose 部署 | indicator-lab | ❌ 无 | ★★☆☆☆ |
| 15 | 后端数据评级(S-D 五档六维加权,现仅存 web-ui/src/grading 前端 TS | (自补,非下游首创) | ⚠️ 前端有、Python/CLI/REST 无 | ★★★☆☆ |
**不借鉴**:两个项目的回测执行内核(easy-tdx 引擎更全:TWAP/VWAP、Brinson 归因、DSL、缠论桥接);indicator-lab 的 `at_least` 条件组合(`combo.py` 已有 MAJORITY);图表截 220 根方案(前端已有自己方案)。
---
## 三、升级开发计划
### P0 — 信任与持久化(v1.24.0,约 1~2 周)
**目标:先修质量口碑,再谈新功能。**
| 任务 | 内容 | 验收标准 |
|------|------|---------|
| P0-1 QFQ 对拍验证体系 | ① 用 `adjust.py` 公式法与 backtest-system 跳空检测法做双引擎互检,不一致即告警;② 建立「已知除权案例」回归集(茅台/浦发等重度除权股);③ `has_bad_prices` 从兜底升级为所有 QFQ 出口(CLI/Web/unified)的强制门禁,失败自动降级本地重算并标记 | 案例集全过;任何出口不再可能出现负价/方向反转;新增 `tests/test_qfq_crosscheck.py` |
| P0-2 回测任务持久化 | SQLite `~/.easy_tdx/tasks.db`(复用 watchlist.db/strategies.db 模式),任务状态/结果落盘,serve 重启不丢;REST 增加 JSON/CSV 导出端点 | 重启 serve 后 /compare 仍能看历史任务;可下载结果文件 |
| P0-3 真实平均持仓天数 | 去掉 `performance.py``avg_holding_days = 5.0` 的固定值,从成交记录真实统计 | 单测覆盖多笔开平仓场景 |
| P0-4 品种感知费率 | 费率模型按品种区分(股票:佣金万2.5~万3 最低5元+印花税卖出千1;ETF:佣金更低、免印花税;B 股单独口径) | 回测引擎按 symbol 自动套用,可覆盖 |
### P1 — 防过拟合验证链(v1.25.0,约 2~3 周)⭐ 主打版本
**目标:补上两个下游都在自己造的最大空白,让「回测好」升级为「样本外也好」。**
| 任务 | 内容 | 验收标准 |
|------|------|---------|
| P1-1 Walk-Forward 引擎 | 新增 `backtest/walkforward.py`:后 70% 切 N 窗(默认 7)严格样本外,**每窗独立开仓**(防跨窗重复计收益,backtest-system v1.2.1 的教训);输出逐窗收益曲线 + 窗间稳定性指标;接入 CLI `easy-tdx backtest ... --wf` 与 REST `/backtest/wf/run/async` | 与 backtest-system 对齐的窗独立语义;Web 前端展示逐窗柱状图 |
| P1-2 策略综合评分 | `backtest/scoring.py`score_strategy() 0-100 加权(收益 50 / 夏普 15 / 回撤 10 / Sortino 5 / WF 稳定性 20),与前端现有 S-D 评级打通(评级后端化一并完成,见 P2-2 可提前) | CLI/Web 均输出评分与分项 |
| P1-3 适配性评估 | `backtest/fitness.py`train/valid/test(默认 60/20/20)三段独立回测 + 可解释检查项(收益一致性、回撤一致性、交易数充分性、胜率区间、参数敏感性等 8 项),≥75% 通过且样本达标 → 「高适配」标记;支持**滚动适配过滤**(仅用早于当天的已平仓数据,杜绝未来数据泄漏) | Web 策略库/对比页显示适配徽章;可解释报告 |
| P1-4 一条龙评估 | `evaluate_strategy()`:默认随机抽样股票池(固定 seed 可复现)→ 对齐 → 自动选出场模式 → 与基准引擎(买入持有 + MyTT MACD)同规则对比 | 一条命令出完整对比报告 |
| P1-5 两段式寻优加速 | 优化器支持指标缓存复用:参数只影响信号组合层时,指标层计算一次(backtest-system 实测快 10 倍) | 网格寻优基准测试提速 ≥3 倍 |
| P1-6 多 seed 验证 + 晋级门槛 | `run-all` / 优化器输出增加多随机种子组合验证;晋级门槛四项(正收益比例/夏普/WF/交易数)可配置 | 报告含跨 seed 稳定性列 |
### P2 — 本地数据仓库(v1.26.0,约 2~3 周)
**目标:把碎片化缓存升级为统一数据底座,服务全市场扫描/因子/回测的提速。**
| 任务 | 内容 | 验收标准 |
|------|------|---------|
| P2-1 K 线仓库 | 新增 `warehouse/` 模块(存储引擎选 DuckDB,零服务、列存、SQL 友好):`easy-tdx warehouse sync`(全量/增量)、源只读、在线补缺不覆盖、按品种价格/成交量系数;**provisional 状态机**15:05 前的今日数据标记临时,筛选/回测默认忽略,收盘后转 completed) | 二次 sync 增量;断网可用;screen/factor/pfactor 可切 `--source warehouse` |
| P2-2 评级后端化 | `web-ui/src/grading/`engine.ts/thresholds.ts)移植为 Python `backtest/grading.py`CLI `--grade`、REST 返回 grade 字段;前端改为消费后端结果(保留前端兜底) | API/CLI 输出 S-D;与前端旧实现结果一致率 100%(对拍单测) |
| P2-3 仓库健康自检 | 数据自检命令:缺口检测、异常跳变检测(复用 P0-1 跳空检测)、最新度报告 | `easy-tdx warehouse check` |
### P3 — 公式与轮动(v1.27.0,约 3~4 周)
**目标:把「写通达信公式」的庞大用户群接进来。**
| 任务 | 内容 | 验收标准 |
|------|------|---------|
| P3-1 通达信公式解析器 | `indicator/formula.py`:解析通达信/麦语言公式,自动识别 `名称:=数值` 参数、命名布尔输出→信号、命名数值→排序/排序卖出字段;内置函数映射到 MyTT;安全除零、无未来数据、数据不足跳过 | 一批典型公式(含用户常见主力/洗盘类指标)解析通过并可直接回测 |
| P3-2 公式三通道接入 | CLI `easy-tdx formula screen/backtest`、REST `/formula/compute`、Web 新页面(粘贴公式 → 选股/回测一体) | 三通道行为一致 |
| P3-3 轮动组合引擎 | `backtest/rotation.py`:按指标排序选股 + 固定槽位等额 + 卖出自动补位 + 日/周/月刷新 + 槽内止盈止损/指标阈值卖出/指标比较卖出 | CLI/REST/Web 均可跑;与单标的回测同一套绩效输出 |
### P4 — 工程化(滚动进行)
| 任务 | 内容 |
|------|------|
| P4-1 Playwright E2E | mock API 的前端 E2E(不依赖真实行情/网络),纳入 CI |
| P4-2 WebSocket 实时联动 | `/ws/realtime/{symbol}` 接通 `realtime/EventBus`(README 已自认未联动;两个下游都没碰实时,这是 easy-tdx 的独有优势区,应当做实) |
| P4-3 Docker Compose | 一键起 serve + Web UI 的部署方案 |
| P4-4 verify_ci 风格脚本 | 一条命令跑完 ruff/mypy/pytest/前端 typecheck+build/E2E,可安装 git hooks |
---
## 四、版本节奏与依赖关系
```
v1.24.0 (P0) ──→ v1.25.0 (P1 防过拟合链,依赖 P0-4 品种费率)
└→ v1.26.0 (P2 数据仓库,与 P1 可并行启动,P2-2 建议提前到 P1 一起做)
└→ v1.27.0 (P3 公式+轮动,依赖 P2-1 仓库提速全市场公式选股)
P4 工程化滚动穿插。
```
**成功指标**(对外可宣传):
- v1.25 后:官方提供 WF + 适配性双验证,下游不再需要自造防过拟合轮子;
- v1.26 后:下游不再需要自建数据层(backtest-system 的 cache/、indicator-lab 的 DuckDB 均可换成 easy-tdx 仓库);
- v1.27 后:通达信公式用户零代码进入回测。
---
## 五、风险与注意
1. **P3 公式解析器工作量大**:通达信公式方言庞杂(函数集、隐式循环语义),建议首版只支持「日期序列 + 常用函数白名单」,明确不支持清单,渐进扩充。indicator-lab 的实现可作参考(注意其 AGPL 许可——**只看思路不抄代码**,避免传染)。
2. **DuckDB 引入新增运行时依赖**:当前核心依赖仅 3 个是卖点。建议放入 optional-dependencies `[warehouse]` 组,import 惰性加载。
3. **WF 每窗独立开仓**是 backtest-system 踩过的坑(v1.2.1 修复),实现时直接采用正确语义,勿重蹈覆辙。
4. **向后兼容**:新增能力全部走可选参数/可选依赖,默认行为不变;v1.24 的 QFQ 门禁若触发降级,需在输出中显式标记(grade 字段),不静默。