test(swap): EQD-6968 自洽化契约钉死——事件利率确定性+快照再定盘载体+CI_007/008 新口径
- Determinism_NoTail_EventFloatRateIndependentOfPublishTime:尾日价缺(上午) vs 有(下午)两世界,金额与事件 FloatRate 完全一致(=末段已消费利率0.01425) - CloseOnly_平仓日为重置日_剩余持仓快照再定盘(+非重置日反例):经 DealInterests 真路由断言快照 FloatRate=当日新定盘(RefixCalls 计数)——载体职责显式化验收 - CalcFirst 用例去掉 closeRate 免疫 hack:priorValueDate 根治后首重置日恒取价 - CI_007 更名+断言翻转:平仓日=重置日+不算尾 → 事件利率=末段已消费利率(旧); 原断言(取新定盘)正是被替换的旧口径契约,根因注释留痕 GLMS-JIATT-20260805 - CI_008:本金结转断言保留,利率断言改为末段旧利率 验证:ConsumedInterestScenario 9/9、InterestEodTailSnapshot+Fr007 36/36、 全量 976 例 145 败与基线 diff=0
This commit is contained in:
@@ -60,6 +60,16 @@ namespace YLErp.Modules.SwapModule
|
||||
return CalcResult;
|
||||
}
|
||||
|
||||
/// <summary>持仓延续腿重置日再定盘接缝:计数并返回受控新定盘(不连库)</summary>
|
||||
public decimal RefixResult { get; set; }
|
||||
public int RefixCalls { get; private set; }
|
||||
|
||||
protected override decimal ResolveOngoingResetFixing(swap_position position, DateTime valueDate)
|
||||
{
|
||||
RefixCalls++;
|
||||
return RefixResult;
|
||||
}
|
||||
|
||||
public List<swap_flow_event> ExecuteDealInterests(
|
||||
List<swap_position> interestList, List<eod_swap_position> eodPositions,
|
||||
DateTime settleDate, trade td, List<swap_flow_event> flowEvents,
|
||||
@@ -223,5 +233,87 @@ namespace YLErp.Modules.SwapModule
|
||||
Assert.AreEqual(5.295342465753m, p.SwapPositionValue);
|
||||
Assert.AreEqual(1.0m, p.TdCurrency);
|
||||
}
|
||||
|
||||
#region 持仓延续腿重置日再定盘(EQD-6968 自洽化:快照利率载体)
|
||||
|
||||
private const decimal OldFloat = 0.01425m;
|
||||
private const decimal NewFloat = 0.0143m;
|
||||
/// <summary>4/27+14:7 天周期的重置日平仓</summary>
|
||||
private static readonly DateTime ResetSettle = StartDate.AddDays(14);
|
||||
/// <summary>4/27+10:非重置日平仓(10%7≠0)</summary>
|
||||
private static readonly DateTime NonResetSettle = StartDate.AddDays(10);
|
||||
|
||||
private static swap_position CreateFloatLegPosition() => new()
|
||||
{
|
||||
id = 1001, SwapTradeId = 1, InterestDirection = (int)SwapDirectionEnum.收取,
|
||||
InterestMode = (int)InterestModeEnum.标的期初全价, InterestRateDefault = Rate,
|
||||
InterestPrincipalFix = Principal, PosiStartDate = StartDate,
|
||||
PosiMatuirityDate = new DateTime(2027, 4, 27), IsInitial = true,
|
||||
InterestType = (int)InterestTypeEnum.单利, IsAnnualized = true,
|
||||
interest_rest_days = 7, interest_rule = 0,
|
||||
FloatRateUnderlyingCode = "FR007",
|
||||
InterestSwapInterval = JsonConvert.SerializeObject(new List<IntervalModel>
|
||||
{ new IntervalModel { Date = StartDate, Rate = Rate, Settlement = 1 } })
|
||||
};
|
||||
|
||||
private static eod_swap_position CreatePreEodBefore(DateTime settle, decimal accumulated) => new()
|
||||
{
|
||||
id = 100, PositionId = 1001, ValueDate = settle.AddDays(-1),
|
||||
InterestDirection = (int)SwapDirectionEnum.收取, InterestMode = (int)InterestModeEnum.标的期初全价,
|
||||
InterestIncomeSum = accumulated, InterestProfitSum = accumulated,
|
||||
InterestRateDefault = Rate, TdInterestPrincipal = Principal,
|
||||
InterestType = (int)InterestTypeEnum.单利, IsAnnualized = true, interest_rest_days = 7
|
||||
};
|
||||
|
||||
private static swap_flow_event CalcResultWithFloat(decimal floatRate)
|
||||
{
|
||||
var e = CreateCalcResult();
|
||||
e.FloatRate = floatRate;
|
||||
return e;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 平仓日恰为重置日且剩余持仓>0:快照 FloatRate 必须显式再定盘为当日新定盘——
|
||||
/// 它是后续非重置日(ByEod 沿用 preEod.FloatRate)与当日应计(intersetAcmount)的利率载体。
|
||||
/// 排除日"纯跳过"后事件利率=末段已消费利率(OldFloat),载体职责与本步骤显式分离。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void CloseOnly_平仓日为重置日_剩余持仓快照再定盘()
|
||||
{
|
||||
var service = new TailStubService
|
||||
{
|
||||
CalcResult = new List<swap_flow_event> { CalcResultWithFloat(OldFloat) },
|
||||
RefixResult = NewFloat,
|
||||
};
|
||||
service.ExecuteDealInterests(
|
||||
new List<swap_position> { CreateFloatLegPosition() },
|
||||
new List<eod_swap_position> { CreatePreEodBefore(ResetSettle, Accrued10d) },
|
||||
ResetSettle, CreateTrade(), new List<swap_flow_event> { CreateCloseEvent() },
|
||||
Remaining, ClosedNotional, 100m, Remaining);
|
||||
|
||||
Assert.AreEqual(1, service.RefixCalls, "不算尾+平仓日=重置日+剩余>0:应恰好显式再定盘一次");
|
||||
Assert.AreEqual(NewFloat, service.PersistedPositions.Single().FloatRate,
|
||||
"剩余持仓快照利率=当日新定盘(非事件末段旧利率)");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CloseOnly_平仓日非重置日_不再定盘_快照沿用事件利率()
|
||||
{
|
||||
var service = new TailStubService
|
||||
{
|
||||
CalcResult = new List<swap_flow_event> { CalcResultWithFloat(OldFloat) },
|
||||
RefixResult = NewFloat,
|
||||
};
|
||||
service.ExecuteDealInterests(
|
||||
new List<swap_position> { CreateFloatLegPosition() },
|
||||
new List<eod_swap_position> { CreatePreEodBefore(NonResetSettle, Accrued10d) },
|
||||
NonResetSettle, CreateTrade(), new List<swap_flow_event> { CreateCloseEvent() },
|
||||
Remaining, ClosedNotional, 100m, Remaining);
|
||||
|
||||
Assert.AreEqual(0, service.RefixCalls, "非重置日平仓:无需再定盘");
|
||||
Assert.AreEqual(OldFloat, service.PersistedPositions.Single().FloatRate,
|
||||
"快照沿用事件末段已消费利率(周期未切换)");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user