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:
hjhan
2026-08-19 11:07:10 +08:00
parent fafae5cac0
commit 6e2cae7c1f
3 changed files with 142 additions and 43 deletions
@@ -439,11 +439,10 @@ namespace YLErp.Modules.SwapModule
[TestMethod]
public void CalcFirst_Simple_NoHeadDropsExactlyStartDayInterest()
{
// closeRate=0.0142 与 7/6 定盘相同:使"00"首段种子利率与"10"首段取价利率一致,
// 断言只对"少计开始日一天"敏感,免疫无日终快照时 fetchAfter=interestStart-1
// 跳过 7/6 取价、首段用种子利率的既有取价细节。
var w10 = Run(InterestTypeEnum., includeCloseDate: true, calcMode: "10", closeRate: 0.0142);
var w00 = Run(InterestTypeEnum., includeCloseDate: true, calcMode: "00", closeRate: 0.0142);
// 无日终快照时 priorValueDate=开始日-1(首重置日 7/6 恒在取价窗内),两世界首段利率同为 7/6 定盘;
// "00" 比"10"恰好少计开始日一天——精确断言钉 CalcFirst 边界与首重置日取价窗。
var w10 = Run(InterestTypeEnum., includeCloseDate: true, calcMode: "10");
var w00 = Run(InterestTypeEnum., includeCloseDate: true, calcMode: "00");
Assert.IsFalse(w10.Threw, "10 不应抛:" + w10.Ex?.Message);
Assert.IsFalse(w00.Threw, "00 不应抛:" + w00.Ex?.Message);
// 开始日 7/6 属首段:all-in = spread(-0.0155) + 定盘(0.0142) = -0.0013
@@ -453,6 +452,27 @@ namespace YLErp.Modules.SwapModule
"不算头(00)应恰好少计开始日一天利息(CalcFirst 回归锚)");
}
// ── 事件利率确定性(EQD-6968 自洽化):排除日不取价,事件利率=末段已消费利率 ──
// 同一交易同一天,尾日价缺(上午平仓) vs 有(下午平仓):金额与落库 FloatRate 必须完全一致,
// 杜绝"记录利率取决于点击时刻"。
[TestMethod]
public void Determinism_NoTail_EventFloatRateIndependentOfPublishTime()
{
var wMorning = Run(InterestTypeEnum., includeCloseDate: false, calcMode: "10",
preEod: BuildPreEod(new DateTime(2026, 7, 13)));
var wAfternoon = Run(InterestTypeEnum., includeCloseDate: true, calcMode: "10", closeRate: 0.0199,
preEod: BuildPreEod(new DateTime(2026, 7, 13)));
Assert.IsFalse(wMorning.Threw, "上午世界不应抛:" + wMorning.Ex?.Message);
Assert.IsFalse(wAfternoon.Threw, "下午世界不应抛:" + wAfternoon.Ex?.Message);
Assert.AreEqual(wMorning.Fe.InterestAmount, wAfternoon.Fe.InterestAmount,
"金额不应因尾日价发布与否而变化(尾日利率零消费)");
Assert.AreEqual(0.01425m, wMorning.Fe.FloatRate,
"事件利率=末段已消费利率(7/13定盘 0.01425),非尾日价");
Assert.AreEqual(wMorning.Fe.FloatRate, wAfternoon.Fe.FloatRate,
"事件利率必须与平仓时刻(尾日价发布前后)无关");
}
// ── EOD 收盘归档路径(settment=true,此前全套件仅覆盖盘中 settment:false)──
// EOD 不取尾日价的依赖链:InitInterestDate 到期日回拨(endDate=D-1) + CalcEodInterest 的
// calcToday=false(valueDate==到期日且不算尾) 整体跳过 ByEod 重算——ByEod 的取价