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,