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)