From a0be0eb00349e7f73c75416f4e8e1bf597c90249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=90=8D=E9=94=90?= <1565842059@qq.com> Date: Fri, 7 Aug 2026 18:36:32 +0800 Subject: [PATCH] =?UTF-8?q?fix(swap):=20=E4=BF=AE=E5=A4=8D=E5=A4=8D?= =?UTF-8?q?=E5=88=A9=E5=B9=B3=E4=BB=93=E6=97=B6=E5=B7=B2=E7=BB=93=E5=88=A9?= =?UTF-8?q?=E6=81=AF=E6=89=A3=E9=99=A4=E8=AE=A1=E7=AE=97=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 CalcCompoundUnwind 方法添加 closePercent 参数用于部分平仓场景 - 更新复利平仓逻辑,将已结利息按平仓比例进行缩放扣除 - 添加部分平仓测试用例验证已结利息按比例扣除的正确性 - 修复了全部已结利息在部分平仓时被全额扣除的问题 --- .../SwapModule/ConsumedInterestScenarioTest.cs | 18 ++++++++++++++++-- YLErpDAL/Modules/SwapModule/SwapDealService.cs | 6 +++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/UnitTestProject/Modules/SwapModule/ConsumedInterestScenarioTest.cs b/UnitTestProject/Modules/SwapModule/ConsumedInterestScenarioTest.cs index d2f56e52..2d2b9016 100644 --- a/UnitTestProject/Modules/SwapModule/ConsumedInterestScenarioTest.cs +++ b/UnitTestProject/Modules/SwapModule/ConsumedInterestScenarioTest.cs @@ -108,13 +108,13 @@ namespace YLErp.Modules.SwapModule } /// 调用 GetInterests 获取复利利息(统一调用入口,settment:false走盘中平仓路径) - private static swap_flow_event CalcCompoundUnwind(StubSwapDealService service, DateTime unwindDate) + private static swap_flow_event CalcCompoundUnwind(StubSwapDealService service, DateTime unwindDate, decimal closePercent = 1m) { var td = CreateTrade(); var position = CreateCompoundPosition(); var interests = service.GetInterests(td, td.trade_extend, unwindDate, unwindDate, new List(), new List { position }, - Principal, Principal, Principal, Principal, 1m, + Principal, Principal, Principal, Principal, closePercent, (int)SwapEventTypeEnum.平仓, false, false, Principal, Principal, add: false, settment: false, newCalcLast: false); Assert.AreEqual(1, interests.Count); @@ -246,5 +246,19 @@ namespace YLErp.Modules.SwapModule $"全部已结再平仓利息应≈0(实际={result.InterestAmount:F6}),不应为负"); Console.WriteLine($"全部已结平仓≈0({result.InterestAmount:F6})✅"); } + + [TestMethod] + public void CI_005_partialClose_scalesConsumedInterest() + { + var unwindDate = StartDate.AddDays(10); + const decimal closePercent = 0.4m; + const decimal consumed = 100m; + + var baseline = CalcCompoundUnwind(CreateService(0m), unwindDate, closePercent).InterestAmount; + var result = CalcCompoundUnwind(CreateService(consumed), unwindDate, closePercent).InterestAmount; + + AssertDecimal(baseline - consumed * closePercent, result, + $"partial close should deduct consumed interest by closePercent ({closePercent})"); + } } } diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index c4c3a504..53bcaff6 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -1294,9 +1294,9 @@ namespace YLErp.Modules.SwapModule } // 复利从头重放得到的是"假设从未结出"的整段总利息,需扣除历史已通过互换结出的利息, // 否则已结部分会重复计息(类比分红 PosiDividendSum = totalToDate − RealizedDividend)。 - // consumedInterest 为绝对值口径(swap_flow_event.InterestAmount 之和),与 interest 口径一致。 - interest -= consumedInterest; - tdinterest -= consumedInterest; + // consumedInterest is full-position absolute interest; scale it to this close portion. + interest -= consumedInterest * closePercent; + tdinterest -= consumedInterest * closePercent; InterestAmount = Math.Round(interest, InterestCalculationPrecision, MidpointRounding.AwayFromZero); TdInterestAmount = Math.Round(tdinterest, InterestCalculationPrecision, MidpointRounding.AwayFromZero); }