fix(swap): 复利重置日=平仓日时 calcLast 不再跳过 FR007 取价
根因(GLMS-JIATT-20260805):InterestCalcMode='10'(算头不算尾,calcLast=false)时, CalcDailyCompoundInterest 循环的 'if(!calcLast && accrueDate==endDate) continue' 会跳过平仓日。若平仓日恰好是重置日(i%period==0),取价代码块被一并跳过, 导致 flowEvent.FloatRate 落库为旧周期利率,传染后续 EOD 复利计算。 修复:把重置日的 FR007 取价提前到 calcFirst/calcLast 跳过判断之前—— calcLast 只应跳过'计息',不应跳过'重置日利率取价'。同时循环外用最终 floatRate 兜底赋值 flowEvent.FloatRate,确保落库值反映最后重置日的利率。 验证: - CI_007 合成测试(平仓日=重置日):修复前 FloatRate=旧值(FAIL),修复后=新值(PASS) - 连库验证(GLMS-JIATT-20260805 8/4平仓):FloatRate 0.0123→0.0213(8/3新值) - 利息金额不变(calcLast 不计当天利息,Amount 不受影响,只修正 FloatRate 字段) - 全套 swap 测试无新增回归(334通过,2失败均为pre-existing单利/EOD路径) 附:CI_007 复现测试 + GLMS20260805 FR007/EOD 诊断工具 + 文档 longRatio 状态更新
This commit is contained in:
@@ -1249,28 +1249,31 @@ namespace YLErp.Modules.SwapModule
|
||||
for (int i = 0; i <= calcDays; i++)
|
||||
{
|
||||
var accrueDate = startDate.AddDays(i);
|
||||
// 重置日取价必须在 calcFirst/calcLast 跳过之前完成:calcLast=false(不算尾) 只应跳过计息,
|
||||
// 不应跳过重置日的 FR007 取价。否则平仓日=重置日时会沿用旧周期利率,
|
||||
// 且 flowEvent.FloatRate 落库为旧值,传染后续 EOD(GLMS-JIATT-20260805 根因)。
|
||||
if (accrueDate >= startDate && i % interestPeriod == 0
|
||||
&& !string.IsNullOrEmpty(position.FloatRateUnderlyingCode))
|
||||
{
|
||||
var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(accrueDate.AddDays(position.interest_rule ?? 0));
|
||||
if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1))
|
||||
{
|
||||
if (floatRate1 != 0) floatRate = floatRate1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格");
|
||||
}
|
||||
}
|
||||
if (!calcFirst && accrueDate == startDate) continue; // 首日不算头
|
||||
if (!calcLast && accrueDate == endDate) continue; // 到期日不算尾
|
||||
if (!calcLast && accrueDate == endDate) continue; // 到期日不算尾(只跳过计息,取价已在上方完成)
|
||||
if (accrueDate >= startDate)
|
||||
{
|
||||
if (i % interestPeriod == 0)
|
||||
{
|
||||
// 复利时:利息并入本金
|
||||
// 复利时:利息并入本金(FR007 取价已提前到 calcFirst/calcLast 跳过之前完成)
|
||||
dynomicPrincipal = principal + interest;
|
||||
tdDynomicPrincipal = principal + interest;
|
||||
// 获取新的浮动利率
|
||||
if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode))
|
||||
{
|
||||
var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(accrueDate.AddDays(position.interest_rule ?? 0));
|
||||
if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1))
|
||||
{
|
||||
if (floatRate1 != 0) floatRate = floatRate1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格");
|
||||
}
|
||||
}
|
||||
flowEvent.InterestPrincipal = tdDynomicPrincipal;
|
||||
TdInterestPrincipal = tdDynomicPrincipal;
|
||||
}
|
||||
@@ -1292,6 +1295,9 @@ namespace YLErp.Modules.SwapModule
|
||||
tdinterest += tdinterest1;
|
||||
}
|
||||
}
|
||||
// 兜底:若循环因 calcLast 跳过最后一天(重置日=平仓日),flowEvent.FloatRate 不会被循环内赋值,
|
||||
// 用最终 floatRate 兜底,确保落库的 FloatRate 反映最后一个重置日的利率(GLMS-JIATT-20260805)。
|
||||
flowEvent.FloatRate = Convert.ToDecimal(floatRate);
|
||||
// 复利从头重放得到的是"假设从未结出"的整段总利息,需扣除历史已通过互换结出的利息,
|
||||
// 否则已结部分会重复计息(类比分红 PosiDividendSum = totalToDate − RealizedDividend)。
|
||||
// consumedInterest is full-position absolute interest; scale it to this close portion.
|
||||
|
||||
Reference in New Issue
Block a user