docs: 同步操作说明/架构/路线图(归档操作、图表基座、数据库目标硬约束)

- USAGE 新增 §6.3.1「归档的日常操作」:查看 / 筛选(回写 URL)/ 导出完整 JSON /
  以此参数再跑 / 删除(写明「删除即失去结果,结果只存归档一份」)/
  历史归档用 restore_experiment_from_job 按原 id 重建;并说明归档完整度如何标注
- USAGE/README 更正技术栈与图表基座:TradingView Lightweight Charts 4.2.3 为唯一
  图表基座(ECharts 已从 package.json、pnpm-lock.yaml、node_modules、文档与
  架构图标注中全部清除),并记录实测证据(个股页图表根节点为
  div.tv-lightweight-charts,页面 canvas 无一来自其它图表库)
- ARCHITECTURE 更正「当前数据库」(原写 SQLite/未来 MySQL):现为本机 MariaDB 10.11,
  §6 补目标库硬约束;USAGE 补服务器身份与实测连接证据
- AGENT.md 新增 §0.1:数据库目标只允许本机 MariaDB,禁止 192.168.1.10,
  由 config.py::assert_db_target_allowed 硬拦截(命中直接抛错,不静默降级)
- DEV_PLAN_DIVIDEND_BACKTEST 记录三轮实施与验证、归档恢复边界(§12.5)、已知限制
- DEV_PLAN v2/v3 标注为历史记录(避免把当时的远端库地址当现状照抄);
  ROADMAP 更正 M3 图表选型
This commit is contained in:
Simon
2026-09-20 07:31:20 +08:00
parent 23972e7063
commit 82240e383d
12 changed files with 1405 additions and 47 deletions
+43 -11
View File
@@ -3,8 +3,10 @@
> 版本:v1.0
> 定位:个人开发、A股、中低频选股/回测、AI Agent 二次开发
> 数据源优先级:Tushare > 新浪财经
> 当前数据库:SQLite
> 未来数据库:MySQL
> 当前数据库:**本机 MariaDB 10.11(`127.0.0.1:3306/qlib`)**
> 数据库目标约束:**只允许本机**;`192.168.1.10` 已禁止作为 DB 目标,由
> `app/core/config.py::assert_db_target_allowed` 在解析配置时硬拦截(见 `AGENT.md` §0.1)
> 历史:SQLite(`data/quant.db`)→ 远端 MySQL → 本机 MariaDB(逐表一致副本)
> 核心量化引擎:Qlib
> 前端:React / Next.js
> 后端:FastAPI + Python
@@ -269,6 +271,13 @@ TushareClient
# 6. 数据库设计
> **目标库约束(硬性)**:一律 `127.0.0.1:3306/qlib`(本机 MariaDB 10.11)。
> `192.168.1.10` 禁止作为数据库目标 —— 连错库不会报错、界面也正常,却会把回测/归档/策略
> 静默写到另一台机器上,属于最难发现的一类故障。守卫在 `get_settings()` 里执行:
> 命中禁用主机直接抛错(应用起不来),禁用列表可用 `QLIB_FORBIDDEN_DB_HOSTS` 覆盖。
> 启动日志会打印 `数据库目标:mysql qlib@127.0.0.1:3306/qlib`(不含密码),便于随时确认。
## 6.1 SQLite 定位
SQLite 用于:
@@ -385,11 +394,16 @@ index
index_daily
trading_calendar
suspend_data
stock_st_data
suspend_data # ⚠️ 未实现(停牌以「当日无行情」近似,结果页如实标注)
stock_st_data # → 由 stock_name_history(tushare namechange)落地时点 ST 判定
financial_indicator
income_statement
# ---- 后续增量(已落地,见 docs/DEV_PLAN_DIVIDEND_BACKTEST.md §10)----
daily_basic # 每日指标:dv_ratio/dv_ttm 股息率、PE/PB、市值(高股息选股)
stock_name_history # 名称生效区间:exclude_st 的**时点**口径(股息陷阱可见)
balance_sheet
cashflow_statement
@@ -552,17 +566,35 @@ Qlib Adapter
# 12. 前端结构
第一阶段:
第一阶段(**已实现**,侧栏按研究闭环分组):
```text
Dashboard
股票池
因子研究
选股
回测
Experiment
研究 总览 / 股票池 / 股票筛选
策略 策略库 / 选股回测 / 实验对比
因子与信号 因子研究 / 因子组合 / 交易信号
数据 数据同步 / 数据管理
```
## 12.1 表现层约定(本轮定型)
| 约定 | 取值 | 理由 |
|---|---|---|
| 图表库 | **TradingView Lightweight Charts**(唯一) | 轻量(~45KB)、原生支持「在 series 上打买卖点标记」,金融图表交互(十字光标/缩放)开箱可用;ECharts 已下线(依赖已移除),避免两套图表基座带来的样式与交互分裂 |
| 图表基座 | `components/charts/LwChart.tsx` | 折线/面积/柱状 + 标记 + tooltip + 可点击图例由一个组件承载;**chart 实例只在结构变化时重建**,数据变化只 `setData`,避免每次刷新重建 canvas |
| 主题 | `components/charts/theme.ts` | 颜色/数值格式集中定义(涨绿跌红按 A 股习惯),组件内不出现硬编码色值 |
| 标记约束 | 标记时间必须存在于对应 series 且**升序** | Lightweight Charts 硬约束:不满足会整组标记丢失。`LwChart` 内统一做「过滤到已有时间点 + 排序」,页面只负责给语义(BUY/SELL) |
| 股票标识 | `SymbolLink`(`lib/symbols.tsx`) | 「有代码必有名称」是产品要求:后端填充 `name`(权威),前端 `GET /api/stocks/names` 缓存兜底;名称缺失显示「—」,**不猜不造**(§7 无静默行为) |
| 参数模型 | `components/StrategyParamsForm.tsx` 单一 `StrategyParams` | 策略库/回测/直通入口共用同一参数模型与校验,避免三处各自维护字段(§6 依赖抽象) |
| 策略说明 | `StrategyDoc`(后端 `describe_strategy` 推导) | 说明与公式**由 spec 真实推导**而非前端手写模板:参数一改,公式同步变;引擎未建模处进 `warnings` 如实暴露(§7/§24) |
| 结果视图 | `components/BacktestResultView.tsx`(回测页与归档页**共用**) | 「刚跑完」和「翻回来看」必须是同一套图表与表格;两处各写一套必然漂移成「归档里少一张图」 |
| 归档页 | `/experiments/{id}` 为 **Server Component**(`app/experiments/[id]/page.tsx`) | 归档是只读内容:选股条件/执行依据/元数据必须服务端直出(客户端渲染时 SSR HTML 里连「选股条件」都搜不到);交互(删除/导出/折叠 spec)隔离在 `components/ArchiveActions.tsx` |
| 归档口径说明 | 归档页顶部「选股条件」+「交易执行依据」两块,取自**归档内 spec** | 说明必须与那次执行一致,不能读当前页面状态(否则「看归档」会看到今天的参数);字段逐项对应引擎实执行语义,不写泛泛的模板话 |
| 归档列表分页 | body 保持 `list[...]`,总数放 `X-Total-Count` 响应头 | 不破坏既有前端契约,同时消除「硬编码 limit=50 静默截断」(§7):前端据此显示「显示 N 条 / 共 M 条」 |
> 前端**只**依赖 `/api/*` 的 Domain 结构(§3.2):`name` 由后端填充而不是前端反查数据库,
> 图表库可替换而不影响领域层,`/backtest` 的三种入口(策略/选股/实验)都只是把 URL 参数
> 映射成同一个 `StrategyParams`。
第二阶段:
```text