docs(迭代07/08): 交易记录本地存储 + 策略持仓展开全量文档 + 需求归档(R-009/R-010)

- PLAN-008/PLAN-009 计划(已完成)
- 迭代 07/08 四件套(目标/技术方案/验收标准/复盘)
- 设计约束:数据存储设计 §10/§10.1、技术约束-012/013、产品约束-008
- R-009/R-010 需求归档(含二次定稿:手动归属、Q4 成本价/成交价)
- 需求池索引同步
This commit is contained in:
2026-09-02 01:21:10 +08:00
parent 859938c4f1
commit 2aacd8a25d
16 changed files with 821 additions and 6 deletions
@@ -0,0 +1,66 @@
# 计划:交易记录本地存储(SQLite)+ 策略关联(阶段航点)
> 编号:PLAN-008 | 粒度:阶段航点(大粒度) | 创建:2026-09-01 状态:**已完成(2026-09-01 迭代 07 验收通过)**
> 派生自终极目标:目标-006(交易复盘)、目标-003(按策略监控市场)
> 依据需求:**R-009(已定稿,2026-09-01Q1-Q8 全部确认)** —— 符合入范围门槛
> 设计约束:技术约束-012(数据存储设计)、技术约束-001/003/004/010(沿用)、产品约束-007 方向语义
## 目标
在 SQLite 新增**交易记录表**trade_orders 委托 + trade_fills 成交),将 QMT Bridge 当日交易数据**本地持久化**(跨日积累成本地历史库),并按**外键链**(成交→委托→策略→holding)建立与插件策略体系的关联,支持**按策略过滤 / 复盘**交易。
- 承接 R-007 的 Q5(本地持久化)与 Q10(按策略过滤);
- 落实迭代 06 复盘遗留项 2(holding_id 关联锚点);
- 解决 R-007 历史范围「接口开发中」占位(本地积累后历史可查)。
## 范围
**做**
1. **两表落地**trade_orders(委托主行,order_id 主键,UPSERT 幂等)+ trade_fills(成交明细,trade_id 主键、order_id 外键关联委托)两表;**两表均不冗余 strategy_id / holding_id**Q3 老师定稿:外键链推导);trade_orders 加派生列 insert_tsinsert_date+insert_time 合成毫秒时间戳,join 持仓窗口用);
2. **定时同步**:服务端 TradeSync 模块 —— 定时(60s)拉当日 orders+trades → UPSERT 落库(幂等);插件启动同步一次(预热今日数据);前端今日轮询写穿(机会式);
3. **策略关联(外键链推导)**:策略/持仓归属不在写入期计算,查询期由委托时间(insert_tsJOIN strategy_holdings 生命周期窗口(created_at ≤ t < closed_atclosed_at 为 NULL=当前持仓)推导;同码多策略取份额最大持仓;无命中视为未关联;
4. **本地历史查询端点**trades/history —— 按 { start, end, code, strategyId, direction } 查本地 SQLite,返回 { orders, fills }(策略过滤走 FK 链 join);
5. **前端**TradeRecordsTab 加策略过滤下拉(全部/各策略/未关联);历史范围从「占位」切换为查本地库;今日仍走 QMT 实时 + 写穿本地。
**不做**
- 手动修正策略关联入口(后续迭代);
- 导出/清理管理界面(后续迭代;复盘需要历史,不做自动清理);
- QMT 历史接口接入(老师完善后再接);
- 下单/撤单等交易操作(目标-007 另议)。
## 程序结构(改造后)
```
src/
├── component/
│ ├── SqliteStore.js # 改:+trade_orders/trade_fills 建表 + 交易 UPSERT/查询 + 策略归属推导
│ ├── DataStore.js # 改:委托交易记录方法
│ └── TradeSync.js # 新增:服务端定时同步(60s + 启动预热 + UPSERT 幂等)
├── api/
│ └── trades.js # 改:+trades/history 端点
└── index.js # 改:装配 TradeSync + storage 注入 api runtime
src/client/views/
└── TradeRecordsTab.jsx # 改:策略过滤下拉 + 历史范围查本地库
```
## 实现步骤(建议顺序)
1. **文档骨架**PLAN-008 + 迭代 07 子目录(本步);
2. **设计约束落地**:数据存储设计.md §10 增补交易记录表设计 + 技术方案约束新增条目;
3. **SqliteStore**:建表(trade_orders/trade_fills+ 交易 UPSERT(幂等)+ 本地历史查询 + 策略归属推导(insert_ts join 持仓窗口);
4. **DataStore**:委托交易记录方法;
5. **TradeSync**:定时同步模块(60s + 启动预热 + 今日范围 UPSERT);
6. **api/trades.js**trades/history 端点(+ 现有 orders/trades 响应附加策略归属信息可选);
7. **index.js**:装配 TradeSyncdispose 清理)+ storage 注入 api runtime
8. **前端**TradeRecordsTab 策略过滤 + 历史范围本地展示;
9. **构建测试**pnpm run build + typecheck + 独立数据目录回归测试(技术约束-011);
10. **验收**:对照迭代 07 验收标准逐条核验,记录迭代复盘。
## 验收要点
- trade_orders + trade_fills 两表落地(零冗余 strategy_id/holding_idinsert_ts 派生列);
- 同步:启动预热 + 60s 定时 UPSERT 幂等(重复同步不重复行、状态覆盖更新);
- 历史查询:按时间段/code/策略/方向查本地库,策略过滤 = 委托时间 join 持仓生命周期窗口(一码多策略取份额最大);
- 前端:策略过滤下拉 + 历史范围展示本地数据(不再占位);今日实时 + 写穿;
- 现有功能不回归(持仓/策略/行情/连接配置/交易记录今日实时);
- 技术约束-011:回归测试用独立数据目录。
@@ -0,0 +1,55 @@
# 计划:策略持仓行展开关联交易记录(Holding → 交易汇总)(阶段航点)
> 编号:PLAN-009 | 粒度:阶段航点(大粒度) | 创建:2026-09-02 状态:**已完成(2026-09-02 迭代 08 老师确认)**
> 派生自终极目标:目标-006(交易复盘)、目标-003(按策略监控市场)
> 依据需求:**R-010(已定稿,2026-09-02Q1-Q3 确认)** —— 符合入范围门槛
> 设计约束:技术约束-012(数据存储设计)、技术约束-001/003/004(沿用)
## 目标
策略持仓 tab 每个持仓行(Holding)可展开,展开显示与该 holding 关联的交易记录(仅委托汇总,不分笔成交),实现「持仓 ↔ 交易」的双向追溯(R-009 反向:交易→持仓已实现,本迭代持仓→交易)。
## 范围
**做**
1. **strategy-positions 附加 holding_id**PositionManager.getStrategyPositions 返回时,查 strategy_holdings 附加当前持仓的 holding_idQ1);
2. **trades/by-holding 端点**:按 holding_id 查 trade_orders,返回委托汇总列表(时间/方向/状态/委托量/成交量/均价/金额/费用)(Q2);
3. **持仓行展开 UI**StrategyTab 持仓行加展开(类似交易记录 tab 展开效果),展开后内嵌小表格显示该 holding 的委托汇总;懒加载(展开时才请求)(Q3)。
**不做**
- 分笔成交明细展示(老师明确只要汇总);
- 交易记录 tab 改动;
- 归属设置入口(R-009 已有)。
## 程序结构
```
src/
├── component/
│ ├── PositionManager.js # 改:getStrategyPositions 附加 holding_id
│ ├── SqliteStore.js # 改:+getOrdersByHolding(holdingId)
│ └── DataStore.js # 改:+getTradeOrdersByHolding
├── api/
│ └── trades.js # 改:+trades/by-holding 端点
src/client/views/
└── StrategyTab.jsx # 改:持仓行展开 + 内嵌委托汇总表(懒加载)
```
## 实现步骤
1. **文档骨架**PLAN-009 + 迭代 08(本步);
2. **SqliteStore**getOrdersByHoldingWHERE holding_id=? ORDER BY insert_ts DESC);
3. **DataStore**:委托方法;
4. **PositionManager**getStrategyPositions 附加 holding_id
5. **api/trades.js**trades/by-holding 端点;
6. **StrategyTab**:持仓行展开 + 懒加载 + 内嵌汇总表;
7. **构建测试**pnpm run build + typecheck + 独立数据目录回归(技术约束-011);
8. **验收 + 复盘**
## 验收要点
- strategy-positions 每行含 holding_id(同策略同 code 当前持仓);
- trades/by-holding 返回该 holding 的委托汇总(无成交的委托也显示);
- StrategyTab 持仓行可展开,展开显示委托汇总表(不分笔成交);
- 懒加载:不展开不请求;
- 现有功能不回归。