diff --git a/UnitTestProject/Modules/SwapModule/GLMS20260817Fr007UnwindMorningTest.cs b/UnitTestProject/Modules/SwapModule/GLMS20260817Fr007UnwindMorningTest.cs index 4c678b3e..2eb3c689 100644 --- a/UnitTestProject/Modules/SwapModule/GLMS20260817Fr007UnwindMorningTest.cs +++ b/UnitTestProject/Modules/SwapModule/GLMS20260817Fr007UnwindMorningTest.cs @@ -29,6 +29,14 @@ namespace YLErp.Modules.SwapModule [new DateTime(2026, 7, 13)] = 0.01425, [new DateTime(2026, 7, 20)] = 0.0143, }; + /// interest_rule=-1(前一营业日基准)取价日市场:重置日 7/6、7/13、7/20(周一) + /// 经 GetFixingDate 回拨至前一营业日 7/3、7/10、7/17(周五)。 + private static readonly Dictionary Fr007MarketPrevBizDay = new() + { + [new DateTime(2026, 7, 3)] = 0.0142, + [new DateTime(2026, 7, 10)] = 0.01425, + [new DateTime(2026, 7, 17)] = 0.0143, + }; private const double PreviousResetRate = 0.01425; private const decimal Notional = 279486108.21m; @@ -344,5 +352,62 @@ namespace YLErp.Modules.SwapModule preEod: BuildPreEod(new DateTime(2026, 7, 13))), "不算尾(10)+本次平仓指定算尾+当日有价 → 应成功"); } + + // ── 前一营业日基准(interest_rule=-1,EQD-6968 方案一场景2)── + // 取价日=重置日前一营业日,当日(7/20)定盘未发布也用不到 → 放行; + // 但取价日(前一营业日)本身缺价 → 仍是真实依赖,必须拦截。 + + [TestMethod] + public void PrevBizDay_TailCalced_ResetDayTodayMissing_Succeeds() + { + AssertNoThrow(Run(InterestTypeEnum.复利, includeCloseDate: true, calcMode: "11", interestRule: -1, + omitDate: CloseDate, market: Fr007MarketPrevBizDay, preEod: BuildPreEod(new DateTime(2026, 7, 13))), + "算尾(11)+前一营业日基准+当日(7/20)未发布 → 应放行(取价日7/17已发布)"); + } + + [TestMethod] + public void PrevBizDay_TailCalced_Simple_ResetDayTodayMissing_Succeeds() + { + AssertNoThrow(Run(InterestTypeEnum.单利, includeCloseDate: true, calcMode: "11", interestRule: -1, + omitDate: CloseDate, market: Fr007MarketPrevBizDay, preEod: BuildPreEod(new DateTime(2026, 7, 13))), + "单利 算尾(11)+前一营业日基准+当日未发布 → 应放行"); + } + + [TestMethod] + public void PrevBizDay_NoTail_ResetDayTodayMissing_Succeeds() + { + AssertNoThrow(Run(InterestTypeEnum.复利, includeCloseDate: true, interestRule: -1, + omitDate: CloseDate, market: Fr007MarketPrevBizDay, preEod: BuildPreEod(new DateTime(2026, 7, 13))), + "不算尾(10)+前一营业日基准+当日未发布 → 应放行"); + } + + [TestMethod] + public void PrevBizDay_TailCalced_FixingDayMissing_StillThrows() + { + var o = Run(InterestTypeEnum.复利, includeCloseDate: true, calcMode: "11", interestRule: -1, + omitDate: new DateTime(2026, 7, 17), market: Fr007MarketPrevBizDay, + preEod: BuildPreEod(new DateTime(2026, 7, 13))); + Assert.IsTrue(o.Threw, "算尾(11)+前一营业日基准+取价日(7/17)本身缺价 → 仍应拦截(真实依赖)"); + StringAssert.Contains(o.Ex.Message, "FR007"); + } + + // ── 算尾+当前营业日+当日非重置日(EQD-6968 方案一场景3)── + // 当日价未被任何计息段消费(末段重置日7/20是历史日),当日(7/22)缺价 → 放行。 + + [TestMethod] + public void TailCalced_NonResetDay_TodayMissing_Succeeds() + { + AssertNoThrow(Run(InterestTypeEnum.复利, includeCloseDate: true, calcMode: "11", closeDate: NonIntCloseDate, + preEod: BuildPreEod(new DateTime(2026, 7, 13))), + "算尾(11)+当日非重置日+当日(7/22)缺价 → 应放行(非重置日不取当日价)"); + } + + [TestMethod] + public void TailCalced_NonResetDay_Simple_TodayMissing_Succeeds() + { + AssertNoThrow(Run(InterestTypeEnum.单利, includeCloseDate: true, calcMode: "11", closeDate: NonIntCloseDate, + preEod: BuildPreEod(new DateTime(2026, 7, 13))), + "单利 算尾(11)+当日非重置日+当日缺价 → 应放行"); + } } }