using YLErp.Derivatives.Interest; using YLErp.Modules.SwapModule.Accrual; namespace YLErp.Modules.SwapModule.Penalty; /// /// EQD-6977 罚息冻结利率解析(纯函数)。 /// /// 规则(需求 2.2.2):剩余期限利率冻结为「最后一个重置区间」的 FR007 定盘值—— /// 终止日恰为重置日且下午已出新价时,仍取上一重置区间(边缘场景显式落地)。 /// /// 冻结来源优先级: /// 1. preEod.FloatRate——上一日终快照即昨日「实际在役」利率(GetFloatRate 非重置日正是沿用它), /// 天然覆盖重置日下午边缘;且避开 td.StartDate / PosiStartDate 双锚点推导(见 GetFloatDate 锚点注记); /// 2. 无 preEod(首日平仓等):取价日 = GetFixingDate(unwindDate-1)(-1 所在重置区间的定盘, /// interest_rule 0=当前营业日/-1=前一营业日由 IndexFixerBase 统一处理)。 /// 固定腿利率本即冻结,直接 Fixed;剩余期限的加点利差由调用方按 SwapIntervalList 取 as-of 平仓日值传入。 /// public static class PenaltyLegRateResolver { /// /// 解析罚息窗口的冻结 all-in 利率。 /// /// 利息腿(融资腿,非保证金) /// 加点利差(调用方按 SwapIntervalList 取 as-of unwindDate 值,同 GetFixedRate 口径) /// 上一日终快照 FloatRate;无 preEod 传 null /// 提前终止日 /// 定盘取价委托(测试可注入);入参=取价日,无价返回 null public static FundingLegRate ResolveFrozenRate( swap_position position, decimal spread, decimal? preEodFloatRate, DateTime unwindDate, Func tryGetFixing) { if (string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) return FundingLegRate.Fixed(spread); if (preEodFloatRate.HasValue) return FundingLegRate.Floating(spread, preEodFloatRate.Value); var fixingDate = IndexFixerBase.GetFixingDate(unwindDate.AddDays(-1), position.interest_rule); var fixing = tryGetFixing(fixingDate); if (!fixing.HasValue) throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fixingDate:yyyy年MM月dd日}的价格"); return FundingLegRate.Floating(spread, fixing.Value); } }