From 48ae429fb8c10eb39186d3ed1c48ab6955231d5d Mon Sep 17 00:00:00 2001 From: hjhan Date: Thu, 20 Aug 2026 13:37:24 +0800 Subject: [PATCH] =?UTF-8?q?refactor(swap):=20EQD-6977=20=E6=B6=88=E9=99=A4?= =?UTF-8?q?=E7=BD=9A=E6=81=AF=E6=8E=A5=E7=BC=9D=E4=BB=A3=E7=A0=81=E8=87=AD?= =?UTF-8?q?=E5=91=B3=E9=81=93=E2=80=94=E2=80=94CalcPenalty=20=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=E5=86=97=E4=BD=99valueDate=E5=8F=82=E6=95=B0=E3=80=81?= =?UTF-8?q?ComputeCarryBreakdown=20=E5=8E=BB=E6=8E=89=E6=9C=AA=E4=BD=BF?= =?UTF-8?q?=E7=94=A8position=E3=80=81GetIntradayUnwindInterests=20?= =?UTF-8?q?=E5=86=85=E8=81=94=E5=9D=97=E6=8A=BD=E4=B8=BA=E7=A7=81=E6=9C=89?= =?UTF-8?q?AppendPenaltyInterests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Penalty/PenaltyInterestAppender.cs | 4 +- .../Penalty/SwapPenaltyInterestCalculator.cs | 11 ++--- .../Modules/SwapModule/SwapDealService.cs | 40 +++++++++++-------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/Penalty/PenaltyInterestAppender.cs b/YLErpDAL/Modules/SwapModule/Penalty/PenaltyInterestAppender.cs index 948845af..6439f85c 100644 --- a/YLErpDAL/Modules/SwapModule/Penalty/PenaltyInterestAppender.cs +++ b/YLErpDAL/Modules/SwapModule/Penalty/PenaltyInterestAppender.cs @@ -68,12 +68,12 @@ public static class PenaltyInterestAppender var policy = AccrualPolicy.BuildEod(position, annualDays, position.InterestType == (int)InterestTypeEnum.复利); var (capitalized, carryIn) = SwapPenaltyInterestCalculator.ComputeCarryBreakdown( - position, unwindDate, resetAnchor, frozenRate, policy, closePrincipal); + unwindDate, resetAnchor, frozenRate, policy, closePrincipal); var penalty = SwapPenaltyInterestCalculator.CalcPenalty( td, position, closePrincipal, unwindDate, maturityDate, unwindDaySettled, maturityCalcLast, capitalized, carryIn, - frozenRate, policy, resetAnchor, eventType, unwindDate); + frozenRate, policy, resetAnchor, eventType); penalty.IsPenaltyInterest = 1; interests.Add(penalty); diff --git a/YLErpDAL/Modules/SwapModule/Penalty/SwapPenaltyInterestCalculator.cs b/YLErpDAL/Modules/SwapModule/Penalty/SwapPenaltyInterestCalculator.cs index fd41a03e..c8a4bfa3 100644 --- a/YLErpDAL/Modules/SwapModule/Penalty/SwapPenaltyInterestCalculator.cs +++ b/YLErpDAL/Modules/SwapModule/Penalty/SwapPenaltyInterestCalculator.cs @@ -42,13 +42,11 @@ public static class SwapPenaltyInterestCalculator /// 合约原始到期日(窗口终点,= td.ExerciseDate) /// 正常平仓利息是否已计平仓日(effectiveCalcLast = calcLast || newCalcLast) /// 交易到期日算尾约定(tradeExtend.CalcLast) - /// 复利承接:被平部分已计至平仓日利息(正常平仓流 InterestAmount);单利传 0 - /// 冻结利率(PenaltyLegRateResolver.ResolveFrozenRate 产物) + /// 冻结利率(PenaltyLegRateResolver.ResolveFrozenRate 产物) /// 计息政策(单复利/重置周期/年化天数;Convention 由本方法覆盖) /// 重置日锚点(对齐 GetFloatRate 的 td.StartDate 口径;锚点二义性注记见其声明) /// 事件类型(平仓) - /// 操作日期 - /// 计息轨迹(可选,SwapCalcTrace 落盘) + /// 计息轨迹(可选,SwapCalcTrace 落盘) public static swap_flow_event CalcPenalty( trade td, swap_position position, @@ -63,7 +61,6 @@ public static class SwapPenaltyInterestCalculator AccrualPolicy policy, DateTime resetAnchor, int eventType, - DateTime valueDate, AccrualTrace? trace = null) { var boundary = AccrualBoundary.Of(includeStart: !unwindDaySettled, includeEnd: maturityCalcLast); @@ -82,7 +79,7 @@ public static class SwapPenaltyInterestCalculator SwapTradeNo = td.TradeNumber, EventType = eventType, EventReason = PenaltyEventReason, - EventDate = valueDate, + EventDate = unwindDate, UnwindDate = unwindDate, PositionId = position.id, InterestDirection = position.InterestDirection, @@ -181,7 +178,7 @@ public static class SwapPenaltyInterestCalculator /// 单利(无重置)时窗口无 carry:capitalized=全段利息、carryIn=0。 /// public static (decimal Capitalized, decimal CarryIn) ComputeCarryBreakdown( - swap_position position, DateTime unwindDate, DateTime resetAnchor, + DateTime unwindDate, DateTime resetAnchor, FundingLegRate frozenRate, AccrualPolicy policy, decimal closePrincipal) { if (policy.ResetPeriodDays <= 1) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 58004c90..99f4cde0 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -627,25 +627,33 @@ namespace YLErp.Modules.SwapModule req.OrginPv, req.Add, settment: false, req.NewCalcLast, req.CloseList); // EQD-6977 罚息:在 GetInterests 返回后追加(避开其 closeList 去重块),仅手动平仓路径(isPenaltyInterest)触发。 if (req.IsPenaltyInterest) - { - var fundingPositions = req.Positions.Where(p => !MarginModes.Contains(p.InterestMode)).ToList(); - var annualDays = req.TradeExtend == null ? 365 : req.TradeExtend.ExtendObj.AnnualDays; - var calcLast = req.TradeExtend?.ExtendObj.CalcLast ?? true; - var trace = new AccrualTrace(); - PenaltyInterestAppender.Append( - req.Td, fundingPositions, interests, req.UnwindDate, annualDays, - unwindDaySettled: calcLast || req.NewCalcLast, - maturityCalcLast: calcLast, - req.PosiNotionalValue, req.ClosePosiNotionalValue, req.ClosePercent, - getSpread: p => GetFixedRate(p, req.UnwindDate), - getPreEodFloatRate: p => req.EodPositions.FirstOrDefault(x => x.PositionId == p.id)?.FloatRate, - tryGetFixing: (d, code) => IndexFixer.TryGetFixing(d, code, out decimal r) ? (decimal?)r : null, - trace: trace); - SwapCalcTrace.Write(trace); // 与既有 4 处 SwapCalcTrace.Write 同款常驻落盘 - } + AppendPenaltyInterests(req, interests); return interests; } + /// + /// EQD-6977 罚息接缝(委托注入 + 轨迹落盘):在 GetInterests 返回后把同构罚息流追加进列表。 + /// 仅在此处耦合上帝类的利率解析(GetFixedRate / IndexFixer)与轨迹常驻落盘(SwapCalcTrace.Write), + /// 其余罚息计息数学全部下沉至 Penalty 模块,保持上帝类最小侵入。 + /// + private void AppendPenaltyInterests(InterestCalcRequest req, List interests) + { + var fundingPositions = req.Positions.Where(p => !MarginModes.Contains(p.InterestMode)).ToList(); + var annualDays = req.TradeExtend == null ? 365 : req.TradeExtend.ExtendObj.AnnualDays; + var calcLast = req.TradeExtend?.ExtendObj.CalcLast ?? true; + var trace = new AccrualTrace(); + PenaltyInterestAppender.Append( + req.Td, fundingPositions, interests, req.UnwindDate, annualDays, + unwindDaySettled: calcLast || req.NewCalcLast, + maturityCalcLast: calcLast, + req.PosiNotionalValue, req.ClosePosiNotionalValue, req.ClosePercent, + getSpread: p => GetFixedRate(p, req.UnwindDate), + getPreEodFloatRate: p => req.EodPositions.FirstOrDefault(x => x.PositionId == p.id)?.FloatRate, + tryGetFixing: (d, code) => IndexFixer.TryGetFixing(d, code, out decimal r) ? (decimal?)r : null, + trace: trace); + SwapCalcTrace.Write(trace); // 与既有 4 处 SwapCalcTrace.Write 同款常驻落盘 + } + public List GetInterests( trade td, trade_extend tradeExtend,