feat(swap): EQD-6977 复利纯函数支持 carryInInterest——窗口前已结利息随首个重置日资本化并持续留在基数(与全窗口重放轨迹严格一致);默认0零行为变化,含数学不变量测试
This commit is contained in:
@@ -61,6 +61,11 @@ public static class CompoundInterestAccrual
|
||||
/// 复利多日计息(替换 CalcDailyCompoundInterest 的纯数学部分)。
|
||||
/// 从 startDate 到 endDate 全程重放,每个重置日把累计利息并入本金。
|
||||
/// </summary>
|
||||
/// <param name="carryInInterest">
|
||||
/// 窗口前已计未结转利息(EQD-6977 罚息承接):在【首个重置日】并入计息基数——
|
||||
/// 与"持有至到期"全期轨迹严格对齐(恒等式:全期复利 = 平仓日已结利息 + 罚息窗口利息)。
|
||||
/// 默认 0 时与旧行为逐位一致。与 resetCarryInterest 互斥使用(后者是全平重放的末段存量替代)。
|
||||
/// </param>
|
||||
public static InterestResult AccruePeriod(
|
||||
decimal notional,
|
||||
IReadOnlyList<(DateTime StartDate, decimal Rate)> segmentRates,
|
||||
@@ -73,10 +78,14 @@ public static class CompoundInterestAccrual
|
||||
decimal realizedInterest,
|
||||
decimal unwindFraction,
|
||||
out decimal finalBasis,
|
||||
AccrualTrace? trace = null)
|
||||
AccrualTrace? trace = null,
|
||||
decimal carryInInterest = 0m)
|
||||
{
|
||||
decimal accrualBasis = notional;
|
||||
decimal accrued = 0m;
|
||||
// carryInInterest 是"窗口前已计未结转利息":先并入 accrued,随首个重置日的
|
||||
// basis = notional + accrued 一并资本化,并在其后每个重置日持续留在基数里
|
||||
//(与全窗口重放时 accrued 含全部历史利息的轨迹严格一致);最终报告时扣除。
|
||||
decimal accrued = carryInInterest;
|
||||
|
||||
trace?.MarkStart(startDate, endDate, boundary, annualDays, isAnnualized);
|
||||
|
||||
@@ -116,6 +125,9 @@ public static class CompoundInterestAccrual
|
||||
|
||||
finalBasis = accrualBasis;
|
||||
|
||||
// 报告口径只含窗口内增量(carryIn 是窗口前已结利息,由正常平仓流单独结算)
|
||||
accrued -= carryInInterest;
|
||||
|
||||
if (realizedInterest != 0m)
|
||||
trace?.Unwind(endDate, unwindFraction, realizedInterest * unwindFraction, accrued - realizedInterest * unwindFraction);
|
||||
accrued -= realizedInterest * unwindFraction;
|
||||
|
||||
Reference in New Issue
Block a user