迭代16: 交易关联驱动持仓份额动态调整(R-018)
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# 技术实现方案:16-交易关联驱动持仓份额动态调整
|
||||
|
||||
> 迭代编号:16 | 依据:PLAN-017 + R-018(已定稿)
|
||||
|
||||
## 0. 核心不变量(数据域分界,R-018 §〇)
|
||||
|
||||
- PositionSync(含幽灵清仓)**只写对账单域**(进程内快照),永不写 strategy_holdings;
|
||||
- strategy_holdings 写操作只来自:**归属服务(交易关联)** + **手动份额操作**(add-shares/remove-shares/move-all-shares/策略删除清空,现状保留);
|
||||
- 账本行转历史(closed_at)唯一途径:卖出段关联把份额减到 0(closeHolding);**幽灵清仓代码删除**。
|
||||
|
||||
## 1. 存储地基(阶段B)
|
||||
|
||||
### 1.1 strategy_holdings 增列(幂等 ALTER,沿用 _ensureXxxColumn 模式)
|
||||
|
||||
```sql
|
||||
ALTER TABLE strategy_holdings ADD COLUMN void_at INTEGER; -- 作废时间(NULL=有效;非 NULL=建仓被撤=从未成立)
|
||||
ALTER TABLE strategy_holdings ADD COLUMN closed_shares REAL; -- 清仓前份额快照(closeHolding 写入;供撤卖出段恢复活动用)
|
||||
```
|
||||
|
||||
- 活动判定收敛:`closed_at IS NULL AND void_at IS NULL`;
|
||||
- 唯一索引重建(活动唯一收窄至两态皆空):
|
||||
```sql
|
||||
DROP INDEX IF EXISTS idx_active_holding;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_holding
|
||||
ON strategy_holdings (strategy_id, code) WHERE closed_at IS NULL AND void_at IS NULL;
|
||||
```
|
||||
- closeHolding 变更:置 shares=0 + closed_at=now + **closed_shares=清仓前份额**(shares 列仍置 0,R-016 Q2 展示语义不变);
|
||||
- 新增 voidHolding(strategyId, code):置 shares=0 + void_at=now(不改 closed_at);作废行不进 R-016 历史层(getHoldingsHistory 过滤 void_at IS NULL);
|
||||
- _mapHolding 增 voidAt / closedShares 字段(读方法 select 补列)。
|
||||
|
||||
### 1.2 归属分段表 trade_order_attributions
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS trade_order_attributions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
order_id TEXT NOT NULL, -- → trade_orders.order_id
|
||||
strategy_id TEXT NOT NULL, -- 段归属策略(冗余,过滤快)
|
||||
holding_id INTEGER NOT NULL, -- 段锚点持仓(R-010 展开用)
|
||||
code TEXT NOT NULL, -- 冗余(by-holding 反查/防呆)
|
||||
direction TEXT NOT NULL, -- buy/sell 冗余(撤段判向)
|
||||
volume REAL NOT NULL, -- 该段已成交量(>0;总额 ≤ order.traded_volume)
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_attr_order_strategy ON trade_order_attributions (order_id, strategy_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_attr_holding ON trade_order_attributions (holding_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_attr_strategy ON trade_order_attributions (strategy_id);
|
||||
```
|
||||
|
||||
- **真相源 = 段表**;trade_orders.strategy_id/holding_id 两列**退役为冗余**(不再作为查询/过滤源;保留列不删,防外部脚本 break;写入不再维护);既有单组归属迁移为第一段(volume=该单 traded_volume,幂等:段表空且 order 有归属才迁);
|
||||
- 撤销语义支持 R-010 by-holding、R-009 history 策略过滤全部改经段表 join。
|
||||
|
||||
## 2. 归属服务(阶段C,新增 src/trades/AttributionService.js)
|
||||
|
||||
> 命名遵守技术约束-016(src/trades/ 交易域)。接口同步(node:sqlite DatabaseSync);归属服务持 `storage.sqlite` + DataStore 门面方法。
|
||||
|
||||
### 2.1 段级 apply(一段关联)
|
||||
|
||||
输入:{ orderId, code, direction, volume(已成交量) } + 目标 strategyId。判定动作表(R-018 §3.3):
|
||||
|
||||
| direction | strategy 活动仓(closed/void 均空) | 动作 |
|
||||
|---|---|---|
|
||||
| buy | 有 | addShares(strategyId, code, volume) → holding 取活动仓 |
|
||||
| buy | 无 | openHolding(strategyId, code, volume) → 新仓(不复活历史/作废行) |
|
||||
| sell | 有 且 shares ≥ volume | reduceShares;减后 0 → closeHolding |
|
||||
| sell | 有 且 shares < volume | **拒绝**(报错 code='segment-exceeds',由 UI 自动截断后再提交;服务端不做隐式截断——避免「半生效」状态与部分关联提示脱节) |
|
||||
| sell | 无 | 拒绝(code='no-active-holding',关联失败提示,R1) |
|
||||
|
||||
成功 → 写段表(order_id,strategy_id,holding_id,code,direction,volume,now)。买入建仓时 holding_id=openHolding 返回;买入加仓/卖出取活动仓 holding_id。
|
||||
|
||||
### 2.2 段级 revoke(撤一段)
|
||||
|
||||
输入:{ order_id, strategy_id }(唯一键)。逆操作(R3,粒度=段):
|
||||
|
||||
- **撤 buy 段**:查段 → holding。
|
||||
- holding 活动(closed/void 空):
|
||||
- shares ≥ 段量 → reduceShares(段量);**减后 shares=0** → voidHolding(作废,非 closeHolding;R3-1/R6 语义:建仓被撤=从未成立,无真实卖出→作废,不产生假清仓历史);
|
||||
- shares < 段量(说明该段之后已有卖出段作用于同一 holding)→ **拒绝**(code='segment-order-conflict',提示先撤更晚的段);
|
||||
- holding 已 closed/void → 该 buy 段本就不应撤销成功(段应随原操作撤)→ 拒绝;
|
||||
- **撤 sell 段**:查段 → holding。
|
||||
- holding 仍活动(该 sell 只是减仓)→ addShares(段量) 加回;
|
||||
- holding 已 closed 且 **closed_shares == 段量**(该段就是清仓段,且其后无新仓)→ **恢复活动**:closed_at=NULL、shares=closed_shares、closed_shares=NULL;
|
||||
- holding 已 closed 且 closed_shares > 段量(部分减仓后另段清仓)→ 拒绝(先撤更晚段);已 closed 且同 code 新活动仓已存在(close 后又建仓)→ 拒绝(无法恢复,避免撞唯一索引;R-018 §3.4 边界);
|
||||
- 成功后删段表行。
|
||||
|
||||
> 实现约束(写入 R-018 边界):**段撤销按「holding 内逆序」支持**;跨 holding 的段(拆单分给多策略)互相独立可任意撤(老师 R7 场景)。乱序撤同 holding 的段返回 segment-order-conflict,提示先撤更晚段——宁可拒绝不写错账(账本正确性 > 操作便利)。
|
||||
|
||||
### 2.3 全量替换 setSegments(改归属 = 撤旧段 + 加新段,原子)
|
||||
|
||||
输入:{ orderId, segments: [{ strategyId, volume }] }(volume>0;总额 ≤ order.traded_volume,允许 < = 部分关联)。
|
||||
流程(单事务):
|
||||
1. 读 order(trade_orders:code/direction/traded_volume);读段表现状;
|
||||
2. diff:将被删除段逐个 revoke(同 2.2 冲突规则)→ 冲突则整体回滚并报错;
|
||||
3. 新增/变更段逐个 apply(同 2.1)→ 任一失败整体回滚;
|
||||
4. COMMIT 后返回 { segments: 当前全部段 }(order 附加)。
|
||||
|
||||
> 事务:SqliteStore 暴露 `runInTransaction(fn)`(BEGIN/COMMIT/ROLLBACK 包裹;同步 API 直接 exec)。
|
||||
|
||||
### 2.4 查询
|
||||
|
||||
- getOrderAttributions(orderId):段列表(含 strategyName 由 settings 附名);
|
||||
- orders 列表附加归属:批量查段表按 order 聚合;
|
||||
- getOrdersByHolding(holdingId):改经段表 join trade_orders(R-010 展示);
|
||||
- 历史策略过滤(getOrderHistory/getFillHistory strategyId):改经段表(fill→order→段表 strategy_id 集合;`__unassigned__` = 无任何段);
|
||||
- getHoldingsHistory:过滤 void_at IS NULL(作废不进历史层)+ closed 逻辑不变。
|
||||
|
||||
## 3. 候选与 API(阶段D)
|
||||
|
||||
- **orders/attribution-candidates 退役 R-017 7 天语义** → 改 `orders/attribution-targets`:{ code } → 全部策略(settings strategies)+ 每策略该 code 当前活动份额 activityShares(0=无仓)+ 该 order 已有关联段数提示(供 UI「指向后判定」的前置展示;**不预筛**,指向后由服务端判定)。策略级(Q1),holdingId 不再作下拉键;
|
||||
- **orders/attribution-set**:{ orderId, segments } → 归属服务 setSegments(替代 set-attribution;set-attribution 端点删除或保留为单段包装——删,避免双写源混乱;既有数据迁移已覆盖);
|
||||
- **orders/attribution-segments**:{ orderId } → 读当前段(UI 展开/编辑用);
|
||||
- 今日 orders 端点:order 行附 `segments: [{strategyId,strategyName,holdingId,volume}]`(取代原单组 strategyId/holdingId 附加;兼容字段保留首段值)。
|
||||
|
||||
## 4. UI 份额分配器(阶段E,TradeRecordsTab)
|
||||
|
||||
- AttributionSelect 退役 → **AttributionAllocator**:
|
||||
- 头部:委托已成交量 / 已关联 Σ / 待分配余额(醒目色);
|
||||
- 一段 = 策略下拉(attribution-targets)+ 份额输入(默认=余额全量,可改小;sell 时 max=min(余额, activityShares) 自动钳制)+ 「添加段」;
|
||||
- 段列表(每段:策略名 + 量 + 「撤」按钮 → 调 attribution-set 去掉该段,即全量重交剩余段;或独立 revoke 端点——为原子性走 attribution-set 全量重交);
|
||||
- 已关联/部分关联/未关联三态展示 + 保存即生效(每步操作即时 setSegments);
|
||||
- 余额为 0 全关联提示;余额 >0 显「未分配剩余」提示(允许部分关联);
|
||||
- 撤销冲突(segment-order-conflict)→ toast 展示后端提示。
|
||||
- TradeRecordsTab order 行「归属」列 = 段 chips(点开进分配器)。
|
||||
|
||||
## 5. 分界 + 软提示(阶段A)
|
||||
|
||||
- PositionSync:删除 `_autoCloseGhosts`/ghostRounds/_ghostMiss/_fetchAccountId 调用链、stats.closedGhosts;类注释更新(只同步对账单快照);保留空快照双重确认与读穿透(对账单域行为不变)。test-position-sync.mjs 相应改断言(幽灵清仓→不再写账本:mock 断言 storage.closeHolding 未被调用);
|
||||
- **漏关联软提示(T3)**:新端点 `positions/orphan-hints`:账本活动行(closed/void 均空)∩ QMT 快照无此 code → 返回 [{strategyId,code,name,shares,holdingId}](**只读**,不动账本);交易记录 tab 顶部横幅提示(N 个持仓对账单已无此票,请去关联卖出单或移出)。阈值:全部孤儿都列(不设 7 天——账本无快照即提示,软提示不自动写)。
|
||||
|
||||
## 6. 涉及文件
|
||||
|
||||
- src/position/PositionSync.js(删幽灵清仓)、scripts/test-position-sync.mjs(改断言)
|
||||
- src/storage/SqliteStore.js(增列/索引重建/voidHolding/close 快照/段表 CRUD/runInTransaction/查询改段表/迁移)、src/storage/DataStore.js(门面透传)
|
||||
- src/trades/AttributionService.js(新增:apply/revoke/setSegments)
|
||||
- src/api/trades.js(attribution-targets/set/segments;orders 附加段)、src/api/strategies.js(strategy-holdings/history 过滤 void)
|
||||
- src/client/views/TradeRecordsTab.jsx(AttributionAllocator 替换 AttributionSelect)
|
||||
- scripts/test-r018-attribution.mjs(新增回归)
|
||||
- 设计约束:技术约束-017/产品约束-011/数据存储设计.md §11 变更记录 + §12 追加
|
||||
|
||||
## 7. 验证链
|
||||
|
||||
test-r018-attribution.mjs(分界/动作表/撤段逆序/迁移/软提示/API)+ test-position-sync 更新 + 存量回归(r017 改/ r016 / r013 / quote-sync)+ typecheck + build。
|
||||
@@ -0,0 +1,41 @@
|
||||
# 迭代复盘:16-交易关联驱动持仓份额动态调整
|
||||
|
||||
> 复盘日期:2026-09-08 | 迭代状态:**验收通过(2026-09-08)** —— 口径:自动化为主体 + 只读走查 + 真实使用顺带确认(老师拍板,见验收标准.md)
|
||||
> 关联需求:R-018(已定稿)| 关联计划:PLAN-017
|
||||
|
||||
## 结果
|
||||
|
||||
迭代 16 达成(R-018 全范围):**数据域分界落地**——幽灵清仓退役(PositionSync 不再写 strategy_holdings 账本);**归属升级为账本写操作**——策略级候选 + 统一份额分配器(委托拆 0..N 段 × 策略 × 量,余额默认全量可改小、允许部分关联)+ 买卖联动账本(买入加仓/建新仓不复活旧行、卖出减仓/归零清仓、仓不足拒绝、无仓拒绝)+ 撤段逆操作(撤建仓买入=作废第三态不产生假清仓历史、撤加仓=减回归零作废、撤卖出=恢复活动仓+份额加回,粒度=段、改归属原子)+ 归属分段存储(trade_order_attributions,真相源)+ R-017 7 天候选退役(holdingId 键控/占位安全逻辑由策略级 targets 承担)+ 漏关联软提示(只读)。存量归属(trade_orders 单列)自动迁移为段表第一段。
|
||||
|
||||
验证:新回归 test-r018-attribution 29/29;test-position-sync 29/29(幽灵退役断言重写);存量回归 r016 24 / r017 12(语义修订)/ r013 21 / r009 14 / r009-api 13(端点更新)/ r009-sync 8 / r009-normalize 11 / r011-api 12 / r011-tabs 23 / quote-sync 27 全绿;typecheck + build 通过。
|
||||
|
||||
## 过程事实
|
||||
|
||||
1. **文档链先行**:讨论收敛 → R-018 定稿 → PLAN-017 → 迭代 16 三件套 → 设计约束变更(技术约束-017 / 产品约束-011 / 数据存储设计 §11-13);
|
||||
2. **阶段A 分界**:PositionSync 删 `_autoCloseGhosts`/ghostRounds/账户守卫链/stats.closedGhosts,只保留对账单快照同步(含空快照双重确认与读穿透);软提示新端点 positions/orphan-hints(账本活动行 ∩ 快照缺失 code,只读);
|
||||
3. **阶段B 存储**:strategy_holdings 增 void_at/closed_shares(幂等 ALTER + 活动唯一索引重建收窄至两态皆空——索引创建移出 SCHEMA_SQL 到补列之后,防旧库无列建索引崩溃,quote-sync 回归暴露);closeHolding 记 closed_shares(shares 仍置 0,R-016 Q2 展示语义不变);voidHolding/reopenHolding/getHoldingById;新建 trade_order_attributions 段表;存量归属迁移段表第一段(幂等);
|
||||
4. **阶段C 归属服务**(src/trades/AttributionService.js 新增):apply(动作表判定)/ revoke(撤段逆操作,同 holding 逆序、跨 holding 独立)/ setSegments(全量替换、单事务原子);setOrderAttribution 兼容封装 = 替换语义(清旧段设新段);
|
||||
5. **阶段D API**:attribution-targets(策略级 + activityShares)/ attribution-set / attribution-segments;orders 与 trades/history 返回附加 segments;R-017 attribution-candidates/set-attribution 端点退役;strategy-holdings/history name 兜底改段表 join;
|
||||
6. **阶段E UI**:AttributionSelect → AttributionCell + AttributionEditor(余额头 + 段 chips 可撤 + 策略下拉/量输入/截断提示 + 全部撤除/完成);交易记录 tab 顶部漏关联软提示横幅;
|
||||
7. **阶段F 回归**:新脚本 test-r018-attribution;更新 position-sync(幽灵退役断言)、r017(7 天候选退役语义)、r009-api(新端点)、r016-history(段表造归属)。
|
||||
|
||||
## 经验教训(复盘沉淀)
|
||||
|
||||
### 1. 语义迁移要逐调用点核对 + 用旧回归脚本当哨兵
|
||||
R-018 把「归属真相源」从 trade_orders 单列迁到段表,牵动 r009/r016/r017/verify-real 一堆脚本与 strategies handler。靠跑存量回归暴露了两类坑:① quote-sync 的旧结构库建库路径在 SCHEMA_SQL 含新列索引时崩溃(索引引用尚不存在的列)——列迁移与索引重建必须同序;② 测试里「UPDATE trade_orders SET holding_id」直改冗余列的方式在真相源切换后不再生效(r016 name 兜底失败)——测试自身要改经段表造数据。沉淀:**存储层语义变更时,先跑全部存量回归锁定断裂点,再逐点核对(skill §5 语义迁移核对)**。
|
||||
|
||||
### 2. 「作废」与「清仓」是两个生命周期终态,不能用同一标记
|
||||
撤建仓买入段若走 closeHolding 会造出假的「已清仓」历史行(R-016 历史层会显示、统计会含)——老师 R3-1 拍板新增 void 第三态。沉淀:**「从未成立」与「曾经成立后卖出」在账本语义上必须区分**,UI 历史层只认 close。
|
||||
|
||||
### 3. 服务端不做隐式截断,让 UI 截断并提示余额
|
||||
卖出段 > 活动仓时服务端直接拒绝(segment-exceeds),由 UI 自动截为可容纳量并醒目提示「余额保留」——避免服务端悄悄改用户意图造成「半生效」状态与提示脱节。沉淀:**涉及钱/仓位的写接口要显式,宁可报错回滚也不要隐式修正**。
|
||||
|
||||
### 4. 数据域分界用一句话可执行规则落地
|
||||
「幽灵清仓是一个同步机制,爪子不许伸到账本」落到代码 = PositionSync 构造里不再持有 storage 写能力路径 + 回归断言 closeHolding 零调用。沉淀:**架构性拍板要落到「哪个模块能写哪张表」的显式约束,并用测试钉死**。
|
||||
|
||||
## 遗留/后续
|
||||
|
||||
1. **r013-columns 测试漂移(既有,非本迭代引入)**:断言「默认 8 列」但 COLUMN_META 自 R-015 加 4 行情列后实际 14 列(4 默认隐藏)——R-015 后未同步,建议另立小修(列显隐功能未破坏,纯测试预期过期);
|
||||
2. **R-016/R-017 文档同步**:R-017 迭代 15 复盘所述「候选窗口」语义已被 R-018 取代(7 天候选退役),R-017 需求文档待标注退役(R-018 需求文档已含 T2 决策,归档时统一);
|
||||
3. **幽灵清仓退役的旧数据影响**:存量库中过去被幽灵清仓转历史的行保持 closed 不变(不回溯);新语义下账本只随交易关联/手动操作走;
|
||||
4. **UI 待老师人工验收项**:多段拆单交互、撤段恢复活动、作废行不显历史层、软提示横幅、策略持仓 tab 不因 QMT 卖光自动消失(须关联卖出单才 close)。
|
||||
@@ -0,0 +1,29 @@
|
||||
# 迭代目标:16-交易关联驱动持仓份额动态调整
|
||||
|
||||
> 迭代编号:16 | 创建:2026-09-08 | 状态:实施中
|
||||
> 依据计划:PLAN-017 | 需求:R-018(已定稿,2026-09-08 老师逐项拍板)
|
||||
|
||||
## 目标描述
|
||||
|
||||
把「交易归属」从纯标签升级为**账本写操作**,落实 R-018 的**数据域分界**:幽灵清仓等同步机制只作用于「全部持仓」对账单域,不再写 strategy_holdings 账本;策略持仓份额只由**交易关联分配器 + 手动份额操作**驱动。
|
||||
|
||||
范围:策略级候选 + 统一份额分配器(委托已成交量拆 0..N 段 × 策略)+ 买卖联动账本(买入加仓/建新仓、卖出减仓/归零清仓、仓不足截断续分、无仓失败提示)+ 撤段逆操作(撤建仓买入=作废第三态、撤加仓=减回归零作废、撤卖出=恢复活动+份额加回,粒度=段)+ 归属分段存储(trade_order_attributions)+ R-017 7 天候选退役 + 漏关联软提示 + PositionSync 删幽灵清仓逻辑。
|
||||
|
||||
## 目标分解(阶段)
|
||||
|
||||
1. **阶段A 数据域分界**:PositionSync 删除幽灵清仓账本写(_autoCloseGhosts 不再 closeHolding),只保留对账单快照同步;漏关联软提示检测基础;
|
||||
2. **阶段B 存储地基**:strategy_holdings 增 `void_at` + `closed_shares`(幂等补列,close 时记录清仓前份额供撤段恢复);新建 `trade_order_attributions` 段表;trade_orders 原两列退役为冗余(读取改经段表);存量单组归属迁移为第一段;
|
||||
3. **阶段C 归属服务**:apply/revoke 判定动作表(买/卖 × 活动仓状态)+ 撤段逆操作 + 原子性(同事务撤旧段+加新段);
|
||||
4. **阶段D 候选与 API**:orders/attribution-candidates 回归「策略级」(R-017 7 天候选退役;holdingId 键控/占位安全逻辑保留);orders/attribution-set(全量替换式)+ attribution-segments(读);
|
||||
5. **阶段E UI 分配器**:TradeRecordsTab 归属入口改策略下拉 + 段量 + 段列表(每段可撤);
|
||||
6. **阶段F 回归**:新回归脚本(分界/分配器动作/撤段/迁移/软提示)+ 存量回归 + typecheck + build。
|
||||
|
||||
## 讨论过程(摘要)
|
||||
|
||||
2026-09-08 讨论收敛全部决策:Q1 策略级候选 / Q2 拆段 / Q3 保留建仓逻辑(份额基于 QMT 持仓创建)/ Q4 已成交量 / Q5 新买入=新仓不复活;R1 无仓卖出关联失败 / R2 分段存储 / R3 撤段逆操作(作废第三态+恢复活动)/ R4 统一分配器(不分子买卖、余额默认全量可改小、允许部分关联)/ R5 买入可拆段 / R6 撤加仓归零作废 / R7 段级取消;数据域分界(幽灵清仓不写账本);T1 关闭(无 30s 竞态);T2 R-017 退役;T3 漏关联软提示。
|
||||
|
||||
## 对老师/主理人的配合需求
|
||||
|
||||
- 重启 DSH web 进程(服务端代码更新)+ 刷新页面人工验收;
|
||||
- 验收通过后迭代 16 标记「验收通过」,R-018 归档 + 需求池索引更新;
|
||||
- 迭代 12(R-014 幽灵清仓条款)、迭代 15(R-017 退役)为既有功能变更,人工验收时一并确认新行为符合预期。
|
||||
@@ -0,0 +1,24 @@
|
||||
# 验收标准:16-交易关联驱动持仓份额动态调整
|
||||
|
||||
> 迭代编号:16 | 依据:PLAN-017 验收要点 + R-018
|
||||
> 验收状态:**已通过(2026-09-08)** —— 口径修订:自动化为主体 + 只读走查;实盘操作类验证项降为「真实使用顺带确认」(老师拍板:实盘不可为验收而操作,边用边发现问题再修)
|
||||
|
||||
## 验收标准线
|
||||
|
||||
1. **数据域分界(阶段A)**:PositionSync 不再写 strategy_holdings——幽灵清仓逻辑删除,同步只维护对账单内存快照;回归脚本断言 storage.closeHolding 不被 PositionSync 调用;
|
||||
2. **存储地基(阶段B)**:strategy_holdings 增 void_at/closed_shares 列(幂等);活动唯一索引收窄至两态皆空;closeHolding 记录 closed_shares(shares 仍置 0);voidHolding 置 void_at;段表 trade_order_attributions 建表 + 存量单组归属迁移为第一段(幂等);
|
||||
3. **份额分配器动作表(阶段C)**:买入段→加仓/建新仓(不复活旧行);卖出段→减仓/归零清仓、仓不足拒绝(segment-exceeds)、无仓拒绝(no-active-holding);撤买入段→减回/归零作废(void,不产生假清仓历史);撤卖出段→加回/恢复活动仓(closed_shares 恢复);跨 holding 段可任意撤、同 holding 乱序撤拒绝(segment-order-conflict)——全量替换 setSegments 原子(失败整体回滚);
|
||||
4. **API(阶段D)**:attribution-targets(策略级 + activityShares);attribution-set(segments 全量替换);attribution-segments(读);今日 orders / trades/history 附加 segments;R-017 7 天候选退役(attribution-candidates/set-attribution 端点退役,候选改由 targets 承担);
|
||||
5. **软提示(T3)**:positions/orphan-hints 返回账本活动行 ∩ QMT 快照缺失的 code(只读不写);
|
||||
6. **自动化**:test-r018-attribution.mjs 29/29 全绿 + test-position-sync 更新后 29/29 + 存量回归(r016 24 / r017 12 / r013 21 / r009 14 / r009-api 13 / r009-sync 8 / r009-normalize 11 / r011-api 12 / r011-tabs 23 / quote-sync 27)全绿 + typecheck + build 通过。
|
||||
|
||||
## 验收方法(2026-09-08 修订,老师拍板)
|
||||
|
||||
- **主体 = 自动化回归**:上述标准线 1-6 由回归脚本 + typecheck + build 机器验证(AI 已执行并出具结果);实盘为真实资金,不可为验收做买卖操作;
|
||||
- **人工只读走查**(老师 2026-09-08 已重启并做一次关联操作确认 OK):分配器界面(余额头/策略下拉带仓数/段 chips)显示正常;仅只读观察,不做实盘写操作;
|
||||
- **顺带确认项(不主动验收,真实使用自然发生时观察)**:卖出全清后策略持仓行不再 30s 自动消失(幽灵退役);顶部漏关联软提示出现;撤段恢复/作废行为——边用边发现问题再修。
|
||||
|
||||
## 验收目标
|
||||
|
||||
- 标准线 1-6(自动化)通过 → 迭代 16 标记「验收通过」;R-018 归档 已完成/ + 需求池索引实现状态更新;
|
||||
- 实盘行为类验证项以「真实使用顺带确认」持续跟进(老师口径:先标记成功,后面边用边发现问题再修)。
|
||||
Reference in New Issue
Block a user