Files
qlib/docs/DEV_PLAN_v2.md
T
Simon 0ffd574f30 docs: 下阶段开发计划(架构 v2 落地 M6-M8)+ MySQL 迁移文档同步
- docs/DEV_PLAN_v2.md:基于 ARCHITECTURE_v2 与 M0-M5 现状的下一阶段计划
  (M-DB 迁移收尾 → M6 因子定义入库/复合因子/口径修复 → M7 Selection/Signal/
  Portfolio 引擎分层 → M8 Strategy 平台化/Web 做实/Agent 工具补齐;含本机 Redis
  127.0.0.1:6379 的接入触发点与执行顺序)
- ROADMAP.md:登记 M-DB 里程碑并指向 DEV_PLAN_v2
- USAGE.md / README.md:数据库描述由 SQLite 更新为 MySQL(config.yaml database.mysql)
2026-09-08 23:58:51 +08:00

16 KiB
Raw Blame History

下阶段开发计划(架构 v2 落地 · 2026-09)

依据:ARCHITECTURE_v2.md(新架构 v2)、AGENT.md(开发约束)、 两份 2026-09 只读调研(后端研究/量化层、前端/Agent/数据层)与 docs/ROADMAP.md 的 M0–M5 记录。 本文件回答:M5(AI Agent Phase 5)之后,下一阶段做什么、按什么顺序做。


0. 当前状态与总判断

已完成(M0–M5):数据层(Tushare 首选 + 新浪兜底 + 审计)→ ResearchSpec → 本地研究引擎 (9 个行情因子 / IC·分层评估 / 低频 TopN 等权回测)→ Job/Experiment 异步归档 → Web 六页 → AI Agent(6 个受控 Tool)。数据库已于 2026-09 从 SQLite 全量迁移至 MySQL(见 §5)。

对照 v2 的核心差距(调研结论):

  1. 研究是一条"单行道":ResearchSpec → 取数 → 因子 → TopN 回测 一次性跑完; v2 强调的 Factor Research / Composite Factor / Selection / Signal / Portfolio 分层尚未拆分, "选股"只是回测器内部逻辑,无法单独回答 v2 §8 的两个问题: 「2023-08-15 为什么选这只股票」「2026-09-08 当前有哪些股票满足策略」。
  2. 因子定义 / 策略等研究元数据未入库:DB 只有 8 张表 (stock / stock_daily / adjust_factor / financial_indicator / trading_calendar / sync_log / job / experiment), v2 §8 期望的 factor_definition / factor_test / factor_composite / universe / selection_rule / signal_rule / strategy / portfolio 等全缺;factor_test 与回测结果只以 Experiment 的 result_json 快照存在。
  3. 口径与数据完整性风险待修:研究链路不消费复权因子(stock_daily 混合 tushare 不复权与新浪前复权行); universe 用"当前名称含 ST"近似、无历史成分/停牌;Job.stage 从未赋值、SSE 是查库轮询。
  4. 前端/Agent 待做实:Selection/Signal 页面不存在;因子组合页无持久化实体;回测结果字段大量未渲染; Agent 工具仅 6 个,v2 §24 期望的 screen_stocks / explain_selection / generate_signals / create_strategy / create_composite_factor 等依赖尚未存在的引擎。

阶段命名延续 ROADMAP:M6 研究层落地 → M7 引擎分层 → M8 平台化与 Agent 增强。 数据库专项单独记 M-DB。


1. M-DB:数据库 MySQL 迁移(已完成,本文件记录收尾项)

已交付(2026-09):

  • MySQL(192.168.1.10:3306,MariaDB 10.11,库 qlib,utf8mb4)建 8 张业务表 + alembic_version, 全部经 alembic upgrade head(迁移 e4d18825…53113c80…91c4e27a…d3f6c9a2),结构由既有 ORM 模型保证。
  • scripts/migrate_sqlite_to_mysql.py:一次性工具 —— sqlite 直连 + pymysql chunk 多值 INSERT + keyset 分页续传 + 幂等(已迁则跳过)+ --verify-only 逐表 COUNT 与抽样比对;支持 --only <表> 并行大表。
  • 配置:config.yaml → database.mysql(host/port/db/user/charset 明文),密码经 .env 的 MYSQL_PASSWORD(AGENT.md §33:密钥不进 config/git);URL 优先级 DATABASE_URL 环境变量 > config.yaml database.mysql > sqlite:///./data/quant.db 兜底; 实现集中在 backend/app/core/config.py::_build_mysql_url,业务层零改动(DAO/Repository 隔离兑现)。
  • 测试隔离:backend/tests/conftest.py 强制每进程 /tmp/qlib-pytest-<pid>.db SQLite(测试绝不触 MySQL)。
  • 驱动:pymysql>=1.1 已入 backend/pyproject.toml。

遗留收尾(小任务,可随时做):

项 说明 建议
job/experiment.result_json 用 MySQL TEXT(≤65,535B) SQLite TEXT 无上限、测试测不出 日级回测结果变长后改 MEDIUMTEXT(新 Alembic 迁移 + Model 类型 variant)
Repository 批量 upsert 在 MySQL 的压测 tuple_.in_() 行值、add_all 单事务无分块 全市场日线增量同步跑一次,观察锁等待/包大小
MySQL 路径无自动化测试 测试全 SQLite 方言 视需要加一个「连 MySQL 的集成冒烟」开关(默认关,显式 env 开启)
scripts/migrate_sqlite_to_mysql.py 属一次性工具 保留供重建目标库 文档标注不可再对生产执行(除 --verify-only)
前端/文档残留 "SQLite" 文案 app-shell / page.tsx / sync.py docstring 随各页面改动顺手清理

2. 下阶段总路线

M6  研究层落地     因子元数据入库 + 复合因子模块 + 口径修复
     ↓
M7  引擎分层       Selection Engine → Signal Engine → Portfolio Engine
     ↓
M8  平台化         Strategy 模型 + /api/strategies + Agent 增强 + 页面做实

设计红线(贯穿):v2 §25「历史回测与当前选股用同一套 Engine」、§26 Experiment 可复现、 AGENT.md「简单优先 / 每阶段可运行 / 一个功能一个 commit / 先 Domain 后 UI / 带测试」。


3. M6:研究层落地(因子目录、复合因子、口径)

目标:把"因子"从代码注册表变成可入库、可版本化、可组合的研究资产,并修掉混合口径风险。 本阶段只做研究和评估能力,不引入选股/信号新概念 —— 避免一次改动跨太多层。

3.1 因子定义入库 + 版本化目录

  • Domain:FactorDefinition(name/description/formula/input_data/frequency/lookback/direction/ normalization/neutralization/availability_rule/version/requires…);FactorDefinitionRepository(Protocol)。
  • Infra:Model factor_definition → Alembic → Repo;注册表 seeding:把 quant/factors.py 现有 9 个 内置因子的元数据灌库(一次性 seed 脚本或 sync factors CLI 子命令),代码仅保留计算函数映射 (name → compute)。
  • API:GET /api/factors 改读库;POST/PUT /api/factors(管理员自定义因子元数据,计算待 M6.3 表达式引擎)。
  • 验收:迁移测试通过;/api/factors 展示入库元数据;未知因子抛 FactorError; 现有因子研究 Job 结果与改动前一致(回归)。

3.2 Composite Factor Engine 模块化

  • 现状:composite_score 内联在 local_engine(截面 zscore × 方向 × 权重 求和)。
  • 目标:抽出独立模块 quant/composite.py:CompositeSpec{components[{name,weight,direction}], method} → 输出 score 面板(先固定权重 + zscore;Rank/Z/IC 加权留接口,不提前实现)。
  • Model 表 factor_composite(+factor_composite_component) 落库(供保存/复用)。
  • 回测/因子测试改调同一 composite_score 函数。
  • 验收:与现有默认 spec 的回测结果逐项一致的回归测试;API GET/POST /api/composites CRUD。

3.3 研究读取口径修复(横切前置,建议最先做)

  • 决策:研究行情统一为不复权 close 为主口径,凡需除权处理处显式声明; 或在 Repository 读路径按 source/adjust 过滤/提供 qfq 查询(利用 adjust_factor 前复权)。
  • ResearchSpec 增加 price_adjustment 字段并在 API/结果 config_snapshot 显式记录口径。
  • 验收:同一只含新浪补缺行的股票,回测口径一致且 config_snapshot 可溯源; 文档声明口径;对现有结果差异给出解释(如有)。

3.4 因子测试结果结构化(可选,如时间紧可并入 M8)

  • Model factor_test(结果结构化落库,替代只存 result_json);factor_test 多因子 spec 不再静默只测第一个。

4. M7:引擎分层(Selection → Signal → Portfolio)

目标:把回测器里的"选股/买卖/仓位"逻辑拆成 v2 定义的独立引擎, 让当前选股与历史回测共用同一套代码(v2 §25 一致性红线)。

4.1 Selection Engine(先做)

  • Domain:SelectionResult{as_of_date, symbol, rank, score, factor_values, filter_status, selection_reason} 与用例 select(spec, as_of)(可对任意历史/当前日期执行)。
  • 三种模式中先落地 A(条件选股:ROE/PE/涨跌幅等条件表达式)+ B(因子评分 TopN/Top%); 模式 C(模型预测)留待 Qlib 模型链路(M8.3)。
  • TopKBacktestRunner._rebalance 改为消费 Selection 结果(同一引擎)。
  • Model:selection_result / selection_snapshot(as_of、spec 快照、结果)。API:POST /api/selections (提交即算)与 GET /api/selections/{id}。
  • 验收(v2 §27):select(as_of=历史日) 与该日回测调仓选股逐 symbol 一致的测试; API 可查"任意日 TopN 与理由";SelectionResult 成为前后端标准化 DTO。

4.2 Signal Engine(规则型)

  • Domain:SignalRule / SignalEvent{signal_date, symbol, signal_type(BUY/SELL/HOLD/WATCH), trigger_reason, score, price};规则引擎执行"分数阈值 + 技术条件 + 市场状态"组合。
  • Model:signal_rule / signal_event;回测与选股都能产事件并落库。
  • API:POST /api/signals、GET /api/signals/history。
  • 验收:能回答「某策略 2023-08-15 为什么对这只股票给 BUY/SELL」;与回测 signal_history 同引擎(一致性测试)。

4.3 Portfolio Engine

  • 把回测器 _rebalance 的资金/仓位逻辑抽为 portfolio 模块:weighting(等权起步)、 单股/行业上限、现金管理;约束默认关闭并在结果 unimplemented 如实标注。
  • Model:portfolio / portfolio_position(可选,先服务回测即可,不提前建表)。
  • 验收:默认配置下回测数值与现实现一致;新约束开关正确进入 config_snapshot/unimplemented。

4.4 Universe 规则化(横切,可与 4.1 并行)

  • Model universe / universe_rule + 规则执行器(把 filter_stocks 的 exclude_st/min_listing_days/ market 规则化入库并补 exclude_suspended 的显式处理或 unimplemented); 预留 index_constituent_history(历史成分,防幸存者偏差)。
  • 验收:universe 可持久化、被 Spec 引用后结果与现有一致;文档声明 ST 快照近似。

5. M8:平台化与增强(Strategy / Agent / Web / 基础设施)

5.1 Strategy 模型与 /api/strategies

  • Domain:Strategy 聚合 universe + factors/composite + selection + signal + portfolio + rebalance; ResearchSpec 可由 strategy 展开。Model strategy(+子表或 JSON 明细);API CRUD。
  • Experiment 归档时记录 strategy_version;Agent 增加 create_strategy Tool(受控白名单)。
  • 验收:Agent「建立策略 X」→ 策略入库 → 回测 → Experiment 带 strategy_version 可复跑一致。

5.2 Web 页面做实(前端主线,与 M6–M8 后端里程碑并行推进)

  • 优先:回测页做实(零新后端 API):渲染 trades 明细/分年度收益/持仓演化/成本参数表单/config_snapshot, lib/types.ts 补全 Trade entry/exit_price、FactorTestReport.factor_name 等缺失字段, Experiment 类型收编进 lib/types.ts(result 改联合类型)。
  • 因子研究做实:IC 时序折线、因子横向对比(数据来自既有 DTO 扩展)。
  • Selection 页(新路由):M7.1 后端就绪后,选当前/历史日 → SelectionResult 表 + 一键跳回测。
  • Signal 页(新路由):M7.2 后端就绪后,信号时间线与理由、风险标志。
  • Job 进度 UI 切换 SSE(需先给执行器补 stage 上报,见 §6)。
  • 每页验收:tsc --noEmit 通过、无未渲染的标准字段、无 SQLite 字样残留。

5.3 Qlib 模型链路(模型选股 Selection 模式 C 的前置,按需)

  • qlib_adapter/feature.py Alpha158 特征 + model.py LightGBM walk-forward(seed 固定); 输出预测分 → Selection 模式 C。作为可选增强,不阻塞 M6–M8 主干。

5.4 AI Agent 工具补齐(依赖 M6/M7/M8.1 引擎)

  • 在引擎就绪后逐个补齐 v2 §24 工具:inspect_factor / create_composite_factor / screen_stocks / explain_selection / generate_signals / create_strategy / get_backtest_result / create_experiment; 每个工具经白名单 + Job/Experiment 链路(不直接写库)。
  • 前端加一个最小 AI 对话入口(后端 /api/agent/chat 已有)—— 可与 M8.2 任意页面里程碑合并。

6. 基础设施专项(含本机 Redis 的定位)

本机已探测:Redis 服务在 127.0.0.1:6379 正常响应(无 redis-cli,连接经 socket 验证)。

v2 §22 与 AGENT.md §19/§38 的原则是"第一版不引复杂队列;复杂后再引入 Redis + Celery/RQ"。 据此把 Redis 放入明确的触发点而非一开始就用:

触发场景 Redis 用途 何时启用
Job 并发/排队:subprocess 双并发上限开始频繁打满、丢任务需可恢复队列 RQ/普通队列替代 FastAPI BackgroundTasks 调度 M8 之后 / 出现排队丢失问题
Job 细粒度 stage + SSE 长连:executor 每阶段写 stage 后广播 Redis pub/sub 做 SSE 事件总线(替代 0.4s 查库轮询) M8.2 前端切 SSE 时(可先行)
行情/因子查询热点:全市场研究重复预热 因子结果 / 最新交易日缓存(key 带 as_of 失效) 研究链路稳定后按 profile 决定

近期只需做一件准备工作:config.yaml 预留 redis.url_env: "REDIS_URL" + 可选 redis.url: "redis://127.0.0.1:6379/0" 配置段,代码不改;真正启用时再落基础设施代码。

其余基础设施待办(低优先):Job cancelled 取消 API 与 /api/jobs 列表端点;executor 增加 stage 上报(data_loading/factor_calculation/backtesting…)——这是前端做 SSE 进度条的前提。


7. 建议的执行顺序(前 6 个 commit 序列)

按 AGENT.md「最小修改、每阶段可跑、一功能一 commit」,给 M6 起步的推荐顺序:

  1. M6.3 口径修复(横切前置,改动小收益大):Repository 读路径按 source/adjust 过滤 + ResearchSpec 口径字段 + 文档。验收:混合行场景回测口径一致。
  2. M6.1 因子定义入库:Model+迁移+seed+GET /api/factors 读库。验收:迁移测试 + 回归。
  3. M6.2 Composite Engine 模块化:quant/composite.py + 回测改调 + factor_composite 表 CRUD。 验收:默认 spec 回测结果逐项一致的回归测试。
  4. M7.4 Universe 规则化:universe/universe_rule 表 + 执行器(结果与现有一致)。可与 2/3 并行。
  5. M7.1 Selection Engine:select(spec, as_of) + TopK 回测改消费 Selection + selection_result/snapshot 表 + API。验收:v2 §27 历史日一致测试。
  6. M7.2 Signal Engine:规则 + signal_event 落库 + API(回测/选股同引擎)。

之后进入 M8(Strategy 模型 → Web 页面做实 → Agent 工具补齐)与 §6 基础设施专项。

每步都遵循:Domain → Repository Protocol → Infra(Model→Migration→Repo) → Service → API → 前端 → 测试(相关模块)→ 更新文档;新增表一律 Model→Alembic→测试。


8. 风险清单(开发中持续检查)

  • 历史一致性:Selection/Backtest 拆分后默认结果必须与拆分前一致(用回归测试锁住,别让重构悄悄改策略语义)。
  • 未来函数 / 幸存者偏差:universe 的 ST/行业/成分历史口径补齐前,回测文档须明示近似; 财务数据始终按 announce_date 可见(已有表键支持)。
  • MySQL 行为差异:TEXT 上限、批量 upsert 锁等待、pymysql 流式读取 —— 见 §1 遗留收尾表。
  • 不要提前堆量:M6 阶段不引入模型选股/ML;M7 不做多因子合成优化;M8 的 Qlib 模型链路按需推进。
  • 前端契约:SelectionResult/SignalResult 先定 DTO(后端 entity)再画页面,避免前后端口径漂移。