Commit Graph
204 Commits
Author SHA1 Message Date
锦麟 王 8648b62af9 Merge remote-tracking branch 'origin/glms/feature/1.4.2' into glms/feature/1.4.2-margin 2026-08-24 09:40:03 +08:00
张名锐 392e36a820 feat(bond): 添加公司行为现金分红标识并优化付息计算逻辑
- 在 BondPayment 模型中添加 IsCorporateActionCashDividend 属性用于区分不同数据来源
- 修改 BondPaymentService 中的 CalcPayment 方法,按每条记录来源分别处理金额单位转换
- 更新单元测试以验证混合债券付息和公司行为分红的正确计算
- 移除不再需要的 useBondPriceScale 参数简化方法接口
- 修正注释说明以反映新的按记录类型分别计算的逻辑
2026-08-21 16:51:55 +08:00
锦麟 王 7b1f69a410 #EQD-6948 国联民生-实现保证金规则(2)追保金额的产生与收盘计算 授信和现金tag 2026-08-21 10:33:29 +08:00
张名锐 8efb468c56 Merge branch 'glms/feature/1.4.2' into glms/feature/0812_zmr_divPower 2026-08-21 09:50:12 +08:00
hjhan 640c78b5a9 refactor(swap): EQD-6977 trace可读性第二批:①②与p{id}语义化——承接①→已并复利本金(capitalized)、②→段内已计利息(carryIn),日志/类头注/方法注/测试断言四处同步,运维凭日志即知两承接量含义;SwapDealService×12+SwapEodPositionService×1的p{position.id}统一改融资腿{position.id}(FIX GetFloatRate/Resolve/Segments/EodCloseRefix全系列);测试断言同步更新(此前漏查到一处trace断言已一并改);27/27罚息单测通过,Swap全套644例中仅2例DB依赖失败(干净树复验为既有环境问题) 2026-08-21 08:54:47 +08:00
张名锐 a44960d31e fix(swap): 修复股票基金类互换合约平仓时公司行为处理逻辑
- 优化 FindFundCorporateActions 方法,明确查询范围为严格大于 eodDate 的开区间,并添加日志记录
- 重命名 TryRestoreEffectiveFundPosition 为 TryRestorePositionFromEod 和 TryRestoreAndValidateUnwindData
- 完善 EOD 数据完整性验证,检查持仓数量和价格的有效性
- 添加详细的公司行为查询和应用过程日志记录
- 优化异常信息,包含更多上下文信息如生效日和记录ID
- 更新方法调用引用以使用新的方法名称
2026-08-20 18:22:17 +08:00
张名锐 039415d44c fix(swap): 修复股票基金类互换合约平仓时公司行为处理逻辑
- 优化 FindFundCorporateActions 方法,明确查询范围为严格大于 eodDate 的开区间,并添加日志记录
- 重命名 TryRestoreEffectiveFundPosition
2026-08-20 17:31:02 +08:00
张名锐 f33647c5be fix: 合并后启动修复 2026-08-20 16:38:11 +08:00
张名锐 582cb2c7c5 Merge branch 'glms/feature/1.4.2' into glms/feature/0812_zmr_divPower
# Conflicts:
#	YLErpDAL/Modules/EodModule/BondPaymentService.cs
#	YLErpDAL/Modules/SwapModule/SwapDealService.cs
2026-08-20 16:21:13 +08:00
张名锐 ff7e540084 refactor(swap): 优化基金公司行为处理逻辑 - finished001
- 修改 FindFundCorporateActions 方法以支持查询跨日期范围的公司行为记录
- 实现按生效日期和ID顺序稳定排序的多条公司行为记录处理
- 更新平仓时基金基线恢复逻辑以正确处理跨多个生效日的场景
- 在测试类中重写 FindFundCorporateActions 方法以支持单元测试验证
- 添加完整的跨非交易日公司行为恢复功能测试用例
2026-08-20 16:10:56 +08:00
hjhan 5552402a7c feat(swap): EQD-6977 罚息开关簿记默认值管道——TradeExtendJson.IsPenaltyInterest(存量缺省false零回填) + InitUnwind 平仓页带出簿记值 + GetUnwindInterestList 参数透传 2026-08-20 15:53:11 +08:00
hjhan ffffe842c6 fix(swap): EQD-6977 罚息精确续接落地——承接量改用实际计息状态(preEod基数+事件实结,弃冻结重放)、锚点统一PosiStartDate、罚息并入既有利息流InterestFee(去独立事件/去is_penalty_interest列及DDL/回退closeList与EOD两处守护)、接缝加eventType==平仓守卫、trace逐腿全程落盘、新增多区间不同定盘恒等式测试(旧冻结重放实现必挂) 2026-08-20 15:11:33 +08:00
hjhan 48ae429fb8 refactor(swap): EQD-6977 消除罚息接缝代码臭味道——CalcPenalty 去掉冗余valueDate参数、ComputeCarryBreakdown 去掉未使用position、GetIntradayUnwindInterests 内联块抽为私有AppendPenaltyInterests 2026-08-20 13:37:24 +08:00
张名锐 b2f4e16782 feat(bond): 支持股票和基金现金分红纳入债券支付计算 - 收紧过度开发行为
- 实现股票/基金现金分红数据从 ex_dividend_info 同步到 BondPayment
- 新增公司行为去重机制,避免镜像任务完成后重复计息
- 统一现金分红存储口径为"每 10 份派现金额",保持与同步任务一致性
- 修改 CalcPayment 方法,股票/基金分红需除以 10 转换实际现金金额
- 添加单元测试验证债券票息和股票/基金分红的不同计算方式
- 更新文档注释说明"每 10 份派现金额"存储规范
- 修复公司行为生效日处理逻辑,确保正确应用除权系数
- 扩展测试覆盖股票类证券的公司行为处理场景
2026-08-20 13:30:36 +08:00
hjhan 35a84cd60d feat(swap): EQD-6977 罚息计息接缝——GetIntradayUnwindInterests 按 IsPenaltyInterest 在 GetInterests 返回后追加同构罚息流 2026-08-20 13:23:10 +08:00
hjhan 3777022bac fix(swap): EQD-6977 closeList 排除罚息事件
GetUnwindInterests 的 closeList 查询加 IsPenaltyInterest!=1 过滤,使已落库罚息事件不进去重基数,避免当日二次部分平仓时正常利息被错误抵扣。DDL(stage1 Ver-5.7.0)须随发布。
2026-08-20 12:59:12 +08:00
hjhan 99ca8ebf2c refactor(swap): EQD-6977 罚息标志管道——UnwindData/InterestCalcRequest/GetUnwindInterests 透传 isPenaltyInterest
新增 UnwindData.IsPenaltyInterest(bool);InterestCalcRequest 加 IsPenaltyInterest 字段+私有ctor参数+IntradayUnwind 工厂可选参(default false);GetUnwindInterests 加 isPenaltyInterest 可选参并透传 IntradayUnwind。零行为变化,现有调用方经默认值不受影响,Penalty 套件 11/11 通过。
2026-08-20 12:57:29 +08:00
张名锐 aa3548e77f feat(bond): 支持债券与股票基金公司行为现金流计算的差异化处理 - init2
- 修改 CalcPayment 方法添加 useBondPriceScale 参数区分债券和股票/基金的金额计算口径
- 债券利息按每100元面值票息通过BondPriceConverter转为入库金额,股票基金分红直接计算
- 在BondPaymentService中添加详细的参数说明文档注释
- 更新SwapDealService中分红计算逻辑,根据标的类型自动选择合适的金额转换方式
- 新增CorporateActionEventLifecycleTest单元测试验证公司行为事件生命周期管理
- 添加SplitCorporateActionTddTest测试验证拆合股功能
- 优化FundCorporateActionRollbackAndUnwindTest扩展到股票类型测试
- 更新前端OperationHistory页面表格列宽和显示格式支持更长的说明信息
2026-08-19 17:48:34 +08:00
hjhan 43fb83ed00 refactor(swap): relaxedFixingFromDate 改名 exclusionStart——名实归位
该参数诞生于"有价则取/缺价回退"口径(55363e9f 由 exclusionEndDate 改名而来),
自洽化(fafae5ca)后排除日一概不取价,"放宽取价"语义已不存在——名字回到
排除区间本义,并与 FIX 日志既有用词"排除起点"对齐:
- BuildSegmentRates/CalcDailyCompoundInterest/CalcDailySimpleInterest 三签名
  + 全平重放传参点 + 方法摘要补 exclusionStart 参数语义文档
零行为变更。

验证:内存套件 113/113;全量 981 例 145 败与基线 diff=0
2026-08-19 11:41:18 +08:00
hjhan f8049f81f8 refactor(swap): InitInterestDate 删除死子句 td.StartDate>interestStart + 触发场景注释归因修正
分析定谳:interestStart 经三条赋值路径(=开始日/不算头+1天/preSettleDate 且仅当
≥interestStart 才覆盖)恒 ≥ td.StartDate,第二 OR 子句恒 false——死代码删除。
注释归因同时修正两侧旧错误:
- 原注释把"不算头首日"笼统挂在返回 true 上——实际由第一子句
  interestStart>interestEnd 兜住(StartDate+1>StartDate);
- 候选修正案"观察日当日已结息(preSettleDate 覆盖窗口末)"亦不精确——日期相等
  时函数返回 false,当日已结息的利息归零在 GetInterests closeList 净额层;
  只有相等叠加到期日不算尾回拨(endDate-1)才严格大于而触发。
新增三条 InitInterestDate 直测钉边界:不算头首日空窗/同日已结息日期相等非空/
同日已结息+到期日回拨空窗。

验证:GLMS20260817Fr007UnwindMorningTest 36/36;全量 981 例 145 败与基线 diff=0
2026-08-19 11:36:53 +08:00
hjhan decbd83d0b refactor(swap): 误导布尔 swap 改名 interestWindowEmpty——按"计息窗口为空"本质命名
InitInterestDate 返回 true 的语义是"计息窗口为空→不计利息"(利率与金额归零),
判定只看日期窗口(interestStart>interestEnd)、与事件类型无关;旧名 swap 把
典型原因(互换当日已结息)当成了效果的名字,读者会误读为事件类型判断。
- SwapDealService: GetInterests 局部变量 + GetFloatRate/CalcUnwindInterest/
  InitSwapDealInterest/CalcMarginInterest 四个签名参数及分支/日志/注释同步
- SwapTradeBaseService.InitInterestDate 返回值语义补入 XML 文档
- MarginInterestGoldenReplay/Shadow 测试命名参数同步
零行为变更。

验证:相关套件 51/51;全量 978 例 145 败与基线 diff=0
2026-08-19 11:31:03 +08:00
hjhan fafae5cac0 refactor(swap): EQD-6968 取价口径自洽化——排除日纯跳过+持仓延续重置日显式再定盘
取价规则只由交易属性决定(算不算尾/interest_rule/重置日历),平仓只切窗口:
① BuildSegmentRates 排除日(不算尾尾日)一概不取价(有价也不取)——事件利率恒为
   末段已消费利率,与金额同源、与平仓时刻无关(旧口径下午平仓落库新利率,金额
   却用旧利率,且上午/下午记录不同);金额零变更(排除日本就零消费)。
② GetFloatRate 不算尾重置日不再先试取尾日定盘(原'有价则取'分支删除)。
③ 剩余持仓的新周期利率改由 SwapEodPositionService 显式获取:平仓日恰为重置日
   且剩余>0 时,快照 FloatRate 经 ResolveOngoingResetFixing 再定盘为当日新定盘
   (生产 GetFixingOrThrow,缺价抛——与 ByEod 重置日/EodCheckSettlePrice 同口径;
   原'有价则取'顺带承担此载体职责,现显式分离)。全平/算尾/观察日无需再定盘。
④ 无日终快照播种 priorValueDate 恒=开始日-1:首重置日(=开始日)的定盘覆盖
   [开始日,下一重置日)全部计息日(不算头时 7/7 起仍属首段),必须落在取价窗内。
   原仅算头回拨一天,不算头时首段误用种子利率(靠②的尾日取价回填掩盖,现已根治)。
   '不算头少计一天'仍由计息边界 IncludeStart=false 承担,天数不变、利率归位。
FIX 日志同步:排除日不取价/EodCloseRefix 再定盘 全程可审计。

验证:全量 976 例 145 败与改动前基线失败名单 diff=0;内存套件(含
ContractReferenceOracle 金标准/InterestEodTailSnapshot)全绿
2026-08-19 11:06:52 +08:00
hjhan 1e6abb4547 refactor(swap): 重置日判定收口 IsResetDay 私有谓词(零行为变更)
EQD-6968 三判定之一的"是否重置日"公式原在 GetFloatRate(days%period) 与
CalcUnwindInterest 当日归周期判定(daysFromStart%rest_days) 各写一遍,
收口为单一谓词;锚点差异(td.StartDate vs position.PosiStartDate,
非初始持仓两锚点可能不同)在注释中显式注记,只收口公式不统一锚点——
统一锚点属行为变更需业务定调。

验证:内存套件 102/102 全绿
2026-08-19 09:33:15 +08:00
hjhan 0418d9f3d3 refactor(swap): InterestCalcMode 算头算尾解析收口至 TradeExtendJson.CalcFirst/CalcLast
三处重复的 StartsWith/EndsWith 字符串解析(GetInterests / InitInterestDate /
SwapEodPositionService EOD平仓后结息)收口为 TradeExtendJson 计算属性:
- [JsonIgnore] 保证 ExtendJson 序列化字节不变;
- InitInterestDate 原写法在 InterestCalcMode 为显式 null 时会 NRE,
  收口后与其他两处 null-安全语义对齐(缺省=算头算尾,实际不可达,属性缺省 11)。
EQD-6968 三判定之一的"算不算尾"至此单点可查。

验证:内存套件 102/102 全绿(GLMS20260817Fr007 23 + Cache 7 + CloseInterest/
InterestScenario/TailSnapshot/EntrySemantics 72)
2026-08-19 09:31:38 +08:00
张名锐 aa1a13d7a3 feat(trade): 新增真实除权日字段并完善基金公司行为处理 init
- 添加 EffectiveDate 字段用于标识真实除权生效日
- 实现公司行为价格系数和数量系数统一计算方法
- 增加基金除权回退和平仓基线恢复功能
- 完善除权日验证逻辑,确保真实除权日不早于股权登记日
- 重构平仓流程,支持按有效EOD基线重新计算损益和现金
- 添加基金拆合股和现金分红的特殊处理逻辑
- 增加单元测试验证各种公司行为场景下的正确性
2026-08-18 11:20:56 +08:00
hjhanandClaude Opus 4.7 cb5ba86d85 EQD-6968: 不算尾缺价改沿用已有利率(删期初回退) + 取价决策FIX常驻日志
① GetFloatRate 不算尾缺价不再回退取期初定盘,改沿用已有利率
   (preEod.FloatRate/position.FloatRate)——其返回值仅作 preEod.id==0 的种子
   且会被分段首段强制取价覆盖,期初取价是无消费者的多余DB读且语义误导;
② BuildSegmentRates 等价重排为 if/else-if 结构,注释改"跳过取价/沿用"准确措辞
   (行为不变:排除日有价仍取新利率,缺价沿用上一重置日利率);
③ 防历史bug"取错重置日利率"复发:GetFloatRate/ResolveFloatRate/BuildSegmentRates
   三处取价决策经 SwapCalcTrace.Critical 常驻 Info 落盘——重置日判定、取价日
   (interest_rule回拨)、命中/缺失、不算尾缺价沿用来源、排除日跳过全程可审计;
④ 测试真内存化:Stub 补 GetConsumedInterest=>0 override(复利路径原偷连96库,
   与类注释"内存,不连库"矛盾);一致性断言措辞对齐新语义;
⑤ 修复 SwapDealService.cs 文件头双 BOM 损坏。

验证:GLMS20260817Fr007UnwindMorningTest 12/12 内存全绿;
邻近套件 67过/15败与改动前基线完全一致(15败均为沙箱无96库 Connect Timeout)。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-17 22:21:55 +08:00
hjhan b94cce68ee chore(cleanup): 删除裁决文档与 saga 注释——保留技术事实,剥离过程叙事(零逻辑改动)
删除 项目文档/双入口口径裁决-复利mode2部分平仓-20260816.md:
四轮状态改写的过程文档,终态有价值的技术事实已转移到代码注释与测试锚点。

保留的技术事实(新家):
- SwapEodPositionService:1325:恒1重算中间值不进结算现金流;系统端到端结果由
  DI_EXCEL_SCENARIO4 家族对账确认书公式保障(最终全平=剩余额×∏利率,2026-08-18
  手算复核);改动口径前必读该测试家族——破坏 ∏ 恒等式的调整会被其拦截
- ContractReferenceOracleTest:13:Excel 金标准期望值亦符合确认书公式(复核记录)
- EntrySemanticsTest 手算锚点 0.036165 保留(公式自含,去文档引用)

清理的 saga 痕迹:契约修复/裁决文档/暂缓/证伪 等过程性话语全部移除,
测试方法名与注释改为中性事实描述;[EOD平仓后收盘结息] 日志文案
'恒1全额结息(历史行为,契约修复暂缓)'→'全额结息(恒1惯例)'。

验证:编译 0 错误;EntrySemantics+Oracle 16/16 绿;全量 928=145/771/12
与基线逐位一致——纯注释/文档/日志文案改动,零逻辑变更。
2026-08-17 13:30:10 +08:00
hjhan 55363e9f51 EQD-6968: 重命名 FR007 不计尾放宽取率参数为准确语义命名,提升可读性
纯改名与化简:BuildSegmentRates 的 includeEnd 别名->calcLast、exclusionEndDate->relaxedFixingFromDate(语义=从该日起放宽定盘缺失拦截而非排除某日);GetFloatRate 不算尾回退改正向结构;GetInterests 抽出 effectiveCalcLast 替代重复 calcLast||newCalcLast。计息逻辑不变,12 用例内存单测全绿。
2026-08-17 13:00:08 +08:00
hjhan bc401bd687 EQD-6968: 不算尾计息不再因平仓日FR007未发布误拦平仓(缺价回退上一重置日利率,有价仍取新利率) 2026-08-17 11:22:37 +08:00
hjhan 9efaa1b5cc chore(swap)+test: 删分红EOD历史死代码 + 补计算过程常驻日志(零行为语义变更);契约修复转为暂缓
死代码删除(SwapEodPositionService.UpdateEodPosition,论证+实证链完整):
- todayConsumedDividend/originNotional/totalPayment/totalInterest 自 0910969e(7/2 改递推式)
  起计算结果从未被消费,仅残留全历史 CalcBondPayment 只读查询+日志副作用,且构成
  脏数据(OriginalStockEqvNotional=null/PosiNetPrice=0)下 EOD 崩溃点(除零,实测复现)
- 配套边界测试 DividendEodNoDoubleCountTest.脏数据边界_*:删除前红(崩溃)→删除后绿
  (不抛异常+四输出字段与正常数据逐字段一致);stash 基线对比确认离线套件无其他差异
- 止血预案:git revert 本提交即回到已验证态

计算过程常驻日志(快速定位,纯增):
- [EOD平仓后收盘结息]:口径/autoSwap/平仓前/剩余/平掉额——排障第一入口
- [分红-EOD计提Copy/Update]:窗口/qty/税率/当日新计/账面前值→后值——与
  [分红-登记日口径]窗口命中日志构成分红计算全链
- [利息-全平专属分支]:全平分支触发标记,兼作契约修复落地后的验证哨兵

契约修复(EOD传真实比例)转为暂缓:影响快照种子,黄金回放验收门因96库网络未恢复
无法执行,按风险优先级撤回行为变更;方案+回归网(同形状等价oracle)+落地哨兵已
全部就绪并留档于裁决文档,DB恢复后可直接落地。
2026-08-16 15:47:09 +08:00
hjhanandClaude 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 f2c2f6052c refactor(swap): 提取 SwapPositionQueries.ActiveByTrade 收口有效持仓查询
- 新增 SwapPositionQueries.ActiveByTrade 静态扩展,收口 'SwapTradeId==X && !Invalid' 规则到单一真相
- 替换 SwapDealService/SwapEodPositionService/SwapTradeService 共 7 处纯重复谓词
- 仅返回 IQueryable,不调 SaveChanges,不动 FindTrade seam / 事务边界;行为保持等价
2026-08-15 12:48:44 +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 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 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 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 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 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 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 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 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