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,