test(swap): 补快照利率携带契约——单利+不算头+有preEod 盲区定谳
该组合此前零覆盖。定谳结论:带 preEod 时 fetchAfter=preEod.ValueDate +
seed=preEod.FloatRate 是设计分工(≤上一日终的重置日沿用快照携带利率,>的重新
取价),与无日终场景的根本区别是种子有正确来源——开始日EOD因窗口为空走正常
取价,快照 FloatRate=开始日定盘(链条起点),并非旧 bug 复发。
- CarryForward_Simple_NoHead_PreEodAtStartCarriesFirstPeriodRate:
preEod{ValueDate=开始日, FloatRate=开始日定盘} → PricedDates=0(不重复取价)、
事件利率=快照利率、金额=上日待实现+3天×(spread+快照利率) 精确断言
- Eod_NoHead_StartDay_SnapshotRateCarriesFirstFixing:开始日EOD("00",窗口
为空)→快照利率=首重置日定盘,钉死携带链条起点
Run 扩展:Outcome 暴露 Svc(取价审计) + BuildPreEod 支持指定利率。
验证:GLMS20260817Fr007UnwindMorningTest 33/33;全量 978 例 145 败与基线 diff=0
This commit is contained in:
@@ -91,6 +91,7 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
public swap_flow_event Fe;
|
||||
public Exception Ex;
|
||||
public StubSwapDealService Svc;
|
||||
public bool Threw => Ex != null;
|
||||
}
|
||||
|
||||
@@ -156,14 +157,14 @@ namespace YLErp.Modules.SwapModule
|
||||
};
|
||||
}
|
||||
|
||||
private static eod_swap_position BuildPreEod(DateTime valueDate)
|
||||
private static eod_swap_position BuildPreEod(DateTime valueDate, decimal floatRate = 0.01425m)
|
||||
{
|
||||
return new eod_swap_position
|
||||
{
|
||||
id = 5001,
|
||||
PositionId = 1001,
|
||||
ValueDate = valueDate,
|
||||
FloatRate = 0.01425m,
|
||||
FloatRate = floatRate,
|
||||
InterestProfitSum = -100000m,
|
||||
TdInterestPrincipal = Notional,
|
||||
InterestIncomeSum = -150000m
|
||||
@@ -211,7 +212,7 @@ namespace YLErp.Modules.SwapModule
|
||||
(int)SwapEventTypeEnum.平仓, false, Notional,
|
||||
false, settment: settment, newCalcLast: newCalcLast, closeList: null);
|
||||
Assert.AreEqual(1, interests.Count, "应返回恰好 1 条利息事件");
|
||||
return new Outcome { Fe = interests[0] };
|
||||
return new Outcome { Fe = interests[0], Svc = svc };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -473,6 +474,40 @@ namespace YLErp.Modules.SwapModule
|
||||
"事件利率必须与平仓时刻(尾日价发布前后)无关");
|
||||
}
|
||||
|
||||
// ── 快照利率携带契约(carry-forward):带 preEod 时不重复取 ≤ValueDate 的重置日 ──
|
||||
// fetchAfterDate=preEod.ValueDate + seed=preEod.FloatRate 是设计分工:≤上一日终的重置日
|
||||
// 沿用快照携带的"截至 ValueDate 生效利率"(真实 EOD 快照由当日重置日再定盘写入),
|
||||
// >上一日终的重新取价。与无日终场景的根本区别:种子有正确来源,不需要强制重取首重置日。
|
||||
|
||||
[TestMethod]
|
||||
public void CarryForward_Simple_NoHead_PreEodAtStartCarriesFirstPeriodRate()
|
||||
{
|
||||
// preEod.ValueDate=开始日(7/6),FloatRate=7/6定盘0.0142(模拟开始日EOD快照的真实语义)
|
||||
var o = Run(InterestTypeEnum.单利, includeCloseDate: true, calcMode: "00",
|
||||
closeDate: new DateTime(2026, 7, 10), preEod: BuildPreEod(StartDate, 0.0142m));
|
||||
Assert.IsFalse(o.Threw, "不应抛:" + o.Ex?.Message);
|
||||
Assert.AreEqual(0, o.Svc.PricedDates.Count,
|
||||
"≤上一日终(7/6)的重置日不重复取价——首段利率由快照携带(carry-forward 契约)");
|
||||
Assert.AreEqual(0.0142m, o.Fe.FloatRate,
|
||||
"首段(也是末段)利率=快照携带的 7/6 定盘");
|
||||
// 不算头不算尾:计息日 [7/7,7/10) 共 3 天 @ (spread+0.0142);单利重放含上日待实现(-100000)
|
||||
Assert.AreEqual(-100000m + Notional * (Spread + 0.0142m) * 3m / AnnualDays, o.Fe.InterestAmount, 0.0000001m,
|
||||
"金额=上日待实现+3天×(spread+快照利率),首段未误用种子外的任何值");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Eod_NoHead_StartDay_SnapshotRateCarriesFirstFixing()
|
||||
{
|
||||
// 链条起点钉死:开始日当天 EOD("00",窗口为空 interestStart=7/7>interestEnd=7/6)——
|
||||
// 窗口为空时"不算尾不取价"分支不命中,走正常取价,快照 FloatRate=开始日定盘。
|
||||
// 次日重放才能以 fetchAfter=开始日 + 携带利率=开始日定盘 正确续算(见上一用例)。
|
||||
var o = Run(InterestTypeEnum.单利, includeCloseDate: true, calcMode: "00",
|
||||
closeDate: StartDate, settment: true);
|
||||
AssertNoThrow(o, "开始日EOD(00) 不应抛");
|
||||
Assert.AreEqual(0.0142m, o.Fe.FloatRate,
|
||||
"开始日EOD快照利率=当日(首重置日)定盘——窗口为空不触发不取价分支");
|
||||
}
|
||||
|
||||
// ── EOD 收盘归档路径(settment=true,此前全套件仅覆盖盘中 settment:false)──
|
||||
// EOD 不取尾日价的依赖链:InitInterestDate 到期日回拨(endDate=D-1) + CalcEodInterest 的
|
||||
// calcToday=false(valueDate==到期日且不算尾) 整体跳过 ByEod 重算——ByEod 的取价
|
||||
|
||||
Reference in New Issue
Block a user