From 01447ffe0404d20d656d4da06b73e1f95f2eb41d Mon Sep 17 00:00:00 2001 From: hjhan Date: Fri, 14 Aug 2026 15:39:44 +0800 Subject: [PATCH] =?UTF-8?q?refactor(swap):=20GetInterests=20=E4=BC=A0?= =?UTF-8?q?=E5=8F=82=E8=AF=AD=E4=B9=89=E6=98=BE=E5=BC=8F=E5=8C=96=E2=80=94?= =?UTF-8?q?=E2=80=94=E7=9B=98=E4=B8=AD/EOD=E5=B9=B3=E4=BB=93=E5=90=8E?= =?UTF-8?q?=E6=94=B6=E7=9B=98=E6=8B=86=E5=8F=8C=E6=98=BE=E5=BC=8F=E5=85=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:GetInterests 同名参数在两类调用方下语义相反,约定只存在于注释(2035e1df 固化): 盘中(:489链) EOD平仓后收盘(:1311链) posiNotionalValue 平仓前剩余本金 vs 平仓后剩余本金 closePercent 实际平仓比例(B) vs 恒1(全额结息) 均走 settment:false 盘中重放算法。6fdc7d80 修的错账即两语义混用产物, mode2 无条件覆盖/mode9 全平兜底是粘合补丁。 改动(纯机械,零行为变化): - SwapDealService 新增 GetIntradayUnwindInterests(preCloseNotional/closedNotional/ closePercentRemaining 具名),GetUnwindInterests 切换调用;needPrice/grossPrice 为 GetInterests 死参数(体内零消费),新入口不再暴露 - SwapEodPositionService 新增虚接缝 CalcEodPostCloseSettleInterests (remainingNotionalAfterClose/closedNotional/恒1),默认实现经 CalcSwapInterests 转发——既有测试替身对该接缝的拦截不变;SaveAutoEodWithCloseInterestPosition 切换调用 - 原 GetInterests/CalcSwapInterests 签名与行为不动(测试直调兼容);EOD 增量路径 (:1148/:1563, settment:true, closePosi=posi 同值) 语义自洽,本次不动 验证:全量 899 测试 145失败/742通过/12跳过——与 e2431e9d 基线逐位一致,零回归。 --- .../Modules/SwapModule/SwapDealService.cs | 39 ++++++++++++++++++- .../SwapModule/SwapEodPositionService.cs | 35 +++++++++++++++-- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 7e69e78b..b22c70e7 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -486,7 +486,10 @@ namespace YLErp.Modules.SwapModule && eventTypes.Contains(x.EventType) && x.DataState == (int)SwapFlowDateStateEnum.完成).ToList(); bool tdClose = closeList.Count > 0; - interests = GetInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions, stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue, closePercent, eventType, tdClose, false, grossPrice ?? 0, orginPv, true, false,false, closeList); + // 显式入口(语义见 GetIntradayUnwindInterests 注释):平仓前剩余本金 + 实际平掉额 + B语义比例,盘中重放 + interests = GetIntradayUnwindInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions, + stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue, + closePercent, eventType, tdClose, orginPv, add: true, newCalcLast: false, closeList); return interests; } @@ -616,6 +619,40 @@ namespace YLErp.Modules.SwapModule /// /// /// + /// + /// 【盘中平仓/互换结息】显式入口——GetInterests(settment:false) 盘中语义的具名封装(2026-08 显式化重构)。 + /// + /// 语义契约(与 EOD 平仓后收盘的 CalcEodPostCloseSettleInterests 相反,勿混用): + /// preCloseNotional = 平仓【前】实时剩余本金(原 GetUnwindInterests 的 stockEqvNotional); + /// closedNotional = 本次实际平掉本金(= preCloseNotional × closePercentRemaining); + /// closePercentRemaining = 平仓比例,B 语义【占剩余】(前端传 A 占期初,须先经 ToRemainingClosePercent 转换); + /// 计息走 CalcUnwindInterest 全区间重放(orginPv 参与保证金腿差分)。 + /// + /// needPrice/grossPrice 为 GetInterests 的历史死参数(方法体内无消费),本入口不再暴露。 + /// + public List GetIntradayUnwindInterests( + trade td, + trade_extend tradeExtend, + DateTime valueDate, + DateTime unwindDate, + List eodPositions, + List positions, + decimal preCloseNotional, + decimal preCloseLongNotional, + decimal preCloseShortNotional, + decimal closedNotional, + decimal closePercentRemaining, + int eventType, + bool tdClose, + decimal orginPv, + bool add, + bool newCalcLast, + List closeList) + => GetInterests(td, tradeExtend, valueDate, unwindDate, eodPositions, positions, + preCloseNotional, preCloseLongNotional, preCloseShortNotional, closedNotional, + closePercentRemaining, eventType, tdClose, needPrice: false, grossPrice: 0m, + orginPv, add, settment: false, newCalcLast, closeList); + public List GetInterests( trade td, trade_extend tradeExtend, diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index be097caf..795b5829 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -102,6 +102,33 @@ namespace YLErp.Modules.SwapModule grossPrice, orginPv, add, settment, newCalcLast, closeList); } + /// + /// 【EOD 当日有平仓后的收盘结息】显式入口——原 SaveAutoEodWithCloseInterestPosition 直调 + /// CalcSwapInterests(settment:false) 的具名封装(2026-08 显式化重构)。 + /// + /// 语义契约(与盘中 SwapDealService.GetIntradayUnwindInterests 相反,勿混用): + /// remainingNotionalAfterClose = 平仓【后】剩余本金(GetInterests.posiNotionalValue 形参位); + /// closedNotional = 本次实际平掉本金(GetInterests.closePosiNotionalValue 形参位); + /// 结息比例恒 1(本次事件全额结息)。该组合会触发 GetInterests 内 mode2 无条件覆盖 / + /// mode9 全平兜底(见其"根因位置"注释,勿删)。 + /// 计息走 CalcUnwindInterest 全区间重放(settment:false)。 + /// + /// 默认实现仍经 CalcSwapInterests 转发,保持既有测试替身对该虚接缝的拦截不变。 + /// + protected virtual List CalcEodPostCloseSettleInterests( + trade td, trade_extend tradeExtend, + DateTime valueDate, DateTime unwindDate, + List eodPositions, List positions, + decimal remainingNotionalAfterClose, decimal remainingLongNotional, decimal remainingShortNotional, + decimal closedNotional, + int eventType, bool tdClose, + decimal grossPrice, decimal orginPv, + bool add, bool newCalcLast) + => CalcSwapInterests(td, tradeExtend, valueDate, unwindDate, eodPositions, positions, + remainingNotionalAfterClose, remainingLongNotional, remainingShortNotional, + closedNotional, 1m, eventType, tdClose, needPrice: true, grossPrice, orginPv, + add, settment: false, newCalcLast, closeList: null); + // FindTrade 已上提到基类 SwapTradeBaseService(三子类实现一致,消除重复) /// 查找交易扩展(生产: DbContext.trade_extend;测试: 内存字典) @@ -1306,9 +1333,11 @@ 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); + // 显式入口(语义见 CalcEodPostCloseSettleInterests 注释):平仓后剩余本金 + 实际平掉额 + 恒1全额结息。 + // 该组合会触发 GetInterests 内共享计息器的模式2/9本金修正(见其"根因位置"注释,勿删)。 + var interests = CalcEodPostCloseSettleInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, + posiNotionalValue, posiLongNotional, posiShortNational, closeNational, + eventType, tdClose: false, grossPrice, orginPv, add: true, newCalcLast: autoSwap || calcLast); // TdInterestAmount:计息器返回的全腿当日/累计参考值,用于拆出 EOD 的当日新增。 // interestAmountBeforeSettlement:本次事件发生前理论应结的高精度利息。 // manualSettledInterestAmount:swap_flow_event 实际落库的手工结息,金额已按分处理。