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:
@@ -0,0 +1,71 @@
|
||||
# 技术实现方案:08-策略持仓行展开关联交易记录(Holding → 交易汇总)
|
||||
|
||||
> 依据:PLAN-009 | 需求:R-010(Q1-Q3 定稿)| 设计约束:技术约束-012、技术约束-011(测试隔离)
|
||||
|
||||
## 技术选型
|
||||
|
||||
- 复用 R-009 的 holding_id 关联(trade_orders.holding_id);
|
||||
- 服务端:strategy-positions 附加 holding_id + trades/by-holding 端点;
|
||||
- 前端:StrategyTab 持仓行展开(懒加载内嵌汇总表)。
|
||||
|
||||
## 数据流
|
||||
|
||||
```
|
||||
策略持仓 tab:
|
||||
load() → strategy-positions(每行含 holding_id)
|
||||
用户点击持仓行 → 展开 → trades/by-holding?holdingId=13 → 委托汇总列表
|
||||
懒加载:不展开不请求
|
||||
```
|
||||
|
||||
## 实现细节
|
||||
|
||||
### 1. PositionManager.getStrategyPositions 附加 holding_id
|
||||
|
||||
```js
|
||||
async getStrategyPositions(strategyId) {
|
||||
const [positions, dataset, holdings] = await Promise.all([
|
||||
this.getAllPositions(),
|
||||
this.storage.getDataset(strategyId),
|
||||
this.storage.getCurrentHoldings(strategyId), // 含 holding_id
|
||||
]);
|
||||
const shareMap = new Map(dataset.map(d => [d.code, d.shares]));
|
||||
const holdingMap = new Map(holdings.map(h => [h.code, h.holdingId]));
|
||||
return positions.map(p => {
|
||||
const shares = shareMap.get(p.code) ?? 0;
|
||||
return shares > 0 ? { ...p, shares, holdingId: holdingMap.get(p.code) ?? null } : null;
|
||||
}).filter(Boolean);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. SqliteStore.getOrdersByHolding
|
||||
|
||||
```js
|
||||
getOrdersByHolding(holdingId) {
|
||||
this.init();
|
||||
return this.db.prepare(
|
||||
'SELECT * FROM trade_orders WHERE holding_id=? ORDER BY insert_ts DESC'
|
||||
).all(holdingId).map(r => this._mapOrderRow(r));
|
||||
}
|
||||
```
|
||||
|
||||
### 3. api/trades.js:trades/by-holding 端点
|
||||
|
||||
```js
|
||||
case 'trades/by-holding':
|
||||
return await storage.getTradeOrdersByHolding(args.holdingId);
|
||||
```
|
||||
|
||||
### 4. StrategyTab 展开 UI
|
||||
|
||||
- 持仓行加展开箭头(类似交易记录 tab);
|
||||
- 展开时调 trades/by-holding,内嵌小表格显示委托汇总:
|
||||
时间 / 方向 / 状态 / 委托量 / 成交量 / 均价 / 金额 / 费用;
|
||||
- 只显示委托汇总(ORDER_STATUS 中文映射复用);
|
||||
- 懒加载:展开时才请求,折叠清空。
|
||||
|
||||
## 涉及设计约束
|
||||
|
||||
| 约束 | 内容 |
|
||||
|---|---|
|
||||
| 技术约束-012 | 数据存储遵循数据存储设计.md(复用 trade_orders.holding_id) |
|
||||
| 技术约束-011 | 测试用独立数据目录(ODL_TEST_DATA_DIR) |
|
||||
@@ -0,0 +1,38 @@
|
||||
# 迭代复盘:08-策略持仓行展开关联交易记录(Holding → 交易汇总)
|
||||
|
||||
> 复盘日期:2026-09-02 | 迭代状态:**已完成(老师确认)**
|
||||
> 关联需求:R-010(策略持仓行展开关联交易记录,已定稿)
|
||||
> 关联计划:PLAN-009(计划-策略持仓行展开关联交易记录)
|
||||
|
||||
## 结果
|
||||
|
||||
迭代 08 达成:策略持仓 tab 每个持仓行(Holding)可展开,展开显示与该 holding 关联的交易记录(委托汇总,不分笔成交);持仓行新增成本价(avgPrice)+ 最后一笔成交价(lastTradePrice)两列;神之一手全部 tab 激活时隐藏 AI 对话输入框(纯 CSS)。实现「持仓 ↔ 交易」双向追溯。
|
||||
|
||||
## 过程事实
|
||||
|
||||
1. **需求定稿(R-010)**:老师提出持仓行展开看关联交易(只要委托汇总)→ AI 登记 Q1-Q3(附加 holding_id / by-holding 端点 / 展开 UI)→ 老师确认 → 补充 Q4(成本价 + 最后一笔成交价,取最新有成交的 tradedPrice,无则默认成本价);
|
||||
2. **服务端**:strategy-positions 附加 holding_id(PositionManager 查 strategy_holdings)+ 计算 avgPrice/lastTradePrice(查该 holding 关联委托,取最新有成交的 tradedPrice);SqliteStore.getOrdersByHolding + DataStore 委托;api trades/by-holding 端点;
|
||||
3. **前端**:StrategyTab 持仓行展开(箭头 + 懒加载 + 内嵌委托汇总表,含交易日/时间列);成本价/最后一笔成交价两列;
|
||||
4. **隐藏输入框**:借鉴 dsh-context 插件的纯 CSS 方案(:has(.odl-root) 命中时隐藏 composer)——神之一手 tab 激活时隐藏输入框,chat/其他 tab 正常显示;
|
||||
5. **验证**:回归测试(by-holding 查询 6 项 + lastTradePrice 计算 4 项)通过、真实数据验证(001330.SZ holding 13 → 博纳影业卖出委托;成本价 6.84 / 最后成交 6.00)、构建 + typecheck 通过。
|
||||
|
||||
## 经验教训(复盘沉淀)
|
||||
|
||||
### 1. 隐藏宿主 UI 优先借鉴成熟插件方案
|
||||
- 曾深挖 DSH composer chain / selector 机制(复杂度高、依赖内部 store),后经老师提示参考 dsh-context 插件——它用一行纯 CSS(:has() 选择器)实现「特定 tab 激活时隐藏输入框」,零宿主改动、零风险;
|
||||
- **沉淀**:改宿主 UI 前先看同类插件怎么做的;纯 CSS :has() 是最优雅的 view 条件渲染方案。
|
||||
|
||||
### 2. 前端声明顺序 TDZ(本次多次踩坑)
|
||||
- 迭代 07/08 多次遇到「Cannot access X before initialization」(TDZ):useEffect 依赖数组/回调在渲染时求值,引用了后声明的 const;
|
||||
- **沉淀**:React 组件内所有 useCallback/useEffect 的依赖引用必须在其声明之后;新增代码时严格核对声明顺序,构建后浏览器验证。
|
||||
|
||||
### 3. 服务端 vs 客户端生效机制
|
||||
- 服务端改动(PositionManager/API/SqliteStore)需重启 DSH 生效;客户端 bundle 刷新即载(rev 变化自动同步);
|
||||
- **沉淀**:改完先确认服务端端点/响应是新行为,再让老师重启。
|
||||
|
||||
## 遗留/后续
|
||||
|
||||
1. **持仓展开的交易汇总**:当前只显示该 holding 关联的委托汇总;后续可按 holding 聚合复盘(目标-006);
|
||||
2. **关注列表 tab**:仍为占位(PlaceholderTab),后续迭代实现;
|
||||
3. **全部持仓 tab**:未做展开(老师只要求策略持仓 tab);如需可复用同样模式;
|
||||
4. **迭代 07 遗留**:QMT Bridge 历史接口(老师完善后接入)、盘中行情写 SQLite 验证(开盘后确认)。
|
||||
@@ -0,0 +1,24 @@
|
||||
# 迭代目标:08-策略持仓行展开关联交易记录(Holding → 交易汇总)
|
||||
|
||||
> 迭代编号:08 | 创建:2026-09-02 | 状态:进行中
|
||||
> 依据计划:PLAN-009 | 需求:R-010(已定稿,2026-09-02)
|
||||
|
||||
## 目标描述
|
||||
|
||||
策略持仓 tab 每个持仓行(Holding)可展开,展开显示与该 holding 关联的交易记录(仅委托汇总,不分笔成交),实现「持仓 ↔ 交易」双向追溯(R-009 反向)。
|
||||
|
||||
## 目标分解
|
||||
|
||||
1. **strategy-positions 附加 holding_id**:持仓行带出关联锚点;
|
||||
2. **trades/by-holding 端点**:按 holding_id 查委托汇总;
|
||||
3. **持仓行展开 UI**:展开显示委托汇总表(懒加载)。
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- 2026-09-02 老师提出需求(持仓行展开看关联交易,只要委托汇总);
|
||||
- 2026-09-02 AI 登记 R-010(讨论中),提出 Q1-Q3(附加 holding_id / by-holding 端点 / 展开 UI);
|
||||
- 2026-09-02 老师确认 Q1-Q3 定稿,进入本迭代。
|
||||
|
||||
## 对老师的配合需求
|
||||
|
||||
- 无阻塞依赖;验收时用真实持仓(如 001330.SZ holding 13)验证展开效果。
|
||||
@@ -0,0 +1,23 @@
|
||||
# 验收标准:08-策略持仓行展开关联交易记录(Holding → 交易汇总)
|
||||
|
||||
## 验收标准线
|
||||
|
||||
1. **strategy-positions 附加 holding_id**:每个持仓行含 holding_id(同策略同 code 当前持仓);
|
||||
2. **trades/by-holding 端点**:按 holding_id 返回该 holding 的委托汇总(时间/方向/状态/量/价/金额/费用;无成交委托也显示);
|
||||
3. **持仓行展开**:策略持仓 tab 每行可展开(箭头指示),展开显示委托汇总表;
|
||||
4. **仅汇总不分笔**:展开内容只显示委托汇总,无分笔成交明细;
|
||||
5. **懒加载**:不展开不请求 trades/by-holding;
|
||||
6. **不回归**:策略持仓份额操作(添加/移出/全部移入)、交易记录 tab、行情等现有功能正常;
|
||||
7. **测试隔离**:回归测试在独立数据目录执行(技术约束-011)。
|
||||
|
||||
## 验收方法
|
||||
|
||||
- 独立数据目录构造持仓 + 委托(holding_id 关联)→ 启动 → 验证 strategy-positions 含 holding_id、trades/by-holding 返回正确;
|
||||
- 真实数据:网格超市 tab 展开 001330.SZ(holding 13)→ 看到博纳影业卖出委托汇总;
|
||||
- 前端:展开/折叠、懒加载、汇总表列正确;
|
||||
- 回归:份额操作、交易记录、行情不回归。
|
||||
|
||||
## 验收目标
|
||||
|
||||
- 持仓 ↔ 交易双向追溯闭环(R-009 交易→持仓 + 本迭代持仓→交易);
|
||||
- 为按 holding 复盘交易铺路(目标-006)。
|
||||
Reference in New Issue
Block a user