fix(swap): 修复复利计算中的利息处理逻辑

- 添加了从开始日期到结束日期的天数计算
- 添加了从前一日末到结束日期的天数计算
- 修复了特定条件下利息本金和浮动利率的赋值
- 修正了利息金额和累计利息金额的计算
- 添加了四舍五入处理以确保精度准确性
- 修复了利息平仓损益的计算逻辑
This commit is contained in:
张名锐
2026-08-07 22:13:58 +08:00
parent 569002e551
commit e819ad02c5
2 changed files with 57 additions and 0 deletions
@@ -431,5 +431,47 @@ namespace YLErp.Modules.SwapModule
AssertDecimal(expectedDailyInterest,
result.InterestPrincipal * (result.InterestRate + result.FloatRate.Value) / AnnualDays);
}
[TestMethod]
public void CI_009_NonResetUnwindWithCalcLastFalseUsesPreviousEodPendingInterest()
{
const decimal pendingInterest = 10019.043756537721m;
const decimal remainingPrincipal = 30041492.070122881942m;
var startDate = new DateTime(2026, 7, 28);
var unwindDate = new DateTime(2026, 8, 7);
var td = CreateTrade();
td.StartDate = startDate;
td.TradeDate = startDate;
var position = new swap_position
{
id = 1001, SwapTradeId = td.id,
InterestDirection = (int)SwapDirectionEnum.,
InterestMode = (int)InterestModeEnum.,
InterestType = (int)InterestTypeEnum.,
InterestRateDefault = 0.001234m,
PosiStartDate = startDate, PosiMatuirityDate = ExerciseDate,
IsAnnualized = true, interest_rest_days = 7,
FloatRateUnderlyingCode = "FR007"
};
var preEod = new eod_swap_position
{
id = 1, PositionId = position.id, ValueDate = unwindDate.AddDays(-1),
TdInterestPrincipal = remainingPrincipal,
InterestIncomeSum = pendingInterest,
InterestProfitSum = pendingInterest,
FloatRate = 0.0213m
};
var service = new StubSwapDealService(
new OptUserInfo(0, nameof(ConsumedInterestScenarioTest), OptUserFrom.UnitTest), 0.0213, 0m);
var result = service.GetInterests(td, td.trade_extend, unwindDate, unwindDate,
new List<eod_swap_position> { preEod }, new List<swap_position> { position },
remainingPrincipal, remainingPrincipal, 0m, remainingPrincipal, 1m,
(int)SwapEventTypeEnum., false, false, 0m, remainingPrincipal,
add: false, settment: false, newCalcLast: false).Single();
AssertDecimal(pendingInterest, result.InterestAmount,
"calcLast=false must not accrue unwind-date interest after the previous EOD");
}
}
}