迭代15: 委托归属候选纳入近期清仓持仓(R-017)
- 交易记录 tab 归属候选只回当前持仓 → 清仓后当日委托失去下拉锚点无法补关联 (2026-09-07 大连热电实际发生: 盘中归属后被清为未关联,下拉已无做T候选) - SqliteStore.getAttributionCandidates: 候选 = 该 code 当前持仓 + 近 7 天清仓的持仓 (closed 标记 + closedAt,排序 当前持仓在前 → 清仓行 closed_at DESC) - AttributionSelect: 下拉 value 改 holdingId 键控(同策略多轮持仓不撞值)、 清仓选项「(已清仓 MM-DD)」后缀、已归属但候选缺失显示「当前归属」占位 - 回归: test-r017-candidates 12/12 + 存量回归全绿
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# 技术实现方案:15-归属候选纳入清仓持仓
|
||||
|
||||
> 迭代编号:15 | 依据:PLAN-016 + R-017
|
||||
|
||||
## 1. 存储层(getAttributionCandidates 扩展,门面透传不变)
|
||||
|
||||
```sql
|
||||
SELECT holding_id, strategy_id, shares, closed_at FROM strategy_holdings
|
||||
WHERE code=? AND (closed_at IS NULL OR closed_at >= ?) -- ? = Date.now() - 7d
|
||||
ORDER BY (closed_at IS NULL) DESC, shares DESC, closed_at DESC
|
||||
```
|
||||
|
||||
- 返回行新增 closed: boolean / closedAt: number|null(消费方:api strategies.js 同方法直接受益——注意 attribution-candidates 端点在 trades.js,调 DataStore.getTradeAttributionCandidates 透传,零改动);
|
||||
- 窗口常量 7 * 86400000(与 R-016 默认范围一致)。
|
||||
|
||||
## 2. UI(TradeRecordsTab.jsx AttributionSelect 重构)
|
||||
|
||||
- 锚点键:currentKey = order.holdingId != null ? String(order.holdingId) : ''(holdingId 是 R-009 定稿的归属锚点;strategyId 在同策略多轮持仓时会撞值);
|
||||
- handleSelect:按 String(holdingId) 找候选 → setAttribution(orderId, code, cand.strategyId, cand.holdingId);__unassigned__ → 双 null;
|
||||
- 占位选项:已归属但候选缺失(清仓超 7 天)→ 「当前归属({strategyId})」,value=currentKey,防 select 悬空显示第一项误导;
|
||||
- 清仓候选文本后缀「(已清仓 MM-DD)」(fmtClosed 本地 helper);select maxWidth 120→150。
|
||||
|
||||
## 3. 数据修复记录(一次性,非功能)
|
||||
|
||||
2026-09-07 大连热电卖出委托 645001623 经 live set-attribution 通道回填 strategy_id=manual-t / holding_id=15(curl 实测 ok:true,orders/by-holding 回读确认)。当日归属曾被清为未关联的原因:候选下拉无做T项时老师误触「未关联」入口——本迭代修复后此路径消除。
|
||||
|
||||
## 4. 验证链
|
||||
|
||||
test-r017-candidates.mjs 12 断言 + typecheck + build + 存量回归(r016 19 / position-sync 35 / r013 21 / quote-sync 27)。
|
||||
@@ -0,0 +1,34 @@
|
||||
# 迭代复盘:15-归属候选纳入清仓持仓
|
||||
|
||||
> 复盘日期:2026-09-07 | 迭代状态:**已实施,待老师人工验收**
|
||||
> 关联需求:R-017 | 关联计划:PLAN-016
|
||||
|
||||
## 结果
|
||||
|
||||
迭代 15 达成:归属候选 = 当前持仓 + 近 7 天清仓持仓(closed 标记 + 「已清仓 MM-DD」后缀),下拉锚点改 holdingId 键控(同策略多轮持仓不撞值)+ 「当前归属」占位防悬空;清仓后当日委托可补关联。另:当日大连热电卖出委托(645001623)的归属已经 set-attribution 通道修复回 manual-t/holding 15(一次性数据修复,非功能)。
|
||||
|
||||
## 过程事实
|
||||
|
||||
1. **数据取证先行**:老师报告「无法关联」时,DB 真相 = 委托归属已被清为 null/null(非从未设置)+ 候选接口只剩网格超市——「归属丢失」与「候选缺失」两个问题一次取证分清;
|
||||
2. **当日修复走既有通道**:set-attribution 本就无候选限制(Q4 可随时改语义),curl 修复 + 回读验证,不新造工具;
|
||||
3. **实现**:SqliteStore.getAttributionCandidates WHERE/ORDER 扩展 + closed/closedAt 字段(门面/api 零改动透传);AttributionSelect 从 strategyId 键控重构为 holdingId 键控 + 占位 + 后缀;
|
||||
4. **验证**:test-r017 12/12;typecheck 通过;存量回归 r016 19/19、position-sync 35/35、r013 21/21、quote-sync 27/27;build 通过。
|
||||
|
||||
## 经验教训(复盘沉淀)
|
||||
|
||||
### 1. 「关联」的锚点键要在多轮持仓出现时重新审视
|
||||
- R-009 时代下拉 value 用 strategyId(一码一策略一行时无碍);R-016 历史行引入后同码可同时存在「当前行 + 历史行」、同策略可有多轮清仓——strategyId 键撞值成为真实 bug 面,holdingId 才是归属锚点(R-009 表结构早已如此,UI 层滞后);
|
||||
- 沉淀:外键语义(表里存什么)和 UI 键(下拉传什么)要对齐审查,表结构升级时 UI 不自动跟上。
|
||||
|
||||
### 2. 「数据问题」与「能力缺失」要分层处置
|
||||
- 老师当下要的是「这笔委托关联回去」(数据问题)——走既有 API 通道立即修复,不等迭代;「以后不再发生」(能力缺失)——立项 R-017 走流程。两层都做但互不阻塞。
|
||||
|
||||
### 3. 候选缺失时的 UI 应该显示「当前归属」而不是悬空
|
||||
- select value 不在任何 option 里时浏览器表现不可控(显示空白或第一项),第一项恰是「未关联」时极易诱导误操作(本次归属被清的可能路径);
|
||||
- 沉淀:受控 select 的 value 必须保证总有对应 option——数据缺口用占位 option 补,不让浏览器自作主张。
|
||||
|
||||
## 遗留/后续
|
||||
|
||||
1. **候选窗口(7 天)与 R-016 范围档是两套口径**:当前均满足场景;若老师后续要统一(候选也用 5 档范围),另议小改;
|
||||
2. **自动归属推导**(_resolveStrategyAttribution 时间窗)仍在(技术约束-013),但 Q3 全手动原则下仅为内部能力,未暴露 UI;维持现状;
|
||||
3. R-015 / 迭代 13、R-016 / 迭代 14 的人工验收仍待老师确认。
|
||||
@@ -0,0 +1,19 @@
|
||||
# 迭代目标:15-归属候选纳入清仓持仓
|
||||
|
||||
> 迭代编号:15 | 创建:2026-09-07 | 状态:已实施,待验收
|
||||
> 依据计划:PLAN-016 | 需求:R-017(已定稿,2026-09-07)
|
||||
|
||||
## 目标描述
|
||||
|
||||
交易记录 tab 的归属候选(orders/attribution-candidates)纳入近 7 天清仓的持仓(closed 标记),下拉锚点改 holdingId 键控——修复「清仓后当日委托无法补关联」(2026-09-07 大连热电做T实际发生:盘中归属被清后下拉已无手动做T候选)。
|
||||
|
||||
## 目标分解
|
||||
|
||||
1. **存储**(SqliteStore.getAttributionCandidates):WHERE 扩展为 closed_at IS NULL OR closed_at ≥ 7 天前;返回行附 closed/closedAt;排序 当前持仓(shares DESC) 在前 → 清仓行 closed_at DESC;
|
||||
2. **UI**(AttributionSelect):value 改 String(holdingId);点选按 holdingId 找候选取 strategyId+holdingId 写入;清仓选项加「(已清仓 MM-DD)」后缀;已归属但候选缺失时显示「当前归属」占位(防 select 值悬空);title 提示更新;
|
||||
3. **回归**:scripts/test-r017-candidates.mjs(12 断言:候选构成/标记/窗口边界/排序/隔离/端点透传)。
|
||||
|
||||
## 对老师/主理人的配合需求
|
||||
|
||||
- 重启 DSH web 进程(服务端代码更新)+ 刷新页面后人工验收;
|
||||
- 验收通过后迭代 15 标记「验收通过」,R-017 归档。
|
||||
@@ -0,0 +1,20 @@
|
||||
# 验收标准:15-归属候选纳入清仓持仓
|
||||
|
||||
> 迭代编号:15 | 依据:PLAN-016 验收要点 + R-017
|
||||
|
||||
## 验收标准线
|
||||
|
||||
1. **自动化**:typecheck + build 通过;test-r017-candidates.mjs 12/12;存量回归 r016 / position-sync / r013 / quote-sync 全绿;
|
||||
2. **候选构成**(真实环境):交易记录 tab 大连热电今日卖出委托的归属下拉 = 网格超市(当前持仓)+ 手动做T(已清仓 09-07)两项;
|
||||
3. **补关联**:点选「手动做T(已清仓 09-07)」→ 保存成功提示 → 行内归属显示手动做T且下拉保持选中;做T策略 tab 历史持仓行展开可见该笔卖出(holding 15 关联);
|
||||
4. **可逆**:切回「未关联」→ 双 null 持久化;再切回做T → 恢复;
|
||||
5. **占位**:归属存在但候选缺失的场景显示「当前归属(…)」占位(可用超 7 天清仓行验证,或观察现有数据)。
|
||||
|
||||
## 验收方法
|
||||
|
||||
- 自动化项 AI 执行出具结果;2~5 老师重启 DSH web + 刷新页面人工验收;
|
||||
- 全部通过后迭代 15 标记「验收通过」,R-017 归档 已完成/。
|
||||
|
||||
## 验收目标
|
||||
|
||||
- 5 条验收线通过,迭代 15 标记「验收通过」,R-017 更新实现状态并归档。
|
||||
Reference in New Issue
Block a user