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);
}
}