refactor(swap): 合并 CalcDailySimpleInterest 重置日/非重置日重复分支

两分支除"重置日重取浮动利率"外本金口径完全一致(都只缩放一次),
原非重置日分支是复制重置日逻辑时多写一行 tdDynomicPrincipal = flowEvent.InterestPrincipal
(已含 closePercent) 导致 closePercent^N 的指数 bug。合并为单分支,仅在
i % interestPeriod == 0 时重取利率,本金处理统一为 InterestPrincipal = 基数×closePercent。

行为保持:SwapModule 全量 196 通过/4 跳过,与重构前一致。
This commit is contained in:
hjhan
2026-07-14 17:23:33 +08:00
parent 7689436364
commit adc22a5b4c
+18 -26
View File
@@ -1014,36 +1014,28 @@ namespace YLErp.Modules.SwapModule
if (!calcLast && accrueDate == endDate) continue; // 到期日不算尾
if (accrueDate > preEodPosition.ValueDate)
{
if (i % interestPeriod == 0)
// 重置日重新获取该段浮动利率;非重置日沿用上一段利率。
// 两分支唯一差异即"是否重取利率",本金口径(只缩放一次)完全一致,
// 合并后消除复制粘贴导致的 closePercent^N 类 bug(原非重置日分支多了一行
// tdDynomicPrincipal = flowEvent.InterestPrincipal 使本金累积乘 closePercent^N)。
if (i % interestPeriod == 0 && !string.IsNullOrEmpty(position.FloatRateUnderlyingCode))
{
// 获取新的浮动利率
if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode))
var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(accrueDate.AddDays(position.interest_rule ?? 0));
if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1))
{
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 (floatRate1 != 0) floatRate = floatRate1;
}
else
{
throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格");
}
flowEvent.InterestPrincipal = tdDynomicPrincipal * closePercent;
TdInterestPrincipal = tdDynomicPrincipal;
}
else
{
// 单利:计息基数(tdDynomicPrincipal)逐日恒定,非重置日与重置日对本金的处理必须一致——
// 显示本金 InterestPrincipal = 基数 × closePercent(线性,只缩放一次)
// 计息基数 TdInterestPrincipal = 基数(不缩放)。
// 修复前此处曾写 tdDynomicPrincipal = flowEvent.InterestPrincipal(已含 closePercent)
// 使下一个非重置日再乘一次 closePercent,累积成 InterestPrincipal = Fix × closePercent^N
// 导致部分平仓"应返还本金"被指数级缩小(50%→Fix×0.5^7、10%→Fix×0.1^7)。
// 与日终 CalcDailySimpleInterestByEod(baseInterestPrincipal 只乘一次)对齐。
flowEvent.InterestPrincipal = tdDynomicPrincipal * closePercent;
TdInterestPrincipal = tdDynomicPrincipal;
}
// 显示本金 = 计息基数 × closePercent(只缩放一次,与日终 ByEod 口径一致);
// 计息基数(tdDynomicPrincipal)逐日恒定、不缩放(单利特征)。
flowEvent.InterestPrincipal = tdDynomicPrincipal * closePercent;
TdInterestPrincipal = tdDynomicPrincipal;
flowEvent.FloatRate = Convert.ToDecimal(floatRate);
var interest1 = flowEvent.InterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate));
var tdinterest1 = TdInterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate));