2aacd8a25d
- PLAN-008/PLAN-009 计划(已完成) - 迭代 07/08 四件套(目标/技术方案/验收标准/复盘) - 设计约束:数据存储设计 §10/§10.1、技术约束-012/013、产品约束-008 - R-009/R-010 需求归档(含二次定稿:手动归属、Q4 成本价/成交价) - 需求池索引同步
2.3 KiB
2.3 KiB
技术实现方案: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
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
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 端点
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) |