49 lines
2.5 KiB
C#
49 lines
2.5 KiB
C#
using YLErp.Derivatives.Interest;
|
||
using YLErp.Modules.SwapModule.Accrual;
|
||
|
||
namespace YLErp.Modules.SwapModule.Penalty;
|
||
|
||
/// <summary>
|
||
/// 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 平仓日值传入。
|
||
/// </summary>
|
||
public static class PenaltyLegRateResolver
|
||
{
|
||
/// <summary>
|
||
/// 解析罚息窗口的冻结 all-in 利率。
|
||
/// </summary>
|
||
/// <param name="position">利息腿(融资腿,非保证金)</param>
|
||
/// <param name="spread">加点利差(调用方按 SwapIntervalList 取 as-of unwindDate 值,同 GetFixedRate 口径)</param>
|
||
/// <param name="preEodFloatRate">上一日终快照 FloatRate;无 preEod 传 null</param>
|
||
/// <param name="unwindDate">提前终止日</param>
|
||
/// <param name="tryGetFixing">定盘取价委托(测试可注入);入参=取价日,无价返回 null</param>
|
||
public static FundingLegRate ResolveFrozenRate(
|
||
swap_position position,
|
||
decimal spread,
|
||
decimal? preEodFloatRate,
|
||
DateTime unwindDate,
|
||
Func<DateTime, decimal?> 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);
|
||
}
|
||
}
|