docs: 同步「买卖理由 / 因子曲线 / 曲线放大 / 作业反馈」与门禁条数
- §6.3 新增两块说明:①回测结果的买卖理由(封闭词表、成交与未成交都覆盖、
区分跌出 TopN / 不在候选池 / 全量换仓 / Tmin / Tmax / 涨跌停 / 现金不足)、
因子曲线口径(持仓市值加权原始值、空仓不落点、带方向与单位)、
`/charts/{id}?s=...` 放大页(Server Component,数据从归档直出,未归档不给假按钮);
②全站统一的作业反馈(useJobRunner + JobProgress:提交瞬间有字、已用每秒自增、
可取消、失败给后端原文、成功给归档入口、自动滚入视野)。
- 门禁条数更新为 524;回测结果契约脚本补充「理由词表/名次/因子值/因子曲线」断言说明;
列出新增的两个理由测试文件。
This commit is contained in:
+43
-4
@@ -508,6 +508,33 @@ PYTHONPATH=. .venv/bin/python -m app.cli.restore_experiment_from_job \
|
|||||||
**归档完整度会明示**:归档页顶部标注「归档完整 N/N」;若曲线因体积预算被裁剪,或该快照产生于
|
**归档完整度会明示**:归档页顶部标注「归档完整 N/N」;若曲线因体积预算被裁剪,或该快照产生于
|
||||||
完整存档上线之前(个股曲线只有 60 只),页面直接显示「**归档不完整**」并给出差异与「以此参数重跑」入口。
|
完整存档上线之前(个股曲线只有 60 只),页面直接显示「**归档不完整**」并给出差异与「以此参数重跑」入口。
|
||||||
|
|
||||||
|
> **买卖理由 + 因子曲线 + 曲线放大**(2026-10):回测结果不再只给「成交了哪些」,
|
||||||
|
> 而是回答「**为什么买 / 为什么卖**」,且数字全部来自引擎当时的计算:
|
||||||
|
> - `ActionRecord.reason`(`TradeReason{code,text,data}`)覆盖**成交与未成交**的每个买卖点:
|
||||||
|
> 名次 / 候选数 / 综合分 / 各因子**原始值** / 持有交易日 / 现金预算 / 涨停比值…;
|
||||||
|
> 原因分类是封闭词表(`quant/trade_reasons.py`),组合引擎与单策略引擎共用同一套构造器,
|
||||||
|
> 两个引擎对同一件事不会写出两种说法。
|
||||||
|
> - 区分「**跌出 TopN**」「**不在候选池**(被股票池/条件过滤,如转 ST)」「**全量换仓**」
|
||||||
|
> (单策略引擎每次调仓先清仓再建仓,被卖出的股票可能仍排在 TopN 内,这时不能写「跌出 TopN」)
|
||||||
|
> 「**Tmin 保护暂留**」「**超 Tmax 强制了结**」「涨停/停牌/现金不足/不足最低佣金」。
|
||||||
|
> - `result.factor_curves`:每个策略因子一条曲线 = 当日**持仓按市值加权平均的原始值**
|
||||||
|
> (不做 z-score、不按方向取反,**空仓日不落点、不插值、不用 0 填充**),带
|
||||||
|
> `label / direction / unit`,界面据此写明口径(如「股息率 %」。收益曲线对照成交日,
|
||||||
|
> 一眼看出「买在什么水平、卖在什么水平」)。
|
||||||
|
> - **每条曲线都能新页面放大**:`/charts/{归档id}?s={equity|drawdown|factor:<name>|sym:<code>|monthly}`。
|
||||||
|
> 放大页是 Server Component,数据从**归档**直出(URL 可分享、刷新还原同一张图);
|
||||||
|
> 结果没归档时不显示假按钮,而是写明「未归档,无法放大」。
|
||||||
|
> 数字格式与后端 `f"{v:.4f}"` 同规则(四舍六入五成双),避免同一个综合分在理由原文与
|
||||||
|
> 数字标签里显示成两个数。
|
||||||
|
|
||||||
|
> **作业反馈(全站统一)**(2026-10):`lib/jobs.ts` 的 `useJobRunner` + `components/JobProgress.tsx`。
|
||||||
|
> 解决的问题是用户原话「点了回测没有任何反馈,不清楚是不是已经开始」:
|
||||||
|
> **提交瞬间**就显示「排队中 + 作业号 + 发起时间」,**已用时间每秒自增**(不等后端报新阶段),
|
||||||
|
> 阶段取后端真实 `stage`,排队/运行中可**取消任务**(`POST /jobs/{id}/cancel`),
|
||||||
|
> 失败显示后端原文、成功给「打开归档 / 去对比」;反馈条出现时自动滚入视野
|
||||||
|
> (运行按钮常在长表单底部,不滚过去等于没显示),并带 `role="status" aria-live="polite"`。
|
||||||
|
> 各页多个作业互不干扰(各自 `anchorId`)。
|
||||||
|
|
||||||
**图表**:全站统一使用 **TradingView Lightweight Charts**(`components/charts/LwChart.tsx`),
|
**图表**:全站统一使用 **TradingView Lightweight Charts**(`components/charts/LwChart.tsx`),
|
||||||
ECharts 已从依赖中移除。买卖点标记(▲绿=买入 / ▼红=卖出)只落在该 series 真实存在的交易日上,
|
ECharts 已从依赖中移除。买卖点标记(▲绿=买入 / ▼红=卖出)只落在该 series 真实存在的交易日上,
|
||||||
并按时间升序提交(Lightweight Charts 的硬约束),因此不会出现标记丢失或错位。
|
并按时间升序提交(Lightweight Charts 的硬约束),因此不会出现标记丢失或错位。
|
||||||
@@ -524,6 +551,16 @@ cd backend && PYTHONPATH=. .venv/bin/python ../scripts/verify_strategy_workspace
|
|||||||
# 只验接口与页面(跳过回测 Job):加 --skip-job
|
# 只验接口与页面(跳过回测 Job):加 --skip-job
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**回测结果契约**(跑一次真实区间,约 3 分钟;校验页面实际读取的每个字段):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend && PYTHONPATH=. .venv/bin/python ../scripts/verify_backtest_page_contract.py --end 2023-12-31
|
||||||
|
```
|
||||||
|
|
||||||
|
它除了净值/个股曲线/买卖点落点,还会断言:**每个买卖点都有结构化理由且原因代码在词表内**、
|
||||||
|
成交类理由带名次/候选数/综合分/因子原始值、`trades` 两端理由齐全、`factor_curves` 非空且
|
||||||
|
日期升序无重复 —— 也就是「买了什么原因、图上的因子曲线」这些字段真的在。
|
||||||
|
|
||||||
#### 6.3.2 界面规范与对齐自检(控件尺寸 / 输入友好)
|
#### 6.3.2 界面规范与对齐自检(控件尺寸 / 输入友好)
|
||||||
|
|
||||||
界面不是"能看就行":控件错位、尺寸与内容不匹配、点不中、报错说不清,都会直接变成操作错误。
|
界面不是"能看就行":控件错位、尺寸与内容不匹配、点不中、报错说不清,都会直接变成操作错误。
|
||||||
@@ -625,12 +662,12 @@ Agent 能力边界(10 个内置受控工具,只读 + 受控写库):
|
|||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
uv run ruff check app tests && uv run ruff format --check app tests
|
uv run ruff check app tests && uv run ruff format --check app tests
|
||||||
uv run pytest # 全量测试(每个里程碑提交前均须通过,当前 500 条)
|
uv run pytest # 全量测试(每个里程碑提交前均须通过,当前 524 条)
|
||||||
|
|
||||||
cd frontend/web
|
cd frontend/web
|
||||||
pnpm run typecheck # tsc --noEmit,0 error
|
pnpm run typecheck # tsc --noEmit,0 error
|
||||||
pnpm run test:charts # 图表标记逻辑单测(7 条,node --test,无需额外依赖)
|
pnpm run test:charts # 图表标记逻辑单测(7 条,node --test,无需额外依赖)
|
||||||
pnpm run build # 13 条路由,含 /strategies /backtest /experiments /experiments/[id]
|
pnpm run build # 路由含 /strategies /backtest /experiments /experiments/[id] /charts/[id]
|
||||||
```
|
```
|
||||||
|
|
||||||
**端到端契约脚本**(会真实提交回测 Job,用于验证「页面实现」与「后端字段」不漂移):
|
**端到端契约脚本**(会真实提交回测 Job,用于验证「页面实现」与「后端字段」不漂移):
|
||||||
@@ -638,7 +675,7 @@ pnpm run build # 13 条路由,含 /strategies /backtest /e
|
|||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
PYTHONPATH=. .venv/bin/python ../scripts/verify_strategy_workspace.py # 选股策略/字段库/因子目录+参数化/公共配置/回测组合库/归档链路(145 项 skip-job,含真实组合回测更多,约 5 分钟)
|
PYTHONPATH=. .venv/bin/python ../scripts/verify_strategy_workspace.py # 选股策略/字段库/因子目录+参数化/公共配置/回测组合库/归档链路(145 项 skip-job,含真实组合回测更多,约 5 分钟)
|
||||||
PYTHONPATH=. .venv/bin/python ../scripts/verify_backtest_page_contract.py # 回测结果结构契约(约 4 分钟)
|
PYTHONPATH=. .venv/bin/python ../scripts/verify_backtest_page_contract.py # 回测结果结构契约:字段 + 买卖理由词表/名次/因子值 + 因子曲线(约 3 分钟)
|
||||||
python3 ../scripts/verify_ui_alignment.py # UI 对齐与控件一致性(8 个页面 × 2 宽度 = 160 项,约 3 分钟)
|
python3 ../scripts/verify_ui_alignment.py # UI 对齐与控件一致性(8 个页面 × 2 宽度 = 160 项,约 3 分钟)
|
||||||
python3 ../scripts/verify_unit_conversion.py # 字段库单位:只能在给定范围内选 + 界面单位⇄基准单位换算(约 2 分钟)
|
python3 ../scripts/verify_unit_conversion.py # 字段库单位:只能在给定范围内选 + 界面单位⇄基准单位换算(约 2 分钟)
|
||||||
python3 ../scripts/verify_factor_params.py # 因子参数化:暴露真实参数/界面新建参数化因子/越界拒绝/停用不影响历史解析(约 3 分钟)
|
python3 ../scripts/verify_factor_params.py # 因子参数化:暴露真实参数/界面新建参数化因子/越界拒绝/停用不影响历史解析(约 3 分钟)
|
||||||
@@ -651,7 +688,9 @@ python3 ../scripts/verify_factor_params.py # 因
|
|||||||
归档、Agent 工具白名单与编排、LLM 配置加载、API 端到端、**策略说明推导**
|
归档、Agent 工具白名单与编排、LLM 配置加载、API 端到端、**策略说明推导**
|
||||||
(`describe_strategy` 的分支/互斥/缺失值语义)、**股票名称回填**(回测与选股两侧)、
|
(`describe_strategy` 的分支/互斥/缺失值语义)、**股票名称回填**(回测与选股两侧)、
|
||||||
**UI 对齐与控件一致性**(同排等高 / 尺寸归一 / 点击目标 / 标签 / 无障碍名 / 横向溢出,
|
**UI 对齐与控件一致性**(同排等高 / 尺寸归一 / 点击目标 / 标签 / 无障碍名 / 横向溢出,
|
||||||
7 个页面 × 1500 与 375px 两种视口,见 §6.3.2)。
|
7 个页面 × 1500 与 375px 两种视口,见 §6.3.2)、**买卖理由与因子曲线**
|
||||||
|
(理由词表封闭、数字来自引擎、因子曲线持仓市值加权且空仓不落点,见
|
||||||
|
`tests/test_trade_reasons.py` 8 条 + `tests/test_local_engine_reasons.py` 14 条)。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user