fix(swap): 修复复利重置日部分平仓后本金计算逻辑

- 修复复利重置日部分平仓后当日利息计算,使用已结转待实现利息的剩余复利本金
- 修复算尾部分平仓后EOD保留剩余复利本金的逻辑,按计息模式返回口径处理
- 修复模式2和模式9在部分平仓时的本金计算差异,避免重复比例调整
- 修复不算尾情况下重置日后已并入本金的待实现利息遗漏问题
- 新增对话案例回归测试验证部分平仓后最终全平场景的正确性
- 添加多种计息模式和交易类型的回归测试用例
This commit is contained in:
张名锐
2026-08-09 16:06:09 +08:00
parent 421662a07c
commit 48e8447925
3 changed files with 407 additions and 6 deletions
@@ -837,6 +837,8 @@ namespace YLErp.Modules.SwapModule
AssertDecimal(compoundPrincipalAfterSevenDays, result.TdInterestPrincipal,
"复利重置日部分平仓后,EOD 本金必须保留 CalcSwapInterests 计算的 7 天复利本金");
AssertDecimal(compoundPrincipalAfterSevenDays * FixedRate / AnnualDays, result.TdInterestIncome,
"复利重置日部分平仓后,当日利息必须使用已结转待实现利息的剩余复利本金");
}
[TestMethod]
@@ -901,6 +903,42 @@ namespace YLErp.Modules.SwapModule
"算尾部分平仓:InterestIncomeSum 应=前日待实现+当日新计(含被平仓部分)-当日实现");
}
[DataTestMethod]
[DataRow((int)InterestModeEnum.合约名义本金规模, "300")]
[DataRow((int)InterestModeEnum.标的期初全价, "700")]
public void DI_GLMS_20260421_0004_CalcLastKeepsRemainingCompoundPrincipal(
int interestMode, string calculatedPrincipalText)
{
var service = new StubEodPositionService
{
AutoInterests = new List<swap_flow_event>
{
new() { InterestPrincipal = decimal.Parse(calculatedPrincipalText) }
}
};
var td = CreateTrade();
td.trade_extend.ExtendJson = JsonConvert.SerializeObject(new TradeExtendJson
{
AnnualDays = AnnualDays,
InterestCalcMode = "11",
SettlementRules = 1
});
var position = CreateInterestPosition();
position.InterestMode = interestMode;
position.InterestType = (int)InterestTypeEnum.;
var previousEod = CreatePreEod(StartDate.AddDays(2), 100m);
previousEod.TdInterestPrincipal = Principal;
var closeFlow = CreateSwapFlowEvent(StartDate.AddDays(3), 50m);
closeFlow.EventType = (int)SwapFlowEventTypeEnum.;
var result = service.ExecuteSaveAutoEodWithCloseInterestPosition(
previousEod, position, td, StartDate.AddDays(3), null,
700m, 0m, new List<swap_flow_event> { closeFlow }, 300m, false);
AssertDecimal(700m, result.TdInterestPrincipal,
"算尾部分平仓后,EOD 必须按计息模式的返回口径保留剩余70%复利本金");
}
[TestMethod]
public void DI_MANUAL_PARTIAL_CLOSE_NoCalcLastUsesRemainingPrincipalDailyInterest()
{