Commit Graph
180 Commits
Author SHA1 Message Date
张名锐 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
张名锐 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
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
张名锐 b2f4e16782 feat(bond): 支持股票和基金现金分红纳入债券支付计算 - 收紧过度开发行为
- 实现股票/基金现金分红数据从 ex_dividend_info 同步到 BondPayment
- 新增公司行为去重机制,避免镜像任务完成后重复计息
- 统一现金分红存储口径为"每 10 份派现金额",保持与同步任务一致性
- 修改 CalcPayment 方法,股票/基金分红需除以 10 转换实际现金金额
- 添加单元测试验证债券票息和股票/基金分红的不同计算方式
- 更新文档注释说明"每 10 份派现金额"存储规范
- 修复公司行为生效日处理逻辑,确保正确应用除权系数
- 扩展测试覆盖股票类证券的公司行为处理场景
2026-08-20 13:30:36 +08:00
hjhan 10a12b7eef fix(swap): EQD-6977 EOD 手动结息守护排除罚息
SaveAutoEodWithCloseInterestPosition 的 manualSettledInterestAmount 求和加 Where(IsPenaltyInterest!=1),防 auto-swap 重算相减时丢失罚息(评审8.1双守护之防御层)。
2026-08-20 12:59:13 +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 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 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
张名锐 ddf233678d feat(swap): 添加基金现金分红处理功能
- 实现 ApplyFundCashDividends 方法处理基金现金分红逻辑
- 现金分红在生效日 EOD 即执行,计入已实现分红字段
- 从盯市盈亏中分离分红金额,避免收益重复计算
- 更新测试用例验证现金分红正确记入已实现分红
- 修正测试方法名称反映实际功能变更
- 完善单元测试验证分红金额计算准确性
2026-08-18 15:43:11 +08:00
张名锐 aa1a13d7a3 feat(trade): 新增真实除权日字段并完善基金公司行为处理 init
- 添加 EffectiveDate 字段用于标识真实除权生效日
- 实现公司行为价格系数和数量系数统一计算方法
- 增加基金除权回退和平仓基线恢复功能
- 完善除权日验证逻辑,确保真实除权日不早于股权登记日
- 重构平仓流程,支持按有效EOD基线重新计算损益和现金
- 添加基金拆合股和现金分红的特殊处理逻辑
- 增加单元测试验证各种公司行为场景下的正确性
2026-08-18 11:20:56 +08:00
hjhan 09fa96a93f refactor(swap-eod): L1 类内去重——CopyInterestLegFields/FinalizeInterestEodRoll 收口四 Save* 重复段(行为保真)
- 腿字段拷贝 3 处×14 行 → 入参化 helper(FloatRate 来源随场景传入,勿统一)
- 滚存收尾 4 处 → FinalizeInterestEodRoll(方向源参数化:三处 position、Copy 一处 eodPayPosition,勿统一;Persist 与日志留调用点保持原序)
- 差异保真:WithClose 不设 InterestFeePending;勿缩放注释保留升级
- 安全网:InterestEodTailSnapshotTest 三格尾部快照(AutoSettle/AutoSettleWithClose/CloseOnly,钉值特征化)+ golden 两格 + DI_EXCEL 家族
- 验证:快照 3/3 逐字段一致;全量 SwapModule 576/566/10/0 与去重前基线完全相同
- 注:本提交为工作区被还原后按原编辑重放,验证结果与首次执行一致
2026-08-17 18:15:09 +08:00
hjhan 9ae2e66b75 refactor(swap-eod): L0 纯函数出仓——InterestEodScenario/ResolveInterestScenario/FindObservationInterval 移至独立 InterestEodScenarioDispatch(零行为变更)
- 上帝类减重 42 行;枚举与两个纯函数零实例状态、零 DB 依赖,符合 Accrual/ 既有纯函数迁移模式
- 测试不再继承 TestableSwapEodPositionService(原仅为够到 protected),plain 测试类
- SwapEodPositionService 两处调用点改为 InterestEodScenarioDispatch.FindObservationInterval 限定名
- 编译 0 错误;表驱动 8/8 通过
2026-08-17 17:36:41 +08:00
hjhan ec9c493420 refactor(swap-eod): 利息腿分派可读性收口——观察日命名统一+命名参数+查找助手+分派规格纯函数(零行为变更)
- insterval/autoInterval → observationInterval,SwapIntervalList→FindObservationInterval→形参 interval 全链同名
- :512/:525 调用点命名参数 autoSwap: true/false,签名未动
- 抽取 FindObservationInterval 消除两处重复观察日谓词(表达式逐字保留,null 语义不变)
- 新增 InterestEodScenario 枚举 + ResolveInterestScenario 影子纯函数 + 8 组合表驱动 InterestEodScenarioDispatchTest(分派结构未接线,生产执行路径不变)
- 编译 0 错误;表驱动 8/8 通过
2026-08-17 16:25:08 +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 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
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 1d9bac4dd6 refactor(swap): 提取 EodSwapPositionQueries.ActiveByTradeAndDate 收口日终有效持仓查询
将 eod_swap_position 上'SwapTradeId + ValueDate + !Invalid'的 5 处重复谓词
(SwapEodPositionService.cs:2133/2195/2246/2487、ConfirmationGenerateContext.cs:2868)
收口到 EodSwapPositionQueries.ActiveByTradeAndDate(tradeId, valueDate),
与 SwapPositionQueries.ActiveByTrade 同构,零逻辑变更。
2026-08-15 13:44:53 +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 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 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 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 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
张名锐 304e04d60a Merge remote-tracking branch 'origin/glms/feature/1.4.2' into glms/feature/1.4.2 2026-08-12 15:10:06 +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
张名锐 2035e1df4c fix(swap): 修复EOD平仓后收盘时结息本金计算错误
- 修正SwapDealService.GetInterests方法中平仓后结息本金语义错位问题
- 区分EOD平仓后收盘与盘中平仓前本金传参的不同语义
- 针对模式2合约名义本金规模强制覆盖为实际平仓额
- 保持模式9标的期初全价在全平时的零值处理逻辑
- 添加债券份额调整公司行动支持和记录日期资格判断
- 实现EOD仓位复制和更新时的公司行动应用逻辑
2026-08-12 14:40:03 +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 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 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
hjhan c52d439469 refactor(return-leg): 4处增值税inline公式替换为 DividendCalc
SwapEodPositionService 4处 payment/(1+tax)*(1-tax) inline 替换:
- 1804/1906/2094: Math.Round(...) → DividendCalc.AfterTax(payment, tax)
- 1893: 中间计算(不四舍五入) → DividendCalc.AfterTaxRaw(total, tax)

修复 MtmCalcTest: UnrealizedPnl 第6参数 ratio 从 1m 改为 1(int)。
(1+tax) inline 公式出现次数: 4 → 0。

验证: 编译0错误, 全量507测试7失败(基线一致)。
2026-08-11 11:12:15 +08:00
hjhan 939d6a4271 fix(return-leg): MtmCalc.UnrealizedPnl ratio 参数改为 int
ratio(收取=1/支付=-1)和 shortRatio 一样是 int, 不是 decimal。
1695行 ratio 声明同步从 decimal 改为 int。
C# decimal*int 自动提升为 decimal, 不影响计算结果。

验证: 编译0错误, 全量507测试7失败(基线一致)。
2026-08-11 11:05:55 +08:00
hjhan 963f7a04e5 refactor(return-leg): 新增 DividendCalc 分红增值税后计算 + 修复 MtmCalc 参数类型
DividendCalc: 增值税后票息 = payment/(1+tax)*(1-tax),
原 SwapEodPositionService 4处重复此公式(1804/1894/1906/2095)。
本次先建纯函数+测试, 4处inline替换下次做。

附带修复: MtmCalc shortRatio 参数从 decimal 改为 int
(原代码6处声明中5处是int, 仅1696是decimal, 统一为int)。
1696行 shortRatio 声明同步改为 int。

验证: 编译0错误, DividendCalc 4个测试全过,
全量507测试7失败(基线一致)。
2026-08-11 11:04:08 +08:00
hjhan a26f848287 refactor(return-leg): 抽取 MtmCalc 标的端盯市计算
把 SwapEodPositionService 4处重复的 UnderlyingMarketValue 公式和
4处 PosiMtmPnL 公式抽成 MtmCalc 纯函数:
- MarketValue(price, qty, contractSize, shortRatio): 标的市值
- UnrealizedPnl(price, costGrossPrice, qty, contractSize, shortRatio, ratio): 盯市未实现盈亏

原代码4处副本(1731/1813/1898/2101 + 1741/1814/1899/2102)全部替换。
验证: 编译0错误, 全量503测试7失败(基线一致)。
2026-08-11 10:45:43 +08:00
hjhan 59651b802e refactor(return-leg): QuantityRollforward 改名 QtyRollforward
代码里统一用 Qty 表示数量, 命名更简洁。
文件/类/测试类同步改名: Quantity→Qty。
2026-08-11 10:40:17 +08:00
hjhan 279c640345 refactor(return-leg): 抽取 QuantityRollforward 标的端数量递推
把 SwapEodPositionService:1980 inline 的数量递推公式抽成独立纯函数:
  qty = 上一日终数量 + 开仓 - 平仓 + 公司行为调整

新增第4参数 corpActionDeltaQty(默认0,当前不影响行为),
预留给公司行为改造(送股/拆股/配股)。
原代码硬编码'数量只因交易变动'假设,改造时填入非零值即可。

ReturnLegs/QuantityRollforward.cs: 纯函数, 不依赖任何实例状态
ReturnLegs 测试: 8个(无交易/开仓/平仓/全平/超额/送股/拆股)
SwapEodPositionService: inline 2行 → QuantityRollforward.Calc() 1行

验证: 编译0错误, 全量497测试7失败(基线一致)。
2026-08-11 10:36:38 +08:00
hjhan 22f22bc9c5 refactor(margin): ConsTrade.InterestMarginModels 4处引用收敛到 MarginModes
上次失败根因: EodClientBalanceCalc:134 是 EF Core LINQ 表达式,
HashSet.Contains 无法翻译成 SQL, 导致场景3/4 全红。

修正: MarginModes 新增 ForLinq(List<int>) 供 EF Core 翻译用。
- SwapEodPositionService 2处纯函数(非LINQ): 用 MarginModes.Contains
- EodClientBalanceCalc LINQ表达式: 用 MarginModes.ForLinq.Contains
- RealTimeClientBanlanceService(已ToList,内存集合): 用 MarginModes.Contains

ConsTrade.InterestMarginModels 产品代码引用: 4处 → 0(只剩定义+注释)。
保证金mode判断 {初始预付金,追加预付金} 现在统一由 MarginModes 提供。

验证: sln编译0错误, 全量485测试7失败(基线一致,零回归)。
2026-08-11 09:57:20 +08:00
hjhan ef1a126b8f refactor(margin): 4处散落marginTypes收敛到MarginModes
SwapEodPositionService: 删除 marginTypes 字段(13处.Contains全改MarginModes.Contains)
SwapEventEmailService: marginTypes 字段改为 MarginModes.All.ToList()
EodClientBalanceCalc: 删除未使用的 marginTypes 局部变量(死代码)
ClientBalanceUtility: 删除未使用的 marginTypes 局部变量(死代码)

收敛后 {初始预付金,追加预付金} 集合只在 MarginModes.All 一处定义,
消除6处副本口径分裂风险。

验证: sln编译0错误, 全量485测试7失败(基线一致,零回归)。
注: 上次27失败是stash残留导致的状态不一致,本次从干净状态逐步改。
2026-08-11 09:40:48 +08:00
张名锐 8fdf2417f4 fix(swap): 修复日终持仓风险_互换 利息金额方向处理逻辑 2026-08-10 17:59:30 +08:00
张名锐 2c4cd56111 feat(swap): 添加收益互换利息计算功能及Excel场景测试
- 新增ExecuteSaveEodInterestPositionCopy方法用于保存日终利息持仓副本
- 添加ExcelScenario4Case类和相关测试数据用于验证利息计算准确性
- 实现DI_EXCEL_SCENARIO4_PartialCloseAndFinalCloseMatchBlAndBn测试方法
- 优化SwapDealService中的利息计算逻辑和平仓处理
- 添加详细的注释说明利息计算的核心业务规则
- 完善SwapEodPositionService中的日终持仓处理逻辑
- 修复部分平仓和最终平仓时的利息金额计算问题
2026-08-09 22:07:19 +08:00
张名锐 48e8447925 fix(swap): 修复复利重置日部分平仓后本金计算逻辑
- 修复复利重置日部分平仓后当日利息计算,使用已结转待实现利息的剩余复利本金
- 修复算尾部分平仓后EOD保留剩余复利本金的逻辑,按计息模式返回口径处理
- 修复模式2和模式9在部分平仓时的本金计算差异,避免重复比例调整
- 修复不算尾情况下重置日后已并入本金的待实现利息遗漏问题
- 新增对话案例回归测试验证部分平仓后最终全平场景的正确性
- 添加多种计息模式和交易类型的回归测试用例
2026-08-09 16:06:09 +08:00
张名锐 7528670e8b fix(swap): 修复部分平仓后算尾利息计算问题(算头算尾T+0合约单利)
- 将测试方法改为数据驱动测试以覆盖不同利息模式
- 在测试中添加对不同利息模式的验证逻辑
- 修复平仓后EOD本金只携带剩余持仓的计算逻辑
- 添加对算尾部分平仓后EOD本金的断言验证
- 优化单利算尾当日按平仓前全额计提的处理逻辑
2026-08-09 13:42:59 +08:00
张名锐 691054c57e fix(swap): 修复部分平仓后跨日复利本金计算逻辑(算头算尾T+1复利合约)
- 修复了5/11 EOD跨日复利本金应保留剩余70%动态本金的计算
- 调整了calcLast=true时已平部分动态本金的处理逻辑
- 修正了部分平仓后剩余仓位跨日携带的本金缩放算法
- 添加了针对不同计算路径的本金比例调整机制
2026-08-08 18:09:31 +08:00