ContractReferenceCalc 独立实现 §8a 确认书公式(∏/重置期切分/末段收口/ 利率确定日=重置日上一营业日),禁止引用生产计息类防同源;4 例手算锚点 自验证(真实规模 5000万/2.05%/90天=75999.04 与玩具锚点)。 引擎对照首批 3 例全绿:mode9/mode2 × 复利 × "10" × T+0 部分平仓30%, 盘中重放与契约 oracle 容差 0.01 元内逐分吻合——盘中口径=确认书公式 自此有机器强制,后续补格直接复用 oracle 供给(TEST-MATRIX §7.5 已登记)。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
11 KiB
融资腿计息测试矩阵
配套 ARCHITECTURE.md。目的:把"覆盖"从用例计数变成格子坐标运算—— 每个用例/fix 显式登记命中坐标,空洞一眼可见。2026-08 建立,依据近 6 周 fix 热力图回溯登记。
0. 范围声明
- 本矩阵只覆盖融资腿 FundingLeg(mode 1 固定值 / 2 合约名义本金规模 / 9 标的期初全价)。
- mode 5/6(保证金/预付金)不属于本矩阵(历史遗留:被错误建模为计息腿,概念上与融资腿无关,
见
Margin/MarginModes.cs注释)。保证金有独立的余额模型与专属黄金回放(96 库 60 条,0 差异)作为护栏。 禁止向本矩阵添加 5/6 格子。 - 主力生产组合(确认书规定)必须全格覆盖,见 §1。
1. 主力族(第一优先级,必须全盖)
InterestMode = 9 标的期初全价 × FR007 浮动(±点差) × InterestType = 复利 × InterestCalcMode = "10"(算头不算尾)
代码锚点:SwapDealService.GetInterests(calcFirst=true / calcLast=false,SwapDealService.cs:646)。
近 6 周 ≥9 个 fix 落在本族内——生产用得最多 = 人工测试打得最狠,fix 清单就是炸点热力图。
2. 维度定义
| 维度 | 取值 | 代码/数据锚点 |
|---|---|---|
| A 生命周期终点 | 持有至到期结算 / 盘中全平 / 盘中部分后持有 / 部分N次后全平 / EOD自动平仓(部分·全) / 互换(续作) | SwapEventTypeEnum;到期:SwapEodPositionService 到期结算路径 |
| B 重置几何 | 第1重置期内平仓 / 跨≥1完整重置期 / 第3重置期内 / 平仓日=重置日 / 重置日±1天 / 末段非整周期(di<7) | 重置频率=7天(已定格,§8);契约重置期定义见 §8a |
| C 比例与次数 | 单次部分(30%) / 同日两次 / 跨重置期多次 / 全平(剩余=0) | closePrecent;双语义转换 ClosePercentMath |
| D 交收 | T+0 / T+1 | valueDate vs unwindDate |
| E FR007 形态 | 每重置日有价 / 加点(+0.25%) / 减点(-2.10%) / 取价日=重置日上一营业日(契约规定) / 缺价分支 | TryGetFloatRate / ResolveFloatRate;66a97e03 对应此维 |
| F 入口 | 见 §3 | |
| G 断言投影 | ①最终利息金额 ②TdInterestPrincipal 逐日携带链 ③InterestIncomeSum+flow_event 全字段 ④方向/符号(报表口径) |
每格必须断言全部 4 个投影 |
3. 入口枚举(F 维)
| 入口 | 代码路径 |
|---|---|
| 盘中平仓/互换结息试算 | SwapDealService.GetInterestsForUnwind(SwapDealService.cs:617,settment:false → CalcUnwindInterest) |
| EOD 正常收盘 | GetInterests(settment:true) → CalcEodInterest |
| EOD 平仓后收盘 | SwapEodPositionService.SaveAutoEodWithCloseInterestPosition(:1246)→ CalcSwapInterests(:1579) |
| EOD 自动互换 | CalcSwapInterests(:1161,EventType=自动互换) |
已知风险:GetInterests 参数语义随入口漂移(EOD 平仓后收盘传"剩余本金+percent=1",
盘中传"平仓前本金+实际比例"),GetInterestsEntrySemanticsTest 曾实测双入口复利口径分歧(b01b485e)。
4. fix 热力图(本族,近 6 周)
| fix | 落点 | 格子坐标 | 自带测试 |
|---|---|---|---|
66a97e03 重置日=平仓日 calcLast 不跳过 FR007 取价 |
SwapDealService:1249/1295 | B=重置日=平仓日 × E=取价边界 | GLMS20260805FR007UnderlyingIdDiagnoseTest(581行) |
48e84479 重置日部分平仓本金 |
SwapEodPositionService:1422 | B=重置日=平仓日 × C=部分 | SwapCloseConversationCasesRegressionTest(358行) |
d3afa6d2 T+1 部分平仓复利本金(算头不算尾快速路径) |
SwapDealService:1243 | D=T+1 × C=部分 × A=部分后持有 | DealInterestsScenarioTest +36行 |
aa5a5ed8 算头不算尾期初复利部分平仓 |
SwapEodPositionService:1418-1573 | 本族正中心 | DealInterestsScenarioTest |
a0be0eb0 复利平仓已结利息扣除 |
SwapDealService:1294 | 已结利息差分(CalcDailyCompoundInterest 回放) | ConsumedInterestScenarioTest |
5539bd9c 复利部分平仓后 EOD 本金 |
SwapEodPositionService:782/1381 | G=携带链投影 | DealInterestsScenarioTest +34行 |
feffc196 Bug A/B/C 浮动部分/全平尾差 |
SwapDealService:1214/1292 | C=部分/全平 × E=浮动 | SwapInterestScenario3And4FloatingTest(24用例,Excel oracle) |
2035e1df EOD 平仓后收盘结息本金语义 |
SwapDealService:1293 / EodService:860,1360 | F=EOD平仓后收盘 × C | 无测试 |
b01b485e 双入口口径分歧(实测发现) |
— | F=入口 × 全族 | GetInterestsEntrySemanticsTest(字符化,非 oracle) |
规律:fix 全部落在 CalcUnwindInterest(SwapDealService 1240-1300)和
SaveAutoEodWithCloseInterestPosition 族(SwapEodPositionService 1380-1580)两个带。
5. 现有用例登记
| 测试文件 | 覆盖格子 | oracle 类型 |
|---|---|---|
| SwapInterestScenario3And4FloatingTest(24) | 本族 A=全平/部分30%→全平 × B=第3重置期内 × D=T+0/T+1 × E=加减点 × F=EOD平仓后收盘 × G=仅金额投影 | Excel 手算(业务源) |
| SwapInterestScenario1And2Test(32) | A=收盘平仓 × B=第1重置期内 × E=固定/浮动 | Excel 手算 |
| DealInterestsScenarioTest(24 方法,工单逐个追加) | 部分平仓×复利族各点,含"10"×3 行 | 工单期望值 |
| ConsumedInterestScenarioTest | 已结利息差分族 | 工单期望值 |
| SwapUnwindSameDayDoublePartialTest | C=同日两次 | 字符化(非独立 oracle) |
| GetInterestsEntrySemanticsTest | F=双入口一致性 | 字符化 |
| ContractReferenceOracleTest(Accrual/,7) | mode9/mode2 × 复利 × "10" × T+0 × 部分30% × B=跨12整期+末段(90/89天) × E=恒定利率(取价日免疫) | 契约公式参考实现(§7.4 第一级)——引擎盘中重放已逐分对齐 oracle |
| GetInterestsUnitTest_T0/T1(89) | mode 1 固定值 T+0/T+1 族(非本族) | 单点断言 |
| GLMS20260805FR007UnderlyingIdDiagnoseTest | B=重置日=平仓日 × E | 诊断+断言 |
6. 空洞清单(热力图 ∩ 未覆盖,按优先级)
- F=EOD平仓后收盘 × C=部分平仓 × 本族 ——
2035e1df无测试落地即合入,该入口×比例格子全裸。 - G=携带链投影(全族) —— 现有断言几乎全是最终金额;
TdInterestPrincipal逐日携带链无一处断言 (7528670e在单利上炸过同款,复利同投影裸奔)。 - B=重置日±1天 / 跨重置期多次部分平仓 —— 热力图边缘未扫。
- A=到期结算 × 本族 ——
db46e48e修过到期结算(28 断言),但非本族参数。 - A=互换(续作) × 本族 —— 7411b9d2/421662a0 炸过续作初始化,本族续作无 oracle。
- C=同日两次 —— 只有字符化测试,无独立 oracle(字符化=锁定现状,不证正确)。
- E=缺价/取价日边界 ——
66a97e03只修了取价跳过,缺价分支行为未钉。
7. 补盖执行顺序
- 先铺守恒不变量(免 oracle,全格便宜):部分平仓后"期初=平掉+剩余"逐日守恒;全平后持仓=0; 复利重置日动态本金=前段本金+利息;多次平仓 closePercent 连乘=累计比例。
- 空洞 1/2 优先:按 §2-G 四投影补 EOD平仓后收盘 × 部分 用例,oracle 用确认书公式 Excel 模板。
- 空洞 6 补独立 oracle(确认书公式),替换字符化地位(保留字符化作回归钉)。
- 每格期望值来源分级(已升级,见 §8a):契约公式独立参考实现 > 生产已对账数字 > 业务签认 Excel > 新旧影子对比;禁止当前代码输出充当 oracle。
- 契约参考实现(§8a 公式)已落地(
UnitTestProject/Modules/SwapModule/Accrual/ContractReferenceCalc.cs, 独立于生产引擎,禁止引用计息类防同源),引擎对照首批 3 例全绿(mode9/mode2 × "10" × 部分30%,ContractReferenceOracleTest)。后续补格直接复用:期望值 =ClosedInterest(平掉额, ReferenceRateAbsolute(...))。 待办:变利率引擎侧对照(取价日 E 维)、确认书生成器参数同源断言(swap_position)。
8. 生产参数(已确认,2026-08)
- 重置频率 = 7 天(确认书:"重置频率每【周】";完整重置期 di=7 天)
- 年化基数 = 365(确认书:"计息基准 A/365",固定利率公式同除 365)
- 生产只有这一种组合,无 360/其他重置频率。现有测试参数
ResetPeriod=7 / AnnualDays=365即为生产主力参数,格子按此定格。
8a. 契约 oracle(确认书公式原文)
模板:Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/*.docx(看多/看空 × 现券/债券ETF 共 4 份,计息条款一致);
变量替换:Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeConfirmationGenerator.cs
(重置频率=interest_rest_days天、利差=InterestRateDefault×10000bp,与计息引擎同源 swap_position 字段)。
浮动利率复利公式(本族契约正文):
参考利率(绝对) = ∏[i=1..k] ( 1 + (FR007i + 利差) × di / 365 ) − 1
- k = 计息期包含的重置期个数;di = 第 i 个基准利率适用的日历日数,完整重置期 di=7,末段不足 7 按实际日历日(测试必须盖非整周期:如持有 17 天 = 2×7+3)
- 利率确定日 = 每个重置期首日(重置日)的上一个营业日,取该日 FR007;营业日准则=上一营业日(→ E 维度取值锚点,与
66a97e03修复直接对应) - FR007 取中国货币网每日公布值
计息期定义(= 算头不算尾的契约原文):自起始日(含)至到期日(不含)的自然日天数。 ⚠ 债券ETF 模板变体:计息期自期初观察日(含)至期末观察日(不含)——观察日→代码日期字段的映射需单独核实,是一个潜在口径分叉点。
重置期定义:每个重置期自上一重置日(含)至下一重置日(不含);首个重置期始于计息期首日;最后一个重置期的最后一日为计息期最后一日(末段收口)。重置日从计息期首日按重置频率依次推算。
固定利率公式:参考利率(绝对) = 固定利率 × 计息期 / 365。 期初预付金利息:支付日(含)至到期日(含)×利率/计息基准——注意预付金契约上是"含尾"的,与利率腿"不含尾"相反。
oracle 使用方式(升级 §7):最强形式是按契约公式写独立参考实现(约 20 行:重置日推算 + 分段取价 + ∏ 公式 + 末段收口),作为测试 oracle 与生产引擎对照,容差 0.01。它比逐格 Excel 手算更便宜且零同源风险;Excel 模板退化为抽样校验参考实现本身。
9. 合入规则(硬约束)
- 计息类 fix:先失败测试,后修代码;测试须登记本矩阵坐标。
- 修一格必须扫同矩阵行兄弟格子(同 fix 家族的邻格)。
- 任何触碰
GetInterests/CalcUnwindInterest/SaveAutoEodWithCloseInterestPosition的 PR: 跑DealInterestsGoldenReplayTest全量 + 保证金黄金回放(防共享管线殃及)。 - 登记 fix 时发现同格已有用例而 bug 仍发生 → 先修断言投影,再修代码。
- oracle 用例与裁决材料一律取 §8 生产参数(7 天重置 / A365 / 真实点差 ±0.25%·−2.10% / 千万级名义本金,如 5000 万)。玩具参数(千元级/重置 3 天/点差 1%)仅限字符化钉子测试—— 其用途是锁行为防漂移,不承担"证明数字正确"职责;用玩具数字做裁决依据会掩盖金额量级 (0.03 vs 0.06 看着"不大",同参数放大到生产即 7.6 万 vs 25 万/笔)。