fix(swap): 修复复利计算和部分平仓处理中的多个问题(算头算尾合约复利平仓)
- 修复合约名义本金规模模式下部分平仓时名义本金计算错误 - 修复最终全平时复利利息计算中历史平仓尾差处理问题 - 修复复利重置日处理中利息重复注入历史本金的错误 - 修复部分平仓后日终待实现利息计算中本金比例应用问题 - 修复全平且实际金额覆盖应结利息后待实现利息清零逻辑 - 新增复合复利交换服务用于单元测试验证 - 添加多个测试用例覆盖复利计算边界场景
This commit is contained in:
@@ -830,6 +830,12 @@ namespace YLErp.Modules.SwapModule
|
||||
|
||||
// 计算名义本金
|
||||
var (closePrincipal, posiPrincipal, newClosePercent) = CalcNotionalByMode(position, closePrecent, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue);
|
||||
if ((InterestModeEnum)position.InterestMode == InterestModeEnum.合约名义本金规模
|
||||
|| (InterestModeEnum)position.InterestMode == InterestModeEnum.标的期初全价
|
||||
&& posiNotionalValue == 0m)
|
||||
{
|
||||
closePrincipal = closePosiNotionalValue;
|
||||
}
|
||||
if ((InterestModeEnum)position.InterestMode == InterestModeEnum.追加预付金 || (InterestModeEnum)position.InterestMode == InterestModeEnum.初始预付金)
|
||||
{
|
||||
positionClone.InterestDirection = position.InterestDirection == (int)SwapDirectionEnum.收取 ? (int)SwapDirectionEnum.支付 : (int)SwapDirectionEnum.收取;
|
||||
@@ -910,6 +916,9 @@ namespace YLErp.Modules.SwapModule
|
||||
closePrincipal = posiShort * closePercent;
|
||||
posiPrincipal = posiShort;
|
||||
break;
|
||||
case InterestModeEnum.合约名义本金规模:
|
||||
closePrincipal = posiNotional * closePercent;
|
||||
break;
|
||||
case InterestModeEnum.标的期初全价:
|
||||
closePrincipal = posiNotional * closePercent;
|
||||
break;
|
||||
@@ -1228,6 +1237,24 @@ namespace YLErp.Modules.SwapModule
|
||||
CalcDailyCompoundInterest(endDate, position, closePosiNotionalValue, interest, annualDays, needPrice,
|
||||
floateRate, closePrecent, orginPv, calcFirst, calcLast, ref InterestAmount, ref TdInterestAmount,
|
||||
consumedInterest, resetCarryInterest);
|
||||
if (preEodPosition.id != 0 && closePrecent == 1m)
|
||||
{
|
||||
// 最终全平只重放上一日终之后的新增利息;历史部分平仓的两位结算尾差已在日终待实现中。
|
||||
var interestAtEnd = new swap_flow_event { InterestRate = rate };
|
||||
decimal amountAtEnd = 0m;
|
||||
decimal tdAmountAtEnd = 0m;
|
||||
CalcDailyCompoundInterest(endDate, position, closePosiNotionalValue,
|
||||
interestAtEnd, annualDays, needPrice, floateRate, closePrecent, orginPv,
|
||||
calcFirst, calcLast, ref amountAtEnd, ref tdAmountAtEnd, consumedInterest);
|
||||
var interestAtPreviousEod = new swap_flow_event { InterestRate = rate };
|
||||
decimal amountAtPreviousEod = 0m;
|
||||
decimal tdAmountAtPreviousEod = 0m;
|
||||
CalcDailyCompoundInterest(preEodPosition.ValueDate, position, closePosiNotionalValue,
|
||||
interestAtPreviousEod, annualDays, needPrice, floateRate, closePrecent, orginPv,
|
||||
calcFirst, calcLast, ref amountAtPreviousEod, ref tdAmountAtPreviousEod, consumedInterest);
|
||||
InterestAmount = preEodPosition.InterestIncomeSum + amountAtEnd - amountAtPreviousEod;
|
||||
TdInterestAmount = preEodPosition.InterestIncomeSum + tdAmountAtEnd - tdAmountAtPreviousEod;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1291,8 +1318,13 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
if (i % interestPeriod == 0)
|
||||
{
|
||||
// 复利时:利息并入本金(FR007 取价已提前到 calcFirst/calcLast 跳过之前完成)
|
||||
var interestToReset = i == 0 || resetCarryInterest == 0m ? interest : resetCarryInterest;
|
||||
// resetCarryInterest 是上一日终待实现按本次平仓比例分摊后的存量,
|
||||
// 只能在 endDate 恰好是当前复利重置日时并入本金。历史重置点必须使用
|
||||
// 重放到当时的 interest,否则会把上一日终存量反复注入历史本金,
|
||||
// 例如 0007 的 5/11 部分平仓会由 84,090.95 被多算为 84,114.88。
|
||||
var interestToReset = i > 0 && accrueDate == endDate && resetCarryInterest != 0m
|
||||
? resetCarryInterest
|
||||
: interest;
|
||||
dynomicPrincipal = principal + interestToReset;
|
||||
tdDynomicPrincipal = principal + interestToReset;
|
||||
flowEvent.InterestPrincipal = tdDynomicPrincipal;
|
||||
|
||||
Reference in New Issue
Block a user