From ae4af111f396c95ef5715eee202b0cb97bb370a2 Mon Sep 17 00:00:00 2001 From: hjhan Date: Tue, 11 Aug 2026 10:23:22 +0800 Subject: [PATCH] =?UTF-8?q?refactor(margin):=20=E6=8A=BD=E5=8F=96=20Resolv?= =?UTF-8?q?eMarginOrginPv=20=E4=BF=9D=E8=AF=81=E9=87=91=E7=BB=B4=E5=BA=A6?= =?UTF-8?q?=E9=87=8D=E6=98=A0=E5=B0=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 把 InitSwapDealInterest 里 8 行 inline 的 orginPv 重映射逻辑抽成独立方法 ResolveMarginOrginPv(position, preEodPosition, fallback)。 保证金腿被迫走融资腿差分公式(dynomicPrincipal = TdPrincipal + posi - orginPv), 但 orginPv 对融资腿是'交易名义本金',对保证金腿须对齐到'保证金余额', 否则维度不匹配算出巨负值。提取后 InitSwapDealInterest 更干净, 且新方法待迁入 Margin 模块。 判断从 InterestModeEnum==5||6 改为 MarginModes.Contains(统一口径)。 纯提取, 行为零变化。 验证: 编译0错误, 全量489测试7失败(基线一致)。 --- .../Modules/SwapModule/SwapDealService.cs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 5bc0a222..ffcc5ee7 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -1150,6 +1150,25 @@ namespace YLErp.Modules.SwapModule return InitSwapDealInterest(td, valueDate, endDate, rate, position, add, swap, posiPrincipal, closePrincipal, closePercent, annualDays, eventType, preEod, false, orginPv, calcFirst, calcLast, consumedInterest); } + /// + /// 保证金腿的 orginPv 维度重映射。 + /// + /// 保证金腿被迫走融资腿的差分公式(dynomicPrincipal = TdInterestPrincipal + posiPrincipal - orginPv), + /// 但 orginPv 对融资腿是"交易名义本金(千万~亿级)",对保证金腿必须是"保证金本金"—— + /// 否则维度不匹配会算出巨负值。本方法把保证金场景的 orginPv 对齐到"上一日保证金本金"。 + /// + /// 待迁入 Margin 模块:保证金独立计息入口建好后,此方法移入 MarginAccount/MarginService。 + /// + private decimal ResolveMarginOrginPv(swap_position position, eod_swap_position preEodPosition, decimal fallback) + { + var previousBalance = preEodPosition.InterestPrincipalFix != 0m + ? preEodPosition.InterestPrincipalFix + : preEodPosition.TdInterestPrincipal; + return preEodPosition.id != 0 && previousBalance != 0m + ? previousBalance + : fallback; + } + /// /// 初始化利息腿信息 /// @@ -1203,22 +1222,10 @@ namespace YLErp.Modules.SwapModule interest.ClientId = td.ClientId; interest.UnwindDate = endDate; - // 根因修复:预付金(保证金)腿的计息基数维度应为"保证金本金"自身,而非整笔交易的名义本金(orginPv)。 - // 否则公式 dynomicPrincipal = TdInterestPrincipal + posiPrincipal - orginPv - // 会把交易名义本金(千万~亿级)当减项扣掉,使"应返还本金"(InterestPrincipal)与计息基数变成巨负值。 - // 此处将预付金腿的 orginPv 对齐为上一日保证金本金;无历史归档时才取当前本金。 - // 差分公式必须使用同一时点口径:上一日本金 + 当前本金 - 上一本金 = 当前本金。 - // 若已有部分平仓后仍取当前本金,会把上一日本金原样保留,导致当日继续按平仓前本金计息。 - // 仅作用于初始预付金(5)/追加预付金(6);其它计息模式(含债券本金腿 标的期初全价=9)仍用交易名义本金,不受影响。 - if (position.InterestMode == (int)InterestModeEnum.初始预付金 - || position.InterestMode == (int)InterestModeEnum.追加预付金) + // 保证金腿的 orginPv 对齐到保证金本金维度,避免差分公式维度不匹配算出巨负值 + if (MarginModes.Contains(position.InterestMode)) { - var previousPrincipal = preEodPosition.InterestPrincipalFix != 0m - ? preEodPosition.InterestPrincipalFix - : preEodPosition.TdInterestPrincipal; - orginPv = preEodPosition.id != 0 && previousPrincipal != 0m - ? previousPrincipal - : position.InterestPrincipalFix; + orginPv = ResolveMarginOrginPv(position, preEodPosition, position.InterestPrincipalFix); } if (swap)