# 融资腿计息测试矩阵 > 配套 [ARCHITECTURE.md](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. 空洞清单(热力图 ∩ 未覆盖,按优先级) 1. **F=EOD平仓后收盘 × C=部分平仓 × 本族** —— 2035e1df 无测试落地即合入,该入口×比例格子全裸。 2. **G=携带链投影(全族)** —— 现有断言几乎全是最终金额;`TdInterestPrincipal` 逐日携带链无一处断言 (7528670e 在单利上炸过同款,复利同投影裸奔)。 3. **B=重置日±1天 / 跨重置期多次部分平仓** —— 热力图边缘未扫。 4. **A=到期结算 × 本族** —— db46e48e 修过到期结算(28 断言),但非本族参数。 5. **A=互换(续作) × 本族** —— 7411b9d2/421662a0 炸过续作初始化,本族续作无 oracle。 6. **C=同日两次** —— 只有字符化测试,无独立 oracle(字符化=锁定现状,不证正确)。 7. **E=缺价/取价日边界** —— 66a97e03 只修了取价跳过,缺价分支行为未钉。 ## 7. 补盖执行顺序 1. 先铺**守恒不变量**(免 oracle,全格便宜):部分平仓后"期初=平掉+剩余"逐日守恒;全平后持仓=0; 复利重置日动态本金=前段本金+利息;多次平仓 closePercent 连乘=累计比例。 2. 空洞 1/2 优先:按 §2-G 四投影补 EOD平仓后收盘 × 部分 用例,oracle 用确认书公式 Excel 模板。 3. 空洞 6 补独立 oracle(确认书公式),替换字符化地位(保留字符化作回归钉)。 4. 每格期望值来源分级(已升级,见 §8a):**契约公式独立参考实现** > 生产已对账数字 > 业务签认 Excel > 新旧影子对比;**禁止当前代码输出充当 oracle**。 5. 契约参考实现(§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. 合入规则(硬约束) 1. 计息类 fix:**先失败测试,后修代码**;测试须登记本矩阵坐标。 2. 修一格必须**扫同矩阵行兄弟格子**(同 fix 家族的邻格)。 3. 任何触碰 `GetInterests`/`CalcUnwindInterest`/`SaveAutoEodWithCloseInterestPosition` 的 PR: 跑 `DealInterestsGoldenReplayTest` 全量 + 保证金黄金回放(防共享管线殃及)。 4. 登记 fix 时发现同格已有用例而 bug 仍发生 → 先修断言投影,再修代码。 5. **oracle 用例与裁决材料一律取 §8 生产参数**(7 天重置 / A365 / 真实点差 ±0.25%·−2.10% / 千万级名义本金,如 5000 万)。玩具参数(千元级/重置 3 天/点差 1%)仅限字符化钉子测试—— 其用途是锁行为防漂移,不承担"证明数字正确"职责;用玩具数字做裁决依据会掩盖金额量级 (0.03 vs 0.06 看着"不大",同参数放大到生产即 7.6 万 vs 25 万/笔)。