hjhan and Claude Opus 4.7
07764e7e3f
test(swap): 契约参考实现落地,引擎主力族盘中重放首次对齐确认书公式 oracle
...
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 >
2026-08-16 12:19:28 +08:00
hjhan and Claude Opus 4.7
f596bd80bc
docs(adjudication): 影响面最终关闭——EOD重算结果被丢弃,零生产后果
...
DealInterests hasClose 分支未接收 SaveAutoEodWithCloseInterestPosition 返回值,
UpdateDbOption 仅打审计字段不落库,快照滚动盘中实结金额——错误的251,355
只存在于内存与日志。内网查证与数据修正清单取消,修复定性为重构卫生项。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-08-16 11:53:15 +08:00
hjhan and Claude Opus 4.7
a5684022fa
docs(adjudication): 裁定资金面无影响——EOD重算不动钱,修复性质降为排雷
...
代码级核查:当日平仓后的EOD重算路径(autoSwap=false)无AddClientCash调用,
快照当日结出与累计已结均滚动盘中实落库金额,剩余待实现亦正确;
错误金额仅存在于重算写入的利息流水记录。撤回"双重结算敞口"表述,
内网查询目的改为确认流水记录无消费方+生成数据修正清单。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-08-16 11:48:52 +08:00
hjhan and Claude Opus 4.7
f75792b45b
docs(adjudication): 裁决材料升级为确认书生产参数规模并钉清触发链
...
- 分歧表新增真实规模复算(5000万/2.05%/7天重置/90天):应结75,999 vs 现结251,355,
单笔多结175,356(3.3倍);玩具参数降级为可复现实测锚点
- 新增触发链一节:EOD平仓后收盘=收盘归档对当日平仓事件的重算(非自动平仓本身),
人工/自动平仓当下结息均正确,分歧仅在当晚归档重算
- TEST-MATRIX §9 增补规则5:oracle与裁决材料一律用生产参数,玩具参数仅限字符化钉子
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-08-16 11:26:42 +08:00
hjhan and Claude Opus 4.7
5a92709c42
docs(swap): 双入口口径分歧裁决申请——复利mode2部分平仓(EOD多结63%)
...
- 契约验算:盘中口径0.036165=确认书∏复利公式手算值(3.7e-7舍入差)
- 机制定位:SwapDealService:1220 closePrecent==1 分支是全平专属设计,
但EOD入口传参惯例percent恒1→EOD部分平仓30%掉进全平分支,
剩余100%持仓待实现利息被一次结走
- 待业务裁决两项:部分平仓应结口径(推荐=契约公式/盘中口径)、全平维持现公式
- 裁决后修复方案已就绪:EOD传真实比例+1220分支回归全平专属+2035e1df粘合退役
- 附生产影响面查证建议(EOD自动部分平仓×复利mode2/9存量事件比对)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-08-16 11:18:15 +08:00
hjhan
c94a3e8c97
test(swap): 铺 §7-1 守恒不变量护栏,守 EOD平仓后收盘×部分平仓 裸格(§6 空洞1)
...
新增 4 个免库纯内存测试(GetInterestsEntrySemanticsTest):①部分平仓 剩余持仓前递且 期初=剩余+平掉;②全平 剩余前递=0;③两次部分平仓 逐日守恒 期初-剩余前递=平掉;④ClosePercentMath 多次平仓累计比例=1-∏(1-各次剩余口径)纯数学。
守恒断言落在 preEod.PosiNotionalValue(剩余前递)而非 InterestPrincipal——后者在 InitSwapDealInterest:1164 后被利息算法重赋值(1197 复利特判/1266 单利路径),语义随入口/模式变,非稳健观测点;剩余前递由 CalcUnwindInterest:1084 在 preEod.id==0 时写入,与利息算法无关,最稳健。
用途:作为 GetInterests 早路由(Tier A)合入的前置护栏——funding-leg(mode2)不触发早路由 continue,故本类任何回归都直接暴露早路由对 EOD平仓后收盘路径的破坏。验证:YLErp_UNIT_TEST_SKIP_INITIALIZATION=1 dotnet test --filter Name~守恒 全过;整类仅 2 个旧复利测试因无 96 库失败,与本次无关。
2026-08-16 11:17:37 +08:00
hjhan and Claude Opus 4.7
73264a30e2
docs(swap): 新增融资腿计息测试矩阵 TEST-MATRIX.md
...
- 主力族(mode9×FR007×复利×算头不算尾)7 维矩阵 + 4 入口枚举 + 近 6 周 fix 热力图定位
(全部落在 CalcUnwindInterest 与 SaveAutoEodWithCloseInterestPosition 两个带)
- 确认书契约公式提取为 oracle:∏[1+(FR007i+利差)×di/365]−1、重置期含首不含尾、
利率确定日=重置日上一营业日、末段 di 按实际日历日收口(来源 GuoLian 插件 4 份模板)
- 生产参数定格:重置频率 7 天/年化 365,唯一组合
- 保证金 5/6 声明不在矩阵内(独立余额模型+专属黄金回放护栏)
- 4 条合入硬规则:失败测试先行/扫兄弟格/黄金回放门禁/断言投影优先
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-08-16 11:03:21 +08:00
hjhan and Claude Opus 4.7
db447aa584
refactor(swap): 保证金腿在 GetInterests 循环入口提前路由,融资腿分支树去除 MarginModes 依赖
...
- 保证金腿(5/6)在最外层路由并 continue:本金(InterestPrincipalFix×closePrecent)、
方向翻转、CalcMarginInterest 收口一处;newClosePercent 在保证金腿恒等于
closePrecent,直接传参
- 融资腿(1/2/9)分支树内 3 处 MarginModes.Contains 归零,后续融资腿改动与保证金解耦
- GetFixedRate 前移为两路共用(纯读函数,已验证无副作用)
- 有意跳过 GetFloatRate:CalcMarginInterest 纯固定利率(FundingLegRate.Fixed/
FloatRate 恒 0),浮动取价对保证金无意义;脏数据 FloatRateUnderlyingCode
缺价时不再阻断保证金结算(唯一行为变化,方向更安全)
- 验证:SwapModule 537 用例 A/B(带改/不带改)摘要完全一致(71F/459P/7S),
失败项均为本机无库环境失败;内网全量单测待跑
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-08-16 11:03:11 +08:00
hjhan
44e24b3172
refactor(margin): MarginModes 反转依赖 ConsTrade.InterestMarginModels 并删除 premiumModes 硬编码副本
...
- MarginModes.All/ForLinq/FixedAmountAndMargin 改为由框架常量 ConsTrade.InterestMarginModels 派生,消除 DAL 层独立重写集合(单一真源在 Core 层,本类退化为形态包装,避免新增保证金形态时口径分裂)
- SwapEodPositionService.premiumModes 局部 new List 字面量替换为 MarginModes.ForLinq(DAL 内部冗余副本消除)
- 重写 MarginModes.cs 过时的“复制 6 次/待收敛”注释,改为记录依赖方向与收敛历史;ForLinq 注释改为“派生自框架常量,仅做形态适配”
- 更新 MarginModesTest 类注释与一致性测试注释以反映派生关系
- 验证:YLErpDAL/UnitTestProject 编译 0 错误;MarginModesTest 5/5 通过
2026-08-16 10:47:45 +08:00
hjhan
04b5206134
test(infra): 缩短测试库连接超时 30s→2s 并加入 MSTest 并行 .runsettings
...
UnitTestProject/appsettings.json: 四个连接串 Connection Timeout=30→2,无库环境连不上 2 秒即失败,避免逐个 DB 测试 30s 空转;有库时 LAN 连接<1s 不受影响。新增 .runsettings: Workers=0(自动取 CPU 核数)+Scope=TestClass 类级并行,opt-in(仅 --settings 生效);共享静态单例(LogFactory/DataCacheManager/YLServiceLocator)启用前先跑串行基线确认无交叉污染。
2026-08-16 10:30:39 +08:00
hjhan
1c19d2f7c5
fix(EQD-7049): 新建空白期权定价页跳过空标的默认查询,避免'标的信息缺失'弹窗
...
- 页面初始化时 updateUnderlying 以空 UnderlyingCode/InstrumentType/VarietyId 发起 /pricing/AjaxGetUnderlying,后端三者皆空返回 JsonError('标的信息缺失') 并自动弹窗
- 前端守卫:三者皆空时仅重置空 underlying 并 return,不再发请求,与后端 AjaxGetUnderlying(PricingController.cs:398-414) 判定精确对应
- 不影响正常路径:选类型(InstrumentType)/品种(VarietyId>0)/具体标的(UnderlyingCode) 仍照常查询
- 同步修改东莞定制版 structure_dz.js
2026-08-14 17:49:59 +08:00
hjhan
ebc6070543
docs(swap): 删除 GetInterests 过期 XML 文档注释 posiLong/ShortNotionalValue
...
- 这两个形参已在 posiLong/posiShort 合并重构中移除,残留 <param> 注释具误导性
- 纯文档改动,零逻辑风险
2026-08-14 17:47:51 +08:00
hjhan
ef37c8e71d
refactor(swap): 合并多空名义本金参数为单一 posiTotalNotional 并加固测试
...
- DealInterests 的 posiLongNotionalValue + posiShortNotionalValue 合并为 posiTotalNotional(调用点以 posiLongNotional+posiShortNotional 求和传入),净减一个参数
- SwapDealService / SwapEodPositionService / InterestCalcRequest 同步收敛多空死管道参数
- 19 个测试调用点适配新签名
- SwapEodPositionServiceIntegrationTest 参数计数断言由裸数字改为参数名集合断言(CollectionAssert.AreEquivalent,对增删/重排/改名敏感)
2026-08-14 17:30:46 +08:00
hjhan
fdf6357c4f
fix(EQD-7049): 期权定价页标的下拉改为服务端搜索,移除全量标的下载
...
- vueUnderlying.lookup 不再遍历全量 ylotc.underlyings(债券十几万量级导致 29s 下载/页面卡死),改为调用 /frontdata/AjaxGetUnderlyingSelect 按关键词服务端搜索
- 默认预拉 20 条(后端 MaxShowLength 硬截断),输入时异步搜索并刷新缓存(乱序响应由 token 丢弃)
- 移除 BasicDataJs 的 标的Live 参数消除全量标的下载;IsCombined 由 IsSynthetic||IsBasket 映射,保留期权黑名单护栏(BlackLimit=1)
- 同步修改东莞定制版 Structure_DZ
2026-08-14 17:06:08 +08:00
hjhan
4a3fee9292
refactor(swap)+test: 删 GetInterests/CalcSwapInterests 死参数 needPrice/grossPrice;补工厂→接缝映射钉子
...
死参数收口(另一半):
- SwapDealService.GetInterests 删 needPrice/grossPrice(体内零消费,2026-08 验证);
InitSwapDealInterest.needPrice 同为死参数一并删
- SwapEodPositionService.CalcSwapInterests 签名+转发同步;两个 EOD 生产调用点
(SaveAutoEodInterestPosition/SaveEodInterestPositionCopy) 重排实参;
CalcEodPostCloseSettleInterests/GetIntradayUnwindInterests 委托同步
- 14 个测试文件 ~44 处直调点机械更新(8 处 override 签名 + 36 处调用实参)
- 注意:EOD 编排链(DealInterests→Save*家族)的 grossPrice(期初不含费价)有真实用途,保留未动
新增钉子:CalcEodPostCloseSettleInterests 工厂→接缝参数映射测试——
CalcSwapInterestsCapture 捕获 stub 断言 EodPostCloseSettle 的完整转发契约
(posi=平仓后剩余/closePosi=平掉额/恒1/settment:false/orginPv 等 11 项)。
该段位置转发含三个相邻同型 decimal,编译器不查错位,此测试兜底。
验证:定向 241 测试通过(含 T0/T1 Excel 验证期望值、EntrySemantics 精确值钉子——
任何 decimal 错位即红);全量 903=145失败/746通过/12跳过,与基线逐位一致。
2026-08-14 16:57:56 +08:00
hjhan
018d7e777f
refactor(swap): InterestCalcRequest 参数对象——GetInterests 双显式入口收敛为单参数
...
新增 InterestCalcRequest(SwapModule 根):
- 承载 GetInterests 全部有效入参(needPrice/grossPrice 死参数不承载),私有构造;
- 仅两个场景工厂可构造:IntradayUnwind(平仓前剩余/实际平掉额/B语义比例)、
EodPostCloseSettle(平仓后剩余/实际平掉额/恒1全额结息)——工厂形参名即场景语义,
物理上防止两套名义本金语义混传(6fdc7d80 错账的温床);
- GetIntradayUnwindInterests / CalcEodPostCloseSettleInterests 签名收敛为单参数 req,
生产调用点(GetUnwindInterests / SaveAutoEodWithCloseInterestPosition)改工厂构造;
- 原 20 参 GetInterests / 19 参 CalcSwapInterests 保留为底层实现与测试兼容层(十余处测试直调,不动)。
验证:定向 140 测试通过;全量 902(+3 字符化测试)= 145失败/745通过/12跳过,
与基线逐位一致,零回归。
2026-08-14 15:57:52 +08:00
hjhan
b01b485ee4
test(swap): GetInterests 双入口语义字符化测试——并实测发现复利口径分歧
...
钉住三组现状(Step3 特判降级的前置回归网):
- 复利×mode2×部分平仓30%:盘中=0.036164835616(closePosi=平掉额300 全程重放);
EOD=0.059041913305(preEod待实现0.05 + 平掉额末段增量0.009042,closePercent==1 分支)
⚠️ 两值不等=同一经济事件两种结息额的口径分歧,已留档待业务裁决(勿当既定正确)
- 单利×mode2:双入口数值留档(Console),断言非零
- 复利×mode9 全平(posi=0):兜底覆盖生效,结息额非零(兜底钉子)
基建复用 GetInterestsUnitTest_T0 口径(T+0、4/27起息、11算头算尾、FR007内存取价stub)。
2026-08-14 15:52:52 +08:00
hjhan
01447ffe04
refactor(swap): GetInterests 传参语义显式化——盘中/EOD平仓后收盘拆双显式入口
...
问题:GetInterests 同名参数在两类调用方下语义相反,约定只存在于注释(2035e1df 固化):
盘中(:489链) EOD平仓后收盘(:1311链)
posiNotionalValue 平仓前剩余本金 vs 平仓后剩余本金
closePercent 实际平仓比例(B) vs 恒1(全额结息)
均走 settment:false 盘中重放算法。6fdc7d80 修的错账即两语义混用产物,
mode2 无条件覆盖/mode9 全平兜底是粘合补丁。
改动(纯机械,零行为变化):
- SwapDealService 新增 GetIntradayUnwindInterests(preCloseNotional/closedNotional/
closePercentRemaining 具名),GetUnwindInterests 切换调用;needPrice/grossPrice 为
GetInterests 死参数(体内零消费),新入口不再暴露
- SwapEodPositionService 新增虚接缝 CalcEodPostCloseSettleInterests
(remainingNotionalAfterClose/closedNotional/恒1),默认实现经 CalcSwapInterests
转发——既有测试替身对该接缝的拦截不变;SaveAutoEodWithCloseInterestPosition 切换调用
- 原 GetInterests/CalcSwapInterests 签名与行为不动(测试直调兼容);EOD 增量路径
(:1148/:1563, settment:true, closePosi=posi 同值) 语义自洽,本次不动
验证:全量 899 测试 145失败/742通过/12跳过——与 e2431e9d 基线逐位一致,零回归。
2026-08-14 15:39:44 +08:00
hjhan
e2431e9d44
refactor(accrual): 计息类型整体迁入 DAL——新增 Accrual/InterestMath,删 Core 未接线孤儿
...
搬迁(算法体逐字未动,仅换命名空间与归属):
- SwapInterest.Round/AccrualDays/FundingLegPrecision + AccrualBoundary/InterestResult
→ YLErpDAL/Modules/SwapModule/Accrual/InterestMath.cs
- AccrualTrace → Accrual/AccrualTrace.cs(被迫同迁:其 MarkStart 引用 AccrualBoundary,
Core 不能反向依赖 DAL)
- 引用切换:Simple/CompoundInterestAccrual、AccrualPolicy、SwapCalcTrace、SwapDealService
(保留 using YLErp.Derivatives.Interest——IIndexFixer/IndexFixerBase 留 Core)
删除(零生产引用,孤儿清零):
- Core:SwapInterest.cs 算法方法(AccrueSimple/AccrueCompoundInArrears/ApplyUnwind/
AccrueUnrealized/ToInterestRate,未接线且与 DAL 生产实现舍入/rollover 口径已分叉)、
AccrualContext.cs、InterestRate.cs
- DAL:AccrualState.cs(零引用死类)
- 测试:SwapInterest_CompoundInArrears_RolloverTimingTests.cs(仅测已删原语)
验证:两解决方案 Rebuild 0 错误;磁盘 SwapInterest. 残留 0;影子/分红/场景 86/86 通过
(含 Accrual 3 影子对账、Margin 影子、divPower 新增 AutoUnwindMultiPartial)。
注:AccrualContext 默认精度 11 与生产 12 的分叉隐患随删除一并消除;
已删原语若将来重建须先补对账测试,勿凭记忆复原(ARCHITECTURE.md 已留警告)。
2026-08-14 15:31:04 +08:00
hjhan
c0ac749e5b
refactor(swap): 删除未接线的衡泰平仓消费死链 AutoSwapUnwindFromConsumer
...
- 移除 SwapDealService.AutoSwapUnwindFromConsumer 及其私有辅助
GetUnwindInterestsByHT(全仓零调用方,随山证 v2.3.0 拷贝引入后从未接线)
- git rm 删除仅被该死链引用的 HengTaiModel/SwapUnwindReq.cs(全仓零引用)
- 修正 UnderlyingEntryFullPriceLeg.cs 中指向已删方法的文档注释
- 保留真实平仓路径 DealUnwind / CalcCloseAmount 等共享活代码
2026-08-14 15:14:09 +08:00
hjhan
58bd27c596
test(EQD-7004): 补自动平仓路径多次部分平仓不重复计入的实证测试——驱动真实 BondPaymentService.CalcPayment(reg_date 口径×当次平仓量 unwindQty),验证总额按登记日持仓分摊、不自洽多算
2026-08-14 14:24:23 +08:00
hjhan
896a5c3dcc
test(EQD-7004): DividendEodNoDoubleCountTest 的 EodSvcStub.CalcBondPayment 由线性假公式改为桥接真实 BondPaymentService(reg_date 口径),使登记日全平/盘中互换端到端测试真正跑生产票息计算
2026-08-14 13:37:52 +08:00
hjhan
6a25e4a2d8
test(EQD-7004): 补 reg_date 口径端到端测试——EOD引擎按债权登记日计提,登记日T+1全平/部分平仓经GetPreEodDividendSum正确读取
2026-08-14 13:13:17 +08:00
hjhan
fffdea4526
fix(EQD-7004): 分红关键链路日志 Debug 提升为 Info(生产可见,k8s console 可输出)
...
bdba5fbe 中加的分红日志原为 Debug 级;但生产 NLog minlevel=Info,k8s console 打不出来。
- 按决策改为 Info 级(5 处): BondPaymentService.GetBondPayments(reg_date 过滤区间+命中条数)、SwapDealService.GetPreEodPositionByDate(EOD 定位+回退)、GetPreEodDividendSum(取EOD日期+PosiDividendSum)、方案C 平仓预览/收益结算两处 DividendIn 赋值
此后日志一律不使用 Debug 级(生产不可见)。任务编号 EQD-7004。
2026-08-14 12:53:39 +08:00
hjhan
37b889c3bf
test(dividend): 补全平端到端测试——登记日全平按交易场所规定不享有当日分红
...
全平场景端到端测试(DividendIn 由 GetPreEodDividendSum 真实算,非喂常量)。
登记日当日全平(盘中平仓→收盘持仓0),按各交易场所规定不享有登记日当日分红(股权登记日以收盘在册为准)。
系统行为正确:①DividendIn 读 T-1(=T日前待实现,正确不含当日);②EOD 全平 PosiQuantity=0 不计提当日。
断言:应得(T日前待实现)==实拿(DividendIn)(不享有当日符合规定)+ EOD 不计提当日。
合并原 d9a55fd1 + 830c72c4:前者误判'丢失缺陷',后者按业务规则修正为'不享有、系统正确'。
2026-08-14 12:49:45 +08:00
hjhan
9bc6344f18
test(dividend): 补端到端测试——盘中互换DividendIn真实算+保存+EOD,验证不重复不丢失
...
填补 MU_001 缺口:MU_001 的互换 DividendIn 是测试喂的常量,本测试由生产方法 GetPreEodDividendSum 真实算出(读 EOD 快照),再喂给 EOD——覆盖"预览算 DividendIn + EOD 扣减"完整链路。
验证:盘中收益互换(不扣持仓) → DividendIn=GetPreEodDividendSum(读T-1) → 保存 → EOD:TdCloseDividend 扣减 DividendIn(不重复) + 当日新计进 PosiDividendSum(不丢失) + 守恒(全程新计-全程实现=末尾PosiDividendSum)。
内存 stub(DealSvcStub+EodSvcStub),不连库,进 CI。
2026-08-14 10:28:10 +08:00
hjhan
bdba5fbecd
fix(EQD-7004): 补全分红登记日口径修复的多次付息累计测试与Trace日志
...
原修复 9df39491 仅覆盖单次登记日(4/3)的两个单点修复,本次补全 EQD-7004 的完整验证与排查手段:
- 测试 GLMS20260105_0006 新增 4 个场景:5 期 reg_date 过滤口径各自命中正确子集;五期票息累计=5x36160=180800;auto 实现归0后下次登记日重新累加;4 期挂账累计读 144640
- 分红读取关键链路加 Debug 级日志(生产可关):BondPaymentService.GetBondPayments(reg_date 过滤区间+命中条数)、SwapDealService.GetPreEodPositionByDate(EOD 定位+回退)、GetPreEodDividendSum(取EOD日期+PosiDividendSum)、方案C 平仓预览/收益结算两处 DividendIn 赋值
实跑 dotnet test 全 GREEN(6/6)。任务编号 EQD-7004。
2026-08-14 10:05:01 +08:00
hjhan
b2cbbff9e7
refactor(margin): 删除未接线的保证金死代码预留抽象
...
- 删除 MarginAccount 整类、IMarginResolver 子树(MarginForm/CashMargin/CreditMargin/GuaranteeMargin)、MarginBalance 只读 struct:全仓零生产实例化,结构上无法适配 CalcMarginInterest 的盘中差分模型。
- 删除仅覆盖上述死代码的 MarginLegTest(不损失活代码覆盖率)。
- 保留被 CalcMarginInterest 实际使用的 MarginCalc/MarginModes 活代码。
- 同步修剪 ARCHITECTURE.md 树图与对账表,清理 AccrualContext.cs 过期注释。
2026-08-14 08:55:37 +08:00
hjhan
909111ad2c
docs(margin): 修正 CalcMarginInterest remarks——SwapIntervalList 是互换观察日排期而非FR007
...
第三次修正(前两次基于错误理解)。查证代码后准确描述:
- SwapIntervalList 是"互换观察日排期"(阶梯利率表 + 结息日历),非 FR007 浮动(浮动由 FloatRateUnderlyingCode + interest_rest_days 独立驱动);保证金前端亦开放分段录入
- rate 来自 GetFixedRate(SwapIntervalList 取 Date≤unwindDate 最近段)
- 盘中用该 rate 全程,与旧 CalcDailySimpleInterest 完全一致(BuildSegmentRates 的 spread 也是 GetFixedRate 单一值全程,不按 SwapIntervalList 切段)——阶梯利率盘中半路变更的精细处理是既有未覆盖口径,非本次引入;EOD 因每日重取 GetFixedRate 能正确反映阶梯
纯注释,零行为变化。
2026-08-14 08:22:49 +08:00
hjhan
67d7733ed6
docs(margin): 修正 CalcMarginInterest remarks——SwapIntervalList 单段是保证金本性而非限制
...
第2点措辞修正:原写"SwapIntervalList 必须单段(多段会漏分段)"误导,把业务本性误述成代码限制。
实际:保证金=固定利率(业务定义),SwapIntervalList 多段是融资腿 FR007 概念与保证金无关;
CalcMarginInterest 只消费 rate(GetFixedRate 已处理分段),不直接读 SwapIntervalList,
单段 segmentRates 是对固定利率的正确建模。纯注释,零行为变化。
2026-08-14 08:14:32 +08:00
hjhan
692b8d753b
docs(margin): 补强 CalcMarginInterest 隐式假设/契约注释 + SwapEodPositionService orginPv 冗余说明
...
- CalcMarginInterest 加 <remarks>:显性化 4 点——InterestType 必须单利、SwapIntervalList 必须单段(违反静默算错、无 assert,前端保证)、方向须调用方翻转、preEod 首日就地修改;附定位指引(SwapCalcTrace 反推 accrualBasis)
- SwapEodPositionService 三处 FixedAmountAndMargin 的 orginPv 赋值加注释:仅固定值腿(mode 1)生效,保证金(5/6)被 CalcMarginInterest 忽略
纯注释,零代码行为变化;全量 SwapModule 524/524 通过。
2026-08-13 18:32:22 +08:00
hjhan
9df39491da
fix(dividend): 分红按债权登记日(reg_date)口径计提,手动互换读取当日EOD快照 (GLMS-20260105-0006)
...
- BondPayment 实体补映射 reg_date(债权登记日,对应 bond_payment_info.reg_date 列)
- BondPaymentService.GetBondPayments 改按 reg_date 过滤(原错用 pay_date_PL/支付日;pay_date_PL 是理论付息日,仍属支付日,非登记日)
- SwapDealService.GetPreEodPositionByDate 由 ValueDate < dealDate 改 <=,登记日当天手动互换读当日EOD分红而非T-1
- 新增 GLMS20260105_0006_RegisterDateDividendTest 回归测试(手工合成内存,先RED复现后GREEN 2/2)
根因:bond_payment_info 表仅有 pay_date_PL(理论付息日)/pay_date_act(实际付息日) 两个支付日,缺登记日;
代码用支付日判定票息归属,且手动互换只读 T-1 EOD 快照;登记日≠支付日(恰差一工作日)时缺陷被掩盖,
导致对话框分红收益显示 0。
2026-08-13 12:31:45 +08:00
hjhan
dea9c4cba5
docs(margin): 修复保证金计息重构后的过时文档与注释
...
按最新代码(CalcMarginInterest 已接生产、orginPv hack 已删、MarginAccount 未接线、保证金精度=12)修正:
- 删除 orginPv 维度重映射的孤儿 summary(方法已删)
- SwapDealService 注释:去掉 orginPv(InitSwapDealInterest)/保证金腿 引用
- SwapInterest/AccrualContext/InterestRate:去掉 Precision=11 是"保证金腿"、"保证金场景"等错误归因(保证金实际跑精度12)
- MarginAccount/MarginBalance:标注"尚未接线",生产入口指向 CalcMarginInterest,去掉"余额×利率×天数"过度简化
- 测试注释:去掉"无 orginPv/差分"(盘中保留差分)、"提交2 待切换"(已完成)
仅文档/注释,零代码行为变化。
2026-08-13 10:58:47 +08:00
hjhan
9b29211d3c
refactor(margin): 保证金计息切换到 CalcMarginInterest + 删 orginPv 外部维度 hack
...
- GetInterests 保证金分支(5/6)切到 CalcMarginInterest,不再走融资腿通用 CalcEodInterest/CalcUnwindInterest
- 删除 InitSwapDealInterest 的保证金 orginPv 维度 hack(保证金已不走该方法,成为死代码)
- CalcMarginInterest 修正三处与旧管线的对齐(全量回归发现):
· 加 endDate 参数(盘中用 InitInterestDate 的 endDate,否则少算天数)
· calcLast 合并 newCalcLast(与 CalcUnwindInterest 一致,算尾)
· 盘中保留 accrualBasis 差分(posiPrincipal 对齐状态路径相关,单一本金变量无法覆盖;orginPv 内部按 PreviousBalance 算,消除外部维度 hack)
- 更新 Shadow/GoldenReplay 测试调用点(加 endDate)
修正说明:盘中“消除差分”不可行——SPC_006(position 已对齐) 与 PrepaidPrincipalCloseTrace(position 未对齐) 期望相反,差分 accrualBasis 经 orginPv 自适应两种状态。CalcMarginInterest 真实收益收敛为:保证金领域独立 + orginPv 内聚 + 消除浮动/分段/复利死分支,而非消除差分。EOD 路径无差分(用昨日终本金)。
验证:全量 SwapModule 522/522 通过(0 失败);真实库黄金回放 60 条 0 差异。
2026-08-13 10:39:03 +08:00
hjhan
7243684839
test(margin): 新增真实库黄金回放验证——96库60条EOD逐日比对,新旧管线0差异
...
- MarginInterestGoldenReplayTest:连 192.168.2.96 测试库,对真实保证金交易(GLMS-20260701-0008/-0013/-0006)逐日 EOD 比对旧管线 GetInterests(settment=true) vs 新方法 CalcMarginInterest
- 结果:60 条腿×日比对,InterestAmount/TdInterestAmount 严格一致(容差1e-6),0 不一致
- 覆盖真实边界:追加预付金多行(base 135555/200000 各自计息)、InterestProfitSum 累计滚动、跨 EOD 续接
- 为提交2(切换生产+删 orginPv hack)建立真实数据安全网
2026-08-13 09:59:48 +08:00
hjhan
af1b4fd27f
refactor(longshort): 全量移除多空组合(StructType)子系统死代码(无入口/无存量,按需求重写优于维护)
2026-08-13 09:50:25 +08:00
hjhan
a86b496f87
test(margin): 新增 CalcMarginInterest 影子对账——保证金计息消除 orginPv/差分,与旧管线数值一致
...
- 新增 CalcMarginInterest(SwapDealService):保证金专属计息,复用 SimpleInterestAccrual 纯函数,notional 直接取保证金余额(EOD=昨日终本金/盘中=今日本金),消除融资腿差分公式 accrualBasis=TdInterestPrincipal+posiPrincipal-orginPv 与 orginPv 维度 hack(对保证金 accrualBasis 恒等于 posiPrincipal,差分冗余)
- 保留累计语义(priorAccrued+增量),满足下游 SwapEodPositionService 字段契约
- 新增 MarginInterestShadowTest:5 场景对账(EOD 续接/首日、盘中全平/部分平仓/互换),新旧 InterestAmount/TdInterestAmount 严格一致
- 本提交仅影子对账,生产路径未改(GetInterests 仍走 CalcEodInterest/CalcUnwindInterest);下一步提交2 切换生产 + 删 orginPv hack
零生产风险;编译 0 错误;影子对账 5/5 + 现有保证金/利息回归 60/60 通过。
2026-08-13 09:37:42 +08:00
hjhan
905bd407e2
refactor(frontend): 清理已删除利息模式 7/8 的前端死分支
...
后端 InterestModeEnum 已删除 mode 7/8(无历史数据),前端对应分支恒不成立。
移除 swaptrade 下 6 个 JS 文件中的 ==7/==8 死分支,并精简仅校验 mode7/8
唯一性的 checkSwapRateList(保留 changeInterestMode 方法签名以对齐 cshtml 绑定)。
2026-08-13 09:05:58 +08:00
hjhan
70550af29a
refactor(funding-leg): 清理CalcNotional死参数posiLong/posiShort+修正过时InterestMode注释
...
- 删除 IFundingLegStrategy.CalcNotional 的 posiLong/posiShort 死参数(多空存续腿界面已禁用,三个实现均不读取),同步三个实现签名、SwapDealService 唯一调用点、FundingLegStrategyTest 7 处调用
- 修正 SwapPosition/SwapFlowEvent/EodSwapPosition 的 InterestMode 字段注释(去掉已删的 3/4,补全 5/6/9)
- 重写 SwapUnwindFloatingLegDiagnosticTdd 过时类注释
零行为变化;编译 0 错误;FundingLegStrategyTest 11/11 通过。
2026-08-13 08:51:21 +08:00
hjhan
beb13ff52f
docs: 删除不适用的利息部分平仓尾差缺陷分析文档
...
该文档分析的几个 bug 结论不正确,已不再适用,移除。
2026-08-13 08:38:51 +08:00
hjhan
50bc6562da
chore: 删除误提交的 TdCarryInCharacterizationTest 占位测试(沙箱漂移产生的无意义文件)
2026-08-12 18:29:51 +08:00
hjhan
dfdc890749
test: 补全 SaveAutoSwapDeal 的测试 seam——修复6个AS_*测试失败
...
- SwapEodPositionService: AddSwapEvent 虚方法(已存在)替换 line 741 的 new SwapEventService 直调
- SwapEodPositionService: 新增 PersistFlowEvent 虚方法,替换 line 749/760 的 DbContext.swap_flow_event.Add 直调
- TestableSwapEodPositionService: PersistFlowEvent 改为 override
- BondTrsAutoSwapScenarioTest.AutoSwapEodService: override PersistFlowEvent 同步到 PersistedFlowEvents
测试: 511→517 通过,7→0 失败
2026-08-12 18:23:51 +08:00
hjhan
84820a3203
test: 修复预存在测试失败-AddClientCashInCashOut no-op override + FR007取价失败兜底
...
- TestableSwapEodPositionService: override AddClientCashInCashOut 与 AddClientCash 同构 no-op,修复6个AS_*测试客户信息未找到异常
- GLMS20260805ClosePercentDiffDiagnoseTest: FR007取价失败走 Inconclusive(与连不上库同语义,外部数据依赖不应判为测试失败)
AS_* 仍有深层失败(自动互换未触发,interestList=0),属预存在的测试数据问题,需单独排查
2026-08-12 18:08:47 +08:00
hjhan
f1f7cae832
refactor(accrual): 抽取BuildSegmentRates共享分段取率+清理needPrice死参数
...
- 抽取 BuildSegmentRates:统一单利/复利分段取率循环,参数化 fetchAfterDate (单利传 ValueDate 仅取新段,复利传 null 全程取)
- 修复 BuildSegmentRates static→instance:访问实例属性 IndexFixer
- 清理 CalcDaily 层 needPrice 死参数:4个 CalcDaily* 方法签名移除 needPrice;上层 CalcSwapInterests/GetInterests 保留 (virtual seam/位置参数兼容)
- 修复 6 处调用点 needPrice 参数传递
- 新增影子测试:单利+FR007浮动+部分平仓+历史归档,验证 segmentRates 一致
- 新增 TdCarryInCharacterizationTest:钉死部分平仓 TdInterestAmount carry-in 行为
测试: 511通过 / 7预存在失败(数据依赖) / 9跳过
2026-08-12 18:02:36 +08:00
hjhan
c412f918d9
refactor(swap): Phase3 提取ClosePercentMath共享模块
...
SwapDealService的4个public static ClosePercent方法body搬到ClosePercentMath.cs:
- ResolveUnwindPreviousNotional (上一日终浮动端名义本金)
- ToRemainingClosePercent (A→B 占期初→占剩余)
- ToOriginalClosePercent (B→A 逆转换)
- CalcDefaultInitClosePercent (默认占期初比例)
DealService保留4个一行转发壳, 外部调用(含6+测试文件)零改动
核实EodService内联closePercent公式与此不同, 非重复, 不替换
SwapModule零回归(7基线/510通过)
2026-08-12 17:31:39 +08:00
hjhan
69295f31ce
refactor(eod): Phase2 提取EodPnlCalculator——11个static方法搬出SwapEodPositionService
...
SwapEodPositionService的static纯计算方法搬到EodPnlCalculator.cs:
- private→internal: RoundMoney/RoundEodInterest/NormalizeEodPositionForStorage/SetFloatingRealizedPnl/FillPositionLegSummary/SumInterestPnL/CalculateWeightedMarginRate
- public留转发壳: CalculateSwapRealizedPnl/NormalizeInterestSignForReport/CalculateWeightedMarginInterest/SetFixedLegRealizedPnl
SwapEodPositionService内所有调用点加EodPnlCalculator前缀
SwapModule零回归(7基线/510通过)
2026-08-12 16:46:13 +08:00
hjhan
40756a28b3
refactor(accrual): BuildLegRate/BuildEodPolicy移到各自类型(Phase1补完)
...
BuildLegRate → FundingLegRate.Build(position, spread, float) — 利率值对象的自然工厂
BuildEodPolicy → AccrualPolicy.BuildEod(position, annualDays, isCompound) — 计息政策的自然工厂
SwapDealService删除2个private static定义, 4处调用点改用类型方法
SwapModule零回归(7基线/510通过)
2026-08-12 16:32:04 +08:00
hjhan
b9362ea700
refactor(swap): Phase1 提取UnwindNormalizer+TradingFeeCalc出SwapDealService
...
SwapDealService的10个private static纯逻辑方法搬到两个新文件:
- UnwindNormalizer.cs: NormalizeNotionalValues/FullCloseRequest/Recalculate/IsFullClose/SettledInterestAmounts/EventUnwindDate (6个)
- TradingFeeCalc.cs: CalcInitTradingFee/CalcInitTradingFeePending (2个)
SwapDealService内21处调用点加类名前缀, 反射测试改为直接调用(public)
SwapModule零回归(7基线/510通过)
2026-08-12 16:26:12 +08:00
hjhan
89eae7555f
docs: 任务4 EOD续接风险分析 + SwapDealService方向比例收口
...
新增 docs/eod-continuation-proposal.md:
- 记录4个风险(并本金起点/consumedInterest语义/resetCarry/全平重放)
- 记录验证方案(6场景影子测试)
- 标注待立项,不混入日常重构
SwapDealService 收尾: 3处内联方向比例→DirectionRatio.ReceivePay
- line389: PosiDirection收取?-1:1 → -ReceivePay
- line1104/1235: InterestDirection==1?1:-1 → ReceivePay
SwapModule零回归(7基线/510通过)
2026-08-12 15:24:15 +08:00
hjhan
8419d53421
refactor(eod): MtmCalc.BlendPrice提取加权均价混合(候选J)
...
4处内联 (prevPrice*prevQty + sum) / total → MtmCalc.BlendPrice(...)
SwapModule零回归(7基线/510通过)
候选K(单点TdRealizedPnL)/L(2处guard差InterestType)/M(2处guard)/N(单点)为低频,
提取收益不足以抵消新增方法的开销, 暂不提取
2026-08-12 15:03:00 +08:00
hjhan
dbdc975da4
refactor(eod): 提取FillPositionLegSummary/SumInterestPnL消除eod_swap汇总重复(候选H)
...
SaveEodSwap与UpdateEodSwap各有~15行相同的持仓腿汇总代码:
- NotionalValueLong/Short(rounded) + MarketValueLong/Short + FloatingPnL + dv01 + TdCloseQty
→ FillPositionLegSummary(eod_Swap, positions)
- 利息腿ForEach按InterestLegPnl汇总InterestPnL
→ SumInterestPnL(interestPositions)
两处合计净减~18行
SwapModule零回归(7基线/510通过)
2026-08-12 14:53:41 +08:00
hjhan
aeb55a01ad
refactor(eod): 提取InterestIncomeCalc.DailyAccrual/RollRealized + MtmCalc.ReturnLegProfitSum
...
候选B: 3处日利息 principal*(rate+float)/annualDays → InterestIncomeCalc.DailyAccrual
候选D: 4处 PosiProfitSum=Mtm+Div+Fee → MtmCalc.ReturnLegProfitSum
候选E: 4对 RealizedInterest/RealizedInterestFee 滚存 → InterestIncomeCalc.RollRealized
SwapModule零回归(7基线/510通过)
2026-08-12 14:50:24 +08:00
hjhan
1aa0579fbd
refactor(eod): MarginModes.FixedAmountAndMargin + DirectionRatio.RateType提取
...
候选F: 3处内联 new List{固定值,初始预付金,追加预付金} → MarginModes.FixedAmountAndMargin
候选I: 7处内联 收取?Buy:Sell → DirectionRatio.RateType(direction)
SwapModule零回归(7基线/510通过)
2026-08-12 14:38:04 +08:00
hjhan
af94003939
refactor(eod): DirectionRatio.ReceivePay/InterestLegPnl替换21处内联三元
...
SwapEodPositionService中散落的收取?1:-1三元表达式和ratio+margin flip块:
- 9处InterestLegPnl块(3-5行→1行): 收取?1:-1 + if(MarginModes)ratio=-ratio
- 12处ReceivePay三元: 收取?1:-1 → DirectionRatio.ReceivePay(dir)
- 含2处反向(收取?-1:1 → -DirectionRatio.ReceivePay)
净减约30行, 消除+1/-1写反的风险
SwapModule零回归(7基线/510通过)
2026-08-12 14:33:23 +08:00
hjhan
bfa230381b
refactor(accrual): 提取BuildLegRate/BuildEodPolicy消除EOD wrapper构造重复
...
EOD CompoundEod + SimpleEod 各有一份相同的FundingLegRate构造(3行)
和AccrualPolicy构造(5行), 共16行重复。
提取为:
- BuildLegRate(position, spread, effectiveFloat): 固定腿→Fixed, 浮动腿→Floating
- BuildEodPolicy(position, annualDays, isCompound): 算头算尾+重置周期
每个EOD wrapper从10行构造代码→2行调用, 净减12行
SwapModule零回归(7基线/510通过)
2026-08-12 14:01:24 +08:00
hjhan
9d321378ac
cleanup(accrual): 删除orginPv死参数(3个方法签名+所有调用点)
...
源码实证orginPv在5/6个CalcDaily方法中是死参数(方法体不读取):
- CalcDailyCompoundInterest: 删 decimal orginPv(3个调用点同步删)
- CalcDailyCompoundInterestByEod: 删(1个调用点+4个测试同步删)
- CalcDailySimpleInterestByEod: 删(1个调用点+2个测试同步删)
保留orginPv的方法(真实消费者):
- CalcDailySimpleInterest: 差分公式 posiPrincipal - orginPv
- GetInterests/CalcUnwindInterest/InitSwapDealInterest: 转发链
SwapModule零回归(7基线/510通过)
2026-08-12 13:58:43 +08:00
hjhan
9d8cfb5ad0
refactor(accrual): 拆分FundingLegAccrual→SimpleInterestAccrual/CompoundInterestAccrual
...
单利与复利语义完全不同(单利本金恒定/复利重置日并本金),
拆成两个独立静态类,各自只含自己的方法:
SimpleInterestAccrual:
- AccrueEod (原AccrueSimpleEod)
- AccruePeriod (原AccrueSimplePeriod)
CompoundInterestAccrual:
- EodBasis (原CompoundEodBasis)
- AccrueEod (原AccrueCompoundEod)
- AccruePeriod (原AccrueCompoundPeriod)
方法名去掉Simple/Compound前缀(类名已携带类型),消除冗余
SwapModule零回归(7基线/510通过)
2026-08-12 13:40:47 +08:00
hjhan
57156feec1
refactor(accrual): 提取ResolveFloatRate收口FR007定盘逻辑
...
EOD单日取率(CompoundEod/SimpleEod)与intraday多日取率(BuildSegmentRates)
原各有一份相同的GetFixingDate+TryGetFixing+throw逻辑(~8行/处,3处共24行)。
提取为私有 ResolveFloatRate(position, date, fallback):
- 无浮动标的返回fallback; 取到非零fixing返回fixing; 取不到抛异常
- EOD: isResetDay ? ResolveFloatRate(...) : floateRate (1行替代12行)
- BuildSegmentRates: 循环内直接调用(1行替代8行)
净减~15行, FR007定盘逻辑收口到一处
SwapModule零回归(7基线/510通过)
2026-08-12 13:37:40 +08:00
hjhan
c86633479d
refactor(accrual): 接线SimpleInterest/CompoundInterest内部 + 分段修复 + 去重
...
CalcDailySimpleInterest/CalcDailyCompoundInterest内部逐日循环→分段纯函数(签名不变):
- AccrueSimplePeriod: AccruedToday改未缩放累计(TdInterestAmount口径)
- AccrueCompoundPeriod: 新增out finalBasis供flowEvent.InterestPrincipal精确赋值
- 修复5处分段边界bug(includeStart/includeEnd/resetCarryInterest interestPeriod=1场景)
- 提取BuildSegmentRates消除SimpleInterest/CompoundInterest取率重复
- 影子测试补AccruedToday断言关闭测试盲区
SwapModule零回归(7基线/510通过)
2026-08-12 13:09:17 +08:00
hjhan
85746d7ee9
test(accrual): 新增同日双次部分平仓字符化测试 + EOD基数快照replay诊断
...
- SwapUnwindSameDayDoublePartialTest: 内存Stub驱动同日两次部分平仓(30%/50%),
验证基数线性累加(0.3N+0.35N=0.65N),推翻"基数不滚动"假设;缺口仅在
调用方是否传陈旧notional,已文档化
- GLMS20260805ClosePercentDiffDiagnoseTest: 从Resources快照反序列化离线重跑
EOD基数诊断,去DB化;无快照Inconclusive,保留Assert.Fail作8/5 bug护栏
2026-08-12 11:28:40 +08:00
hjhan
ff937f24e7
refactor(accrual): EOD去退化差分——删除baseNotional死参数
...
EOD路径 orginPv≡posiPrincipal(调用点line1091/1096实证),notional==baseNotional恒成立,
差分项 notional-baseNotional 恒为0,baseNotional 是死参数。
简化:
- AccrueSimpleEod: 删 notional+baseNotional 两参数,basis=priorNotional 直赋值
- AccrueCompoundEod: 删 baseNotional 参数,非重置日 basis=priorNotional
- SimpleEodBasis 整个删除(不再需要)
- CompoundEodBasis 去掉 baseNotional 参数
- EodContext trace 去掉 baseNotional
- 差分注释块删除(EOD不再有差分)
差分逻辑 notional-baseNotional 只该存在于 unwind 专用路径(Period函数本就没有baseNotional)
净减20行(18增/38删),SwapModule零回归(7基线/508通过/8跳过)
2026-08-12 10:58:53 +08:00
hjhan
ffd539d8c3
refactor(accrual): 抽出CompoundEodBasis/SimpleEodBasis消除基数公式重复
...
- 基数差分公式(priorNotional+notional-baseNotional)原在AccrueCompoundEod内部与调用点各算一遍
- 抽成public static单一真相源: CompoundEodBasis/SimpleEodBasis, 纯函数与调用方共用
- 差分语义文档集中到一处(EOD退化为priorNotional / unwind增量生效)
- 吸收外部review: 三元拆具名方法 + 消重复, 但否决priorFloatingLegNotional(orginPv非浮动腿概念)
- 影子测试16/16绿, SwapModule零回归(7基线/508通过)
2026-08-12 10:48:04 +08:00
hjhan
3b02440979
refactor(accrual): 接线CalcDailyCompoundInterestByEod→AccrueCompoundEod + 全链路Trace
...
- AccrualTrace新增Segment(分段区间/天数/基数/利率)与EodContext(重置日/平仓比例/基数分量)语义方法
- AccrueSimplePeriod/AccrueCompoundPeriod补全AccrualTrace?参数:MarkStart→逐段Segment→复利Rollover→Unwind→MarkEnd
- CalcDailyCompoundInterestByEod内部实现下沉至FundingLegAccrual.AccrueCompoundEod纯函数
删除调试垃圾LogFactory('test').Error,取率/重置日/remainingFraction逻辑保留
- flowEvent.InterestPrincipal/FloatRate副作用在调用方保留(下游EOD播种次日TdInterestPrincipal)
- 全量SwapModule测试零回归(7基线失败/508通过/8跳过)
2026-08-12 10:37:52 +08:00
hjhan
2f7caa7a1f
refactor(accrual): referenceNotional→baseNotional, notional统一
...
- referenceNotional → baseNotional(更短更清晰)
- 新代码统一用 notional(不用 principal):
QuantLib/Strata 对 swap leg 用 notional 是业界标准
- DB字段(InterestPrincipalFix等)保持不动(legacy)
- 注释标注 legacy 对照(orginPv/originalPv/dynomicPrincipal)
验证: 编译0错误, 7影子测试全过, 全量523测试7失败(基线一致)。
2026-08-12 10:20:13 +08:00
hjhan
ce6c0812e1
refactor(accrual): 参数命名对齐业界标准(QuantLib/Strata)
...
FundingLegAccrual 4个方法的参数命名全面纠正:
| 旧名 | 新名 | 理由 |
|-------------------|-------------------|------|
| originalPv | referenceNotional | Pv(现值)概念错误,实际是参考本金 |
| closeRatio/closePercent | unwindFraction | 统一,对齐 ApplyUnwind.unwindPercent |
| consumedInterest | realizedInterest | 对齐 AccrualState.RealizedInterest |
| priorUnrealized | priorAccrued | 对齐 InterestResult.Accrued |
| priorAccrualPrincipal | priorNotional | 简洁,对齐 QuantLib notional |
| positionPrincipal | notional | 简化,去掉冗余前缀 |
| dynomicPrincipal | accrualBasis | 修正typo+用业界术语 |
同步更新:
- SwapDealService.CalcDailySimpleInterestByEod 调用点
- 3个影子测试文件命名参数
- SwapInterest.Round 改为 public(所有Round收口一处)
删除半成品残留: SwapInterest_CompoundInArrears_RolloverTimingTests.cs
验证: 编译0错误, 7个影子测试全过, 全量520测试7失败(基线一致)。
2026-08-12 10:11:26 +08:00
hjhan
3f194f7ccc
fix(accrual): Round收口到SwapInterest.Round + 复利分段边界修复
...
3项修复:
1. SwapInterest.Round 从 private 改为 public:
所有计息路径收口到一处, FundingLegAccrual 不再用裸 Math.Round
2. ApplyUnwind 精度警告:
注释标注'资金腿务必传 FundingLegPrecision=12', 默认11是易忘的坑
3. AccrueCompoundPeriod 分段边界修复(根因):
旧bug: 中间段 IncludeEnd=true 导致重置日利息用了旧本金
修复: 中间段 IncludeEnd=false(半开区间), 重置日归下一段用新本金
对齐旧逐日循环语义: 重置日先更新本金再算息
同时: 中间值不Round(对齐旧代码只在最终输出Round一次)
清理: 删除 SwapInterestAccrueCompoundInArrearsTest 半成品残留
验证: 编译0错误, 7个影子测试全过, 全量520测试7失败(基线一致)。
2026-08-12 09:59:53 +08:00
hjhan
552fb2061b
Merge branch 'glms/feature/1.4.2' of http://git.yiliantech.com/gitlab/otc-dev/zszq-trs into glms/feature/1.4.2
2026-08-12 09:48:53 +08:00
hjhan
431ac9b502
feat(accrual): 新增 AccrueCompoundPeriod + 影子测试(3个全过)
...
第3步迁移: CalcDailyCompoundInterest(盘中复利多日)。
新增纯函数 AccrueCompoundPeriod:
- 从 PosiStartDate 到 endDate 全程重放
- 每个重置日并本金: principal + replayed interest
- 末日(endDate)为重置日且 resetCarryInterest!=0 时用存量替代
- consumedInterest × closePercent 在末尾扣除
- 分段模型替代逐日循环, 段内本金恒定+利率恒定
影子测试(3个,全过):
- 固定利率全平+末日重置日: 旧新一致
- 部分平仓30%+consumedInterest扣除: 旧新一致
- 算头算尾(calcMode=11): 旧新一致
清理: 删除 SwapInterestAccrueCompoundInArrearsTest(半成品残留,
依赖已回退的 SwapInterest 签名)。
修复: SwapInterestAccrueCompoundInArrearsTest 缺 using(已随文件删除)。
验证: 编译0错误, 全量520测试7失败(基线一致)。
4个CalcDaily*方法的新架构纯函数全部就绪, 旧方法暂保留对比。
2026-08-12 09:48:49 +08:00
hjhan
963b5e66af
feat(accrual): 新增 AccrueSimplePeriod + 影子测试
...
第2步迁移: CalcDailySimpleInterest(盘中单利多日)。
新增纯函数 AccrueSimplePeriod:
- 单利特征: 计息本金恒定(差分 = priorAccrualPrincipal + positionPrincipal - originalPv)
- 按重置日分段, 每段用 AccrualDays 算天数×日利息(无逐日循环)
- 续接 priorValueDate 之后的日期
修复: SwapInterest.Round 是 private, 新方法改用 Math.Round。
修复: IReadOnlyList 无 IndexOf, 改用 for 循环索引。
影子测试(2个,全过):
- 固定利率无归档: 旧新一致(差分本金=0,利息=0,符合旧逻辑)
- 有归档续接+部分平仓50%: 旧新一致
验证: 编译0错误, 全量517测试7失败(基线一致)。
2026-08-12 09:27:20 +08:00
hjhan
217c2d5826
feat(accrual): 新增 FundingLegAccrual.AccrueCompoundEod + 影子测试
...
第1步迁移: CalcDailyCompoundInterestByEod(EOD复利单日)。
新增纯函数 AccrueCompoundEod:
- 重置日: 本金 = positionPrincipal + priorUnrealized × remainingPercent
- 非重置日: 本金 = priorAccrualPrincipal + positionPrincipal - originalPv
- InterestAmount = priorUnrealized × closeRatio + dayInterest
- TdInterestAmount = dayInterest(不含 priorUnrealized)
影子测试(2个,全过):
- 重置日场景: 旧新 InterestAmount/TdInterestAmount 一致
- 非重置日场景: 同上
旧方法暂不删——新旧并存,对比验证后再替换调用点。
验证: 编译0错误, 全量515测试7失败(基线一致)。
2026-08-12 09:15:01 +08:00
hjhan
5dc8bdbf9e
refactor(interest): 计息 trace 命名对齐业界最佳实践
...
- InterestTrace → AccrualTrace:追踪对象是"计息过程"而非泛指的 Interest,与仓库
既有的 SwapCalcTrace(-Trace 后缀约定) 及 AccrualContext/AccrualBoundary/AccrualPolicy
家族一致;AccrualTrace 经 SwapCalcTrace.Write 常驻落盘,二者职责分清(收集器 vs 落盘通道)。
- InterestStep → AccrualTraceEvent、InterestTraceEntry → AccrualTraceEntry:
条目类别对应 QuantLib/Strata 的"事件"概念(AccrualTraceEvent),命名自描述。
- SwapCalcTrace.Persist → Write:"Persist" 易误读为落库持久化;此处只是写入日志通道,
且类内已有私有 Record(string),故用 Write 避免歧义。
纯改名、数值逻辑零改动;YLErpDAL + UnitTestProject 编译 0 错。
2026-08-12 07:05:41 +08:00
hjhan
be3be877ec
refactor(interest): 引入 AccrualContext 并将 AccrueCompound 重命名为 AccrueCompoundInArrears
...
1. 新增 AccrualContext 只读值对象,把 annualDays/precision/trace 三个"与金额利率无关"
的横向参数打包为上下文成员。计息纯函数只吃一个 ctx,签名去噪、可读性提升;
ctx 为只读值对象(非类的实例/静态字段),不破坏纯函数(线程安全、可重入、可测)。
trace 因此成为"传入上下文的成员"而非散落参数,满足"默认成员而非参数"的诉求。
2. AccrueCompound → AccrueCompoundInArrears:精确表达 OIS/SOFR/FR007 的
compounded-in-arrears 语义(每子区间取定盘、段末滚入本金),与
InterestRate.Compounding.Compounded 闭式分支(TRS 下死路径)一刀两断、不再混淆。
纯增量、数值逻辑不变;YLErpDAL + UnitTestProject 编译 0 错 0 警;FR007 两段切换场景
实跑 trace 与旧版数值完全一致。
2026-08-12 06:13:38 +08:00
hjhan
fcf52a305e
feat(interest): 融资腿计息接入 trace 并常驻落盘
...
FundingLegAccrual.AccrueSimpleEod 接 InterestTrace;SwapCalcTrace 新增 Persist
把收集器条目经 Critical 无条件落盘(与开关无关);已迁移的 EOD 单利适配器
CalcDailySimpleInterestByEod 创建并 Persist trace。纯增量、数值逻辑不变。
2026-08-12 06:05:02 +08:00
hjhan
fba87bd7cc
feat(interest): AccrueCompound 支持每段独立利率 + 发射 Reset/Rollover trace
...
重构为按重置日切段、每段可有独立利率(resetSchedule),适配 FR007 浮动逐段取价
(取价仍在编排层,原语只吃一个数,与 QuantLib/Strata 同范);trace 记录
重置日前后利率切换与段末并本金(本金增加),完整覆盖"重置日前后/利率切换/本金增减"。
2026-08-12 06:05:02 +08:00
hjhan
03861ea369
feat(interest): 新增 InterestTrace 结构化追踪收集器
...
纯值对象(零日志依赖):计息纯函数把"发生了什么"记录为语义化条目
(Day/ResetBefore/ResetAfter/Rollover/Unwind),由适配器统一经 SwapCalcTrace
常驻落盘。ToString 产出稳定可 diff 的逐行文本,新旧引擎同一笔交易可直接 diff
定位"是计算变了还是重构引入漂移"。
2026-08-12 06:05:01 +08:00
hjhan
63bfc8ca8f
refactor(interest): SwapDealService 接入 FundingLegRate 工厂并复用 FundingLegPrecision
...
取率处改用 Fixed/Floating 工厂;InterestCalculationPrecision 引用
SwapInterest.FundingLegPrecision,消除重复常量定义。
2026-08-12 05:36:02 +08:00
hjhan
dee491b8d0
refactor(interest): FundingLegAccrual 删除危险骨架,仅保留纯函数 AccrueSimpleEod
...
移除标注"切勿在未迁移前接入生产"的 AccrueDay/AccruePeriod 骨架(含 IIndexFixer/
Func 取价),保留与旧实现逐字对齐的纯函数,消除两套计息逻辑并存的隐患。
2026-08-12 05:36:02 +08:00
hjhan
e7514a2d84
cleanup(interest): 删除 AccrualPolicy 未使用的 FromLegacy 工厂与冗余 using
...
FromLegacy 无调用方;移除 YLErp.DBModels using 后 InterestTypeEnum 仅存于注释。
2026-08-12 05:36:02 +08:00
hjhan
4e67af52e8
refactor(interest): FundingLegRate 瘦身为单一 all-in 利率值对象
...
固定/浮动腿的区别是取率环节的事,计息只认一个数;以 Fixed/Floating 工厂
取代原 4 字段构造,不再为腿型背负多余字段。
2026-08-12 05:36:01 +08:00
hjhan
39ec71f268
refactor(interest): SwapInterest 计息数学收敛为 InterestRate,新增资金腿精度常量
...
引入 ToInterestRate 入口把 TRS 利率收敛为通用原语;提取 FundingLegPrecision=12
公共常量,消除 SwapDealService 与 FundingLegAccrual 的重复定义。
2026-08-12 05:36:01 +08:00
hjhan
aff540801c
feat(interest): 新增通用利息原语 InterestRate(与互换解耦)
...
单利/复利/连续复利收敛为 Compounding 一个 switch 分支,利息计算不再住在
SwapModule/互换词汇里,谁需要算息都能直接用。连续复利仅 e^(r·t) 一行。
2026-08-12 05:36:01 +08:00
hjhan
0c447ff5ff
refactor: 提取融资腿计息领域模型 (AccrualPolicy/FundingLegRate/AccrualState/FundingLegAccrual) - 将 CalcDailySimpleInterestByEod 纯数学下沉至 FundingLegAccrual.AccrueSimpleEod, 消除 double 往返转换, 引入值对象收敛散落参数
2026-08-11 22:37:19 +08:00
hjhan
246392b665
cleanup: 删除 SwapInterestAdapter 半成品, 回退 SwapInterest 未提交改动
...
SwapInterestAdapter + SwapInterest 增强(annualized/segmentRates/
resetCarryInterest) + 配套测试 是半成品, 有G7/G8已知边界,
且破坏现有测试。按审查建议回退, 作为独立PR后续处理。
当前工作区只剩 BondIndex/RateYield 到期日修复。
验证: 编译0错误, 全量513测试7失败(基线一致)。
2026-08-11 19:23:21 +08:00
hjhan
dafc06793e
refactor: AddClientCashInCashOut 加 virtual + 修正架构文档
...
AddClientCashInCashOut 从 public 改为 public virtual,
使测试可 override, 消除 RecordMarginCashFlow 迁出的阻塞。
AddClientCash 已是 virtual, 这是统一两者。
修正 ARCHITECTURE.md: 保证金有余额和返息(非'没有计息基数')。
验证: 编译0错误, 全量513测试7失败(基线一致)。
2026-08-11 17:09:13 +08:00
hjhan
7cea09d976
docs: 新增 SwapModule ARCHITECTURE.md 架构说明
...
记录重构后的三大限界上下文结构:
- FundingLegs(融资腿) / Margin(保证金) / ReturnLegs(标的端)
- 命名规则(防歧义): Funding/Return/Margin/FloatRate
- Core 层纯函数库(SwapInterest + IIndexFixer)
- 已消除的 inline 重复清单
- 方向因子类型规范(int)
- 待后续改造的接缝预留
不改原有文档(corp-action-*.md 仍准确)。
2026-08-11 17:03:44 +08:00
hjhan
5a7869e0c9
fix(return-leg): PositionValueCalc.ratio 改为 int, 统一方向因子类型
...
ratio(收取=1/支付=-1)是方向因子, 应该是 int。
和 MtmCalc/DirectionRatio/MarginCalc 的 int 保持一致。
调用点(SwapEodPositionService 4处)原 ratio 是 decimal,
加 (int) 显式转换(值恒为 1或-1, 零精度损失)。
排查确认: 这是唯一的类型不一致, 其他纯函数参数类型均已统一。
验证: 编译0错误, 全量513测试7失败(基线一致)。
2026-08-11 16:59:22 +08:00
hjhan
16c44d3b50
refactor(return-leg): 抽取 PositionValueCalc 持仓价值汇总
...
SwapEodPositionService 8处 SwapPositionValue inline 公式替换:
- 4处 InterestProfitSum * ratio + PosiProfitSum → PositionValueCalc.Calc(带ratio)
- 4处 InterestProfitSum + PosiProfitSum → PositionValueCalc.Calc(默认ratio=1)
持仓价值 = 利息端收益 + 浮动端收益, 8处副本→1个纯函数。
这是最后一个高性价比的纯函数提取。
验证: 编译0错误, 全量513测试7失败(基线一致)。
2026-08-11 16:50:21 +08:00
hjhan
744f1ae448
Merge branch 'glms/feature/1.4.2' of http://git.yiliantech.com/gitlab/otc-dev/zszq-trs into glms/feature/1.4.2
2026-08-11 15:46:35 +08:00
hjhan
7e169dd53f
fix(margin): 回退 PreviousBalance 简化, 恢复三级 fallback
...
尝试去掉第2级(TdInterestPrincipal)导致5个保证金测试失败。
根因: 生产 EOD 归档(eod_swap_position(35774))的 InterestPrincipalFix=0,
只有 TdInterestPrincipal 有值。第2级不是死代码, 不可删。
恢复三级 fallback, 补充注释说明每级命中的真实场景。
教训: 不能只看赋值点判断字段是否有值, 必须看实际数据。
验证: 编译0错误, 全量509测试7失败(基线一致)。
2026-08-11 15:46:28 +08:00
hjhan
6fe5d81917
refactor(margin): 3个保证金纯函数迁入 MarginCalc, 改正命名
...
从 SwapDealService 剥离到 Margin/MarginCalc.cs:
- PreviousBalance: 取上一日终保证金余额(原 ResolveMarginOrginPv, 改正命名)
- FlipDirection: 保证金方向翻转(原 FlipMarginDirection)
- AccumulateSettlement: 平仓汇总(原 AccumulateMarginSettlement)
命名修正: orginPv 是融资腿概念, 保证金没有; 改为 PreviousBalance。
SwapDealService 里删掉这3个private方法, 调用点改用 MarginCalc.XXX。
RecordMarginCashFlow 暂留(依赖实例方法 AddClientCash)。
保证金纯函数现在全部在 Margin 模块, SwapDealService 只保留
RecordMarginCashFlow(资金记录, 需要实例上下文)。
验证: 编译0错误, 全量509测试7失败(基线一致)。
2026-08-11 14:35:42 +08:00
hjhan
2fbffcceb4
refactor(margin): 3处散落保证金资金记录收敛到 RecordMarginCashFlow
...
RecordMarginCashFlow 加委托重载, 统一 AddClientCash(virtual)和
AddClientCashInCashOut(非virtual)两条路径。
替换3处 inline:
- :1663 SwapUnwind 平仓(AddClientCash, 只有应付预付金)
- :1979 DealUnwind(AddClientCashInCashOut, 只有应付预付金)
- :2128 SwapIncome 互换(AddClientCash, 只有预付金返息)
- :2195 自动互换(AddClientCash, 只有应付预付金, swapEvent.unwindData)
注释掉的返息代码(//if SwapMarginRebatePnl)同步清理——
通过传 marginRebate:0 表达'不写返息', 不再留注释代码。
SwapDealService 保证金资金记录 inline: 4处 → 0。
全部走 RecordMarginCashFlow 的 2 个重载。
验证: 编译0错误, 全量509测试7失败(基线一致)。
2026-08-11 14:26:29 +08:00
hjhan
11923e11b7
refactor(margin): 抽取 RecordMarginCashFlow 保证金资金记录
...
SwapLongShortUnwind 里 inline 的保证金资金记录
(应付预付金 + 预付金返息)抽成独立方法。
SwapDealService 内保证金方法清单(待整体迁入Margin):
- ResolveMarginOrginPv 维度重映射
- FlipMarginDirection 方向翻转
- AccumulateMarginSettlement 平仓汇总
- RecordMarginCashFlow 资金记录(新)
验证: 编译0错误, 全量509测试7失败(基线一致)。
2026-08-11 13:48:06 +08:00
hjhan
870cd337f6
refactor(margin): 抽取 AccumulateMarginSettlement 保证金平仓汇总
...
把 SwapUnwind 里 inline 的保证金汇总逻辑(SwapMarginRebatePnl +
SwapMarginAmount)抽成独立方法, 与融资腿汇总分离。
原循环里保证金和融资腿混在一起, 现在保证金走
AccumulateMarginSettlement, 融资腿汇总留在主循环。
待迁入 Margin 模块。
验证: 编译0错误, 全量509测试7失败(基线一致)。
2026-08-11 13:18:20 +08:00
hjhan
585cefa85d
Merge branch 'glms/feature/1.4.2' of http://git.yiliantech.com/gitlab/otc-dev/zszq-trs into glms/feature/1.4.2
2026-08-11 13:13:35 +08:00
hjhan
29df4c480d
refactor: 删除 CalcNotionalByMode, 保证金/融资腿计息基数内联到调用点
...
CalcNotionalByMode 已完成历史使命:
- 融资腿(1/2/9)迁入 FundingLegStrategyFactory
- 保证金(5/6)迁入 MarginModes.Contains 分支
- 死代码(3/4/7/8)已删
调用点(GetInterests:843)现在内联两条路径:
- 保证金: closePrincipal = Fix × closePercent (用 MarginModes.Contains 判断)
- 融资腿: FundingLegStrategyFactory.Get(mode).CalcNotional(...)
删除:
- CalcNotionalByMode 方法(含注释)
- 2个用反射调私有方法的诊断测试(验证的逻辑已被FundingLegStrategyTest覆盖)
验证: 编译0错误, 全量509测试7失败(基线一致)。
2026-08-11 13:13:32 +08:00
hjhan
a610b962a5
docs: InterestModeEnum 补充已删除成员编号注释
...
记录 3/4/7/8 删除前的名称和编号, 防止误回收。
注释里有数字空位标注(3=已删, 4=已删, 7=已删, 8=已删)。
2026-08-11 13:06:36 +08:00
hjhan
47422b9024
feat(margin): MarginAccount 加计息入口 AccrueInterest
...
保证金账户现在具备独立计息能力:
AccrueInterest(rate, start, end, boundary, annualDays)
委托 SwapInterest.AccrueSimple(余额×利率×天数/年化)。
保证金利息是券商对客户保证金存款付息, 方向与融资腿相反。
Margin 模块现在完全独立于 CalcNotionalByMode——
有自己的余额管理 + 计息入口, 不依赖融资腿框架。
测试: 3个计息用例(7天/零余额/释放后减半)。
CalcNotionalByMode 的 mode 5/6 case 仍在(下游路径共用),
待 EOD 归档改走 Margin 路径后再删。
验证: 编译0错误, 全量511测试7失败(基线一致)。
2026-08-11 13:03:38 +08:00
hjhan
e9b54bdcf6
cleanup: 删除死代码枚举 mode 3/4/7/8 及相关引用
...
mode 3(持仓名义本金)/4(持仓市值): 零引用死代码
mode 7/8(多空存续名义本金): 界面已禁用, 无历史数据(用户确认)
删除:
- InterestModeEnum: 移除 持仓名义本金/持仓市值/多头存续名义本金/空头存续名义本金
枚举值保持显式(1/2/5/6/9), DB契约不变
- CalcNotionalByMode: 移除 mode 7/8 的 case
- ConsTrade.InterestModels/InterestNotionalModels: 移除 mode 7/8
- 删除3个 mode 7/8 相关测试方法(场景已不存在)
CalcNotionalByMode 现在只剩 mode 5/6(保证金)的 case,
待 Margin 独立计息入口建成后整体删除。
验证: 编译0错误, 全量508测试7失败(基线一致)。
2026-08-11 13:00:52 +08:00
hjhan
ed7b9102d4
docs: CalcNotionalByMode 补充过渡期注释, 说明保留原因
...
回应命名评审: 确认 FundingLegs 目录无旧文件残留(5个新文件),
旧类名/命名空间零引用。CalcNotionalByMode 有意保留:
- mode 5/6(保证金)待 Margin 独立入口建成后迁出
- mode 7/8(多空存续)界面已禁用, 保留为防御性兜底
待 mode 5/6 迁出后本方法可整体删除。
2026-08-11 12:55:02 +08:00
hjhan
cbe5b58577
refactor: 新增 DirectionRatio 方向因子纯函数, 替换7处三元式
...
多空方向(PositionType==Long?1:-1)和收付方向(xxx==收取?1:-1)
在两个上帝类里重复 15+处, +1/-1 写反是常见 bug 源。
新增 ReturnLegs/DirectionRatio.cs:
- LongShort(positionType): 多头=+1, 空头=-1
- ReceivePay(direction): 收取=+1, 支付=-1
替换:
- SwapEodPositionService: 6处 shortRatio 三元式(含注释1处)
- SwapDealService: 1处 shortRatio + 1处 directionRatio
验证: 编译0错误, 全量511测试7失败(基线一致)。
2026-08-11 12:30:53 +08:00