Merge remote-tracking branch 'origin/glms/feature/1.4.2' into glms/feature/1.4.2
This commit is contained in:
@@ -178,6 +178,10 @@
|
||||
> 这一章回答一个关键质疑:两页口径不同,凭什么断定是 income 漏了 `longRatio`、而不是 unwind 多算了?
|
||||
> 以及:给 income 补 `longRatio` 会不会把正确逻辑改坏、或造成"双重翻转"?
|
||||
|
||||
> ⚠️ **状态说明(2026-08-07)**:本章关于"income 漏 longRatio → 错 / unwind 对"的论断,目前是**待业务背书的 Working Hypothesis**,
|
||||
> 尚未取得业务/量化签字。且比这更基础的"收益结算的价差基准是否应在结算后滚动"的产品定义仍未确认(见第八章)。
|
||||
> **在业务下定论前,本章仅作论证记录,不视为最终定性**——第八章才是如实记录"代码现在实际怎么做"的事实层。
|
||||
|
||||
### 7.1 两个方向乘子是**独立轴**(这是避免误判的前提)
|
||||
|
||||
- `floatRatio = PayDirection==1(收取) ? +1 : -1` —— 跟随**收付方向**(`FrontendCalcReference.cs:35`)
|
||||
@@ -228,3 +232,98 @@
|
||||
- **历史脏数据**:过去"空头+互换"事件已用错符号落库;修复后新事件正确,跨时间对比会出现不连续。需决定:回溯校正(改 `MarkClosePnl`+重算 `SwapRealizedPnl`+对账 `AddClientCash` 历史)还是标注留痕。
|
||||
- **改动范围**:严格限定在 income 页 `:207` 与 `CalcIncome:107` 补 `longRatio`,切忌顺手改 `floatRatio` 或其他页面。
|
||||
4. **前置确认**:建议先让业务/量化签字"income 的 `MarkClosePnl` 应含多空方向(与平仓一致)",再动手——因为结论虽由代码+基线铁证支撑,但涉及客户现金流,需业务背书。
|
||||
|
||||
---
|
||||
|
||||
## 八、当前行为实录与待确认项(2026-08-07)
|
||||
|
||||
> 本章**只记录"代码现在实际怎么做"**(可验证事实),并明确列出"哪些还无法判定谁对"。
|
||||
> 与第七章(论断层)的区别:第七章给出了"income 错 / unwind 对"的论证,但该论断**尚未取得业务/量化背书**,
|
||||
> 且涉及"价差基准是否应在收益结算后滚动"这一更基础的产品定义。因此把它们在本章降格为"待确认假设",
|
||||
> 先如实记录现状,避免过早定性。
|
||||
> 文档定位:**当前不修改代码、不加测试,仅留痕**。正确性待业务/量化逐项确认后再回填。
|
||||
|
||||
### 8.1 收益结算(income)页当前行为实录
|
||||
|
||||
- **界面入口**:交易详情页头部操作区「**收益结算**」按钮(权限 `交易管理_收益互换`),打开 `/swaptrade2/SwapIncome/`
|
||||
(`SwapIncome.cshtml` + `incomeSwapTrade.js`)。与「**平仓**」按钮(`SwapUnwind.cshtml`)外观相似,
|
||||
但**没有平仓比例、没有事件日期**——本质是"期间结算、头寸保留",而非关闭头寸。
|
||||
- **价差损益 `MarkClosePnl` 当前公式(代码事实)**:
|
||||
- `incomeSwapTrade.js:104` `initPosiGrossPrice = this.floatPosition.PosiGrossPrice`
|
||||
- `:199/207` `floatRatio = PayDirection==1 ? 1 : -1`
|
||||
- `:207` `MarkClosePnl = positionAmount × (deliveryPrice − initPosiGrossPrice) × floatRatio`
|
||||
(`positionAmount = PositionQty × ContractSize`,`deliveryPrice = getStorageDeliveryPrice()`)
|
||||
- 后端同口径 `FrontendCalcReference.CalcIncome:107`:**无 `longRatio`**,`CalcIncome:92` 注释明示"无 longRatio"。
|
||||
- **事实结论**:income 页当前**只用 `floatRatio`(收付方向)翻转,未乘 `longRatio`(多空方向)**。
|
||||
|
||||
### 8.2 价差基准 `swap_position.PosiGrossPrice` 当前行为实录
|
||||
|
||||
- **开仓时**:`PosiGrossPrice = TradingAmountAvg`(成交/期初全价,`SwapTradeService.cs:396`),规范名 `EntryDirtyPrice`
|
||||
(`FrontendCalcReference.cs:15/156`)。
|
||||
- **收益结算后**:`UpdateInitalPosition`(`SwapDealService.cs:2276-2281`)对"互换"分支**只更新费用 `PosiTradingFee`,不改 `PosiGrossPrice`**;
|
||||
`SwapIncome`(`:2005`)直接落库、**不调用** `UpdateInitalPosition`。
|
||||
- **平仓后**:`SaveSwapDealInternal`(`:2212`)只改 `Quantity/PositionQty`,不改动基准价含义。
|
||||
- **EOD 日终**:`SwapEodPositionService` 操作的是快照表 `eod_swap_position`,其 `PosiGrossPrice` 为成本基准、
|
||||
靠 `eod.Clone()` 跨日结转(`CopyEodPosition:1688`),每日行情价只写入 `UnderlyingPrice`(`:1716`),**不覆盖成本基准**。
|
||||
活表 `swap_position.PosiGrossPrice` 最终由 EOD 回写(`UpdateSwapPosition:62` / `UpdateSwapPositionWithRealTime:85`),
|
||||
但回写的仍是"成本基准"而非当日行情价。
|
||||
- **事实结论**:`swap_position.PosiGrossPrice` 在持仓生命周期内**恒等于开仓期初价 P0,从不滚动到上一次结算价**。
|
||||
|
||||
### 8.3 已确认事实 vs 待确认假设 对照
|
||||
|
||||
| 项 | 已确认事实(代码可验证) | 待确认假设(需业务/量化背书) |
|
||||
|----|--------------------------|------------------------------|
|
||||
| income 是否含 `longRatio` | 当前**不含**(code 实证) | 是否**应该**含(与平仓一致)?——第七章论证"应含",但**未获业务签字** |
|
||||
| 空头 income 符号 | 当前公式对空头会得出与平仓/后端**相反**的符号 | 这是否是"错误"?取决于产品对空头收益结算现金流的符号约定 |
|
||||
| 价差基准是否滚动 | 当前**不滚动**(恒为 P0) | 收益结算应是"增量(从上次结算价)"还是"绝对(从 P0)"?——**产品定义未确认** |
|
||||
| 多次收益结算重复计入 | 当前若对**同一开放持仓做多次收益结算**,每次都按 (当前价−P0) 计,**首段会被重复计入**(数学推导) | 业务实际是否允许/发生过"同一持仓多次收益结算"?——**需生产数据确认** |
|
||||
| 下游现金流 | `SwapIncome:2007` `AddClientCash(-SwapRealizedPnl)` 用前端值记账(code 实证) | 若公式口径需改,历史已落库金额是否需追溯校正? |
|
||||
|
||||
### 8.4 待确认问题清单(请业务 / 量化 / 产品逐项答复)
|
||||
|
||||
1. **空头收益结算的符号约定**:空头 TRS 做期间结算,客户现金流方向应是"空头涨价=亏"(与平仓一致,即含 `longRatio`)还是相反?
|
||||
请给出业务样例与会计分录。
|
||||
2. **收益结算的价差口径**:期间结算的 `MarkClosePnl` 应是"本段增量"(结算后把持仓基准滚动到本次结算价)还是"从开仓期初价累计"?
|
||||
两者在"单次结算后随即平仓"时数值相同,但在**多次结算 / 结算后仍保留持仓**时相差巨大。
|
||||
3. **是否存在"同一开放持仓多次收益结算"的真实业务场景**?若有,当前"不滚动基准"会导致重复计入,必须修;
|
||||
若无(每次结算后即关仓),则当前行为无害、仅作防御性加固。
|
||||
4. **多空与收付是否允许非对角组合**(`多头+收取` / `空头+支付`)?若存在,则"收支/多空"两字段非冗余、必须分别存储;
|
||||
若不存在(vanilla TRS 永远反向),则可视为冗余但当前仍各存各的。
|
||||
|
||||
### 8.5 验证脚本(用于把"待确认"转为"已确认")
|
||||
|
||||
```sql
|
||||
-- (a) 是否存在「空头 + 走收益结算/互换路径」且 MarkClosePnl 非 0 的事件
|
||||
SELECT trade_id, position_id, event_type, position_type, pay_direction,
|
||||
mark_close_pnl, value_date
|
||||
FROM swap_event
|
||||
WHERE position_type = 2
|
||||
AND event_type IN ('互换','结息') -- 按实际枚举值调整
|
||||
AND mark_close_pnl <> 0
|
||||
ORDER BY value_date DESC;
|
||||
|
||||
-- (b) 同一持仓是否被多次收益结算(判断是否触发"基准不滚动 → 重复计入")
|
||||
SELECT position_id, COUNT(*) cnt, MIN(value_date) first_dt, MAX(value_date) last_dt
|
||||
FROM swap_event
|
||||
WHERE event_type IN ('互换','结息') -- 按实际枚举值调整
|
||||
GROUP BY position_id
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY cnt DESC;
|
||||
```
|
||||
- 若 (a) 返回 0 行 → 当前无"空头收益结算"样本,longRatio 不一致问题**未实际触发**;
|
||||
- 若 (b) 返回 0 行 → 当前业务每次结算后即关仓,"基准不滚动"**无害**;
|
||||
- 若 (b) 有行 → 立即按"结算后把 `swap_position.PosiGrossPrice` 滚动到本次结算价"评估修复。
|
||||
|
||||
### 8.6 多轮回归未暴露的原因(实证,非推断)
|
||||
|
||||
1. **覆盖空洞**:`FrontendCalcCharacterizationTest` 的 income 场景 `FC_006~009` **全是 `PositionType=1`(多头)**;
|
||||
唯一空头场景 `FC_005` 是 unwind。income 的空头分支从未被构造。
|
||||
2. **校验同源**:`ValidateFrontendPnL`(`SwapDealService.cs:2004`)用 `BuildFrontendValidationDiffs` 以**同一 `CalcIncome`(也无 longRatio)**
|
||||
重算比对,前端错值 == 后端重算 → diff 恒为 0 → 永不告警("预言机与被测代码共享同一 bug"盲区)。
|
||||
3. **真实数据隐形**:golden `dividend_trade_1875/1891.json` 中,空头块为 `swap_position` 持仓行(`MarkClosePnl=0`),非结息事件;
|
||||
真实样本从未走空头 income。
|
||||
4. **多头恒等变换**:income 漏的是 `longRatio`,而多头 `longRatio=+1` 是恒等变换,故整个多头组合
|
||||
(≈100% 真实数据 + 100% 回归)下两页数值一致,bug 不可见。
|
||||
|
||||
> 注:第 1–4 点解释的是"longRatio 不一致为何没被抓到"。而 8.2/8.4 的"基准不滚动"问题,
|
||||
> 即便被测也需"多次收益结算"样本才能触发,现有单笔 income / 单笔 close 测试同样覆盖不到——属另一类盲区。
|
||||
|
||||
Reference in New Issue
Block a user