diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 367cef46..307f3b5f 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -860,9 +860,17 @@ namespace YLErp.Modules.SwapModule posiPrincipal = r.PosiPrincipal; newClosePercent = r.ClosePercent; } + // 根因位置:SwapEodPositionService.SaveAutoEodWithCloseInterestPosition 在平仓后收盘时传入 + // “收盘后剩余本金 + closePercent=1”,与盘中“平仓前本金 + 实际关闭比例”不是同一语义。 + // GetInterests 同时被盘中试算和 EOD 平仓后收盘调用:后者传入的 + // posiNotionalValue 是收盘后的剩余本金,closePosiNotionalValue 才是本次实际平掉的本金。 + // 例如平仓前 100、平掉 30、收盘后剩余 70 时,EOD 传入 posi=70、close=30、closePercent=1。 + // 模式2(合约名义本金规模)的本次结息本金必须始终是实际平仓额,因此无条件覆盖, + // 否则会错误地用剩余 70 结算本次平掉的 30。模式9(标的期初全价)的部分平仓 + // 仍保留既有的剩余/复利动态本金承接逻辑;仅最终全平时 posi=0,才覆盖以避免结息本金为 0。 if ((InterestModeEnum)position.InterestMode == InterestModeEnum.合约名义本金规模 - || (InterestModeEnum)position.InterestMode == InterestModeEnum.标的期初全价 - && posiNotionalValue == 0m) + || ((InterestModeEnum)position.InterestMode == InterestModeEnum.标的期初全价 + && posiNotionalValue == 0m)) { closePrincipal = closePosiNotionalValue; } diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index c70476bb..f8d9dabb 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1293,6 +1293,11 @@ namespace YLErp.Modules.SwapModule var tradeExtend = td.trade_extend.ExtendObj; // oriPosiNotionalValue 是平仓前规模,posiNotionalValue 是收盘后剩余规模,closeNational 是本次关闭规模。 // 例如 30% 平仓:303139117.80 = 212197382.46 + 90941735.34。 + // 注意:此处的 posiNotionalValue 与盘中 GetUnwindInterests 传给 GetInterests 的语义不同: + // 盘中传平仓前的当前剩余本金,EOD 此处传平仓后的剩余本金;后面又以 closePercent=1 + // 调用共享计息器。因此策略的 "posiNotional × closePercent" 在本例会得到 212197382.46, + // 而本次实际应结的平仓本金是 closeNational=90941735.34。该语义错位由 + // SwapDealService.GetInterests 的模式2无条件修正、模式9全平零值兜底分流处理,不能删除。 decimal oriPosiNotionalValue = posiLongNotional + posiShortNational + closeNational; decimal posiNotionalValue = posiLongNotional + posiShortNational; // ratio 只负责把腿内原始金额转换为本方盈亏方向,不参与计息金额本身的计算。 @@ -1360,6 +1365,8 @@ namespace YLErp.Modules.SwapModule List preEodPositions = new List(); preEodPositions.Add(eodPayPosition); var calcLast = tradeExtend?.InterestCalcMode?.EndsWith("1") ?? true; + // 此处 closePercent=1 表示 EOD 计算本次事件时走全额结息;它不是 closeNational / oriPosiNotionalValue。 + // 与上方“收盘后剩余本金”同时传入会触发共享计息器的模式2/9本金修正,见 GetInterests。 var interests = CalcSwapInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNotional, posiShortNational, closeNational, 1, eventType, false, true, grossPrice, orginPv, true, settment: false, newCalcLast: autoSwap || calcLast); // TdInterestAmount:计息器返回的全腿当日/累计参考值,用于拆出 EOD 的当日新增。 // interestAmountBeforeSettlement:本次事件发生前理论应结的高精度利息。