Files

75 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 需求:R-018 交易关联驱动持仓份额动态调整(归属 = 账本写操作)
> 登记:2026-09-08 来源:老师指令(2026-09-08 新优化需求讨论)| 需求状态:**已完成**
> 归档日期:2026-09-08 | 实现迭代:16-交易关联驱动持仓份额动态调整(验收通过 2026-09-08
> 讨论记录索引:R-018.md 正文(Q1-Q5/R1-R7 + 数据域分界 + T2/T3);实现细节见 04-迭代记录/16-交易关联驱动持仓份额动态调整/
> 归档路径:本文件已移入 05-需求池/已完成/
> 迭代状态标记:已定稿(2026-09-08)→ 已实现(迭代 16)→ **已归档(验收通过 2026-09-08,口径=自动化为主体 + 只读走查 + 真实使用顺带确认)**
## 需求描述(一句话)
从**交易记录出发**给委托关联策略/持仓时,**自动同步调整该策略下持仓的份额**(关联即账本写操作),支持一笔委托拆多段分配给不同策略;取消/改归属时做逆操作回滚份额;账本生命周期只由关联交易 + 手动份额操作驱动,同步机制不写账本。
## 〇、数据域分界(最根本前提,2026-09-08 老师拍板)
**「全部持仓」= 对账单域**:唯一数据源 = PositionSyncQMT 快照,10s 内存同步,整体替换)。**包括幽灵清仓在内的一切同步机制只作用于对账单域**,QMT 说了算(老师原话:幽灵清仓本就是一个同步机制,不可以让幽灵把爪子伸太长)。
**「策略持仓」= 账本域(strategy_holdings**:写操作只来自两条通道——
1. **交易关联分配器**(本需求新增):建仓 / 加仓 / 减仓 / 清仓 / 作废;
2. **手动份额操作**(+ 添加持仓 / 移出 / 全部移入):无交易来源时的兜底通道(Q3:保留现在的建仓逻辑;份额以 QMT 持仓信息为基础创建,受「已分配 ≤ 总持仓」校验)。
**既有行为变更**:R-014 定稿的「幽灵自动清仓」(连续 3 轮消失 → closeHolding 本地全部策略当前持仓)**不再写 strategy_holdings**;账本行转历史只由「卖出单关联 → reduceShares 归 0 → closeHolding」产生。影响既有定稿:技术约束-017(幽灵清仓条款)、产品约束-011、R-014、迭代 12(已实现待验收)需修订;PositionSync 删减幽灵清仓逻辑(变更理由 = 本次讨论,写入变更记录)。
## 背景与现状
1. **QMT 实盘持仓**(对账单):PositionSync 10s 内存快照,真实 volume/price(技术约束-017);
2. **本地策略账本** strategy_holdingsshares + 生命周期(open/add/reduce/close),此前靠手动份额操作维护;账本 ≠ 对账单(R-014:holding_id 是交易锚点,不掺易变快照);
3. **交易归属** trade_orders.strategy_id/holding_id:手动设置(R-009/R-017),只做过滤/展示/追溯,**不改数量**——本需求改变这一点。
**展示行关系(防误解)**:策略持仓 tab 当前持仓行 = **QMT 快照 ∩ 账本 shares>0**(行由对账单驱动、份额由账本驱动)。卖出全清 → QMT 无此 code → 展示行随快照消失(≤10s,与幽灵清仓无关);此时账本行仍为当前持仓(closed_at NULL),作为**待关联锚点**保留,直到卖出单被关联。
## 讨论记录(2026-09-08
| # | 决策点 | 结论(老师拍板) |
|---|---|---|
| 1 | 归属候选按什么给?(Q1) | **策略级下拉**,不做预先判断(有无持仓/历史持仓),指向动作发生后按目标策略当时的活动持仓状态现场判定 |
| 2 | 驱动量基准?(Q4 | **已成交量**(撤单/废单不动账) |
| 3 | 交互模型?(R4 统一分配器) | 不分买卖两套流程:一笔委托已成交量可拆 0..N 段(策略×量);待分配余额 = 成交量 − 已分配段和;默认输入 = 余额全量可改小;允许部分关联(剩余保留「未关联」醒目提示);买入卖出均可拆多段 |
| 4 | 买入关联动作?(原始第 2 条) | 该策略有活动持仓 → `addShares` 加仓;无活动持仓(含曾有历史/作废行)→ `openHolding` 建**新仓**(不复活旧行;Q5) |
| 5 | 卖出关联动作?(原始第 3 条) | 活动仓 ≥ 段量 → `reduceShares`,归 0 → `closeHolding`;活动仓 < 段量 → **自动截断**段量=可容纳量归零清仓,余额保留继续分配;该策略无活动持仓 → 关联失败提示(R1) |
| 6 | 撤段逆操作?(R3,粒度=段) | 撤建仓买入段 → 持仓**作废**(新增第三态,非 closeHolding,不产生假清仓历史);撤加仓买入段 → `reduceShares` 减回,归 0 且无真实卖出 → 作废;撤卖出段 → **恢复活动仓 + 份额加回**(撤销语义,区别于 Q5 新买入不接旧仓) |
| 7 | 改归属语义? | 撤旧段 + 加新段,**原子**;撤卖出段若该 holding 已被真实卖出(非本单所致)无法恢复 → 提示不可撤 |
| 8 | 数据域分界?(本轮核心) | 幽灵清仓等同步机制只作用于对账单域;策略持仓写操作只来自交易关联 + 手动份额操作 |
| 9 | T1 卖出关联 vs 幽灵清仓时序竞态 | **关闭**:幽灵不写账本 → 卖出后账本行保留为待关联锚点,无 30s 竞态 |
| 10 | T2 R-0177 天清仓候选) | **退役确认**:新时序下清仓发生在卖出单关联之后,不存在「系统先清、用户后补」场景,候选回归「当前持仓 + 未关联」;R-017 的 holdingId 键控/占位安全逻辑保留 |
| 11 | T3 漏关联兜底 | **软提示确认**:检测「账本有活动行 + QMT 快照无此 code」时提示老师去关联/移出;不自动写账本(不违背分界) |
## 核心规则汇总
| 触发 | 判定 | 动作 |
|---|---|---|
| 买入段 | 该策略该 code 有活动持仓 | `addShares`(加仓,量=段量) |
| 买入段 | 无活动持仓(含曾有历史/作废行) | `openHolding` 建新仓(不复活旧行) |
| 卖出段 | 活动仓 ≥ 段量 | `reduceShares`;归 0 → `closeHolding`(账本转历史唯一途径) |
| 卖出段 | 活动仓 < 段量 | 自动截断:段量=可容纳量 → 归零清仓,余额保留继续分配 |
| 卖出段 | 该策略无活动持仓 | 关联失败提示 |
撤段逆操作:撤建仓买入 → 持仓作废(第三态);撤加仓买入 → 减回归 0 作废;撤卖出 → 恢复活动仓 + 份额加回。改归属 = 撤旧段 + 加新段(原子)。
## 存储 / 模型调整方向
1. **holding 第三态**strategy_holdings 增加作废标记(如 `void_at`);活动 = `closed_at IS NULL AND void_at IS NULL`;作废行不进 R-016 历史「已清仓」层,保留数据可追溯;活动唯一索引(同策略同 code)收窄至两态皆空;
2. **归属单列 → 分段表**:新表(如 `trade_order_attributions`order_id → strategy_id/holding_id/volume/direction/created_at),一笔委托 N 段;R-010 by-holding 与 R-009 history 策略过滤改经段表 join(同一单可出现在多个 holding 展开里);trade_orders 原两列退役或降级为「主归属」快照,已有单组归属迁移为第一段;
3. **软提示(T3**:账本有活动行 + QMT 快照无此 code 时的可见性提示(不动账本)。
## 边界
**做**:幽灵清仓账本侧退役(PositionSync 删幽灵清仓逻辑)+ 策略级候选 + 统一份额分配器(拆段/余额)+ 买卖份额联动 + 撤段逆操作(含作废第三态)+ 归属分段存储 + 查询/展示适配 + R-017 7 天候选退役(holdingId 键控/占位保留)+ 漏关联软提示 + 回归。
**不做**:自动归属推导仍不暴露(可另议);全部持仓 tab / 未分配 tab 份额联动 UI;跨策略「未分配余额」自动兜底;账本写操作自动化兜底(软提示不自动改账本)。
## 验收
见规划后的迭代验收标准(本需求涉及既有已实现功能变更:迭代 12 幽灵清仓语义、迭代 15 R-017 退役,验收需含存量回归)。