Commit Graph
131 Commits
Author SHA1 Message Date
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 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 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 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 e35a738d2e refactor(funding-leg): 修复2个类名+补DividendCalc注释
采纳命名审查建议(优先级最高的2项):

1. UnderlyingFullPriceLeg → UnderlyingEntryFullPriceLeg
   补齐'期初(Entry)'——建仓时点全价, 非当前全价, 金融上是不同计息口径

2. FixedNotionalLeg → FixedAmountLeg
   去掉误导性的Notional——'固定值'是合同写死的数额, 不一定是名义本金,
   避免与ContractNotionalLeg的Notional概念撞车

3. DividendCalc 补充注释: 业务含义(债券票息+股票分红统一用Dividend)、
   税务口径(还原不含税再扣税)、命名保持理由

验证: 编译0错误, 全量507测试7失败(基线一致)。
2026-08-11 11:24:05 +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 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 946cbbb66d refactor: InterestLeg 改名 FundingLeg(业界标准 Financing Leg)
命名: InterestLeg→FundingLeg, 消除'interest'与通用'利息'歧义。
Funding精确表达'融资成本'(客户付券商的杠杆成本 spread+FR007)。

改名清单:
- IInterestLegStrategy → IFundingLegStrategy
- InterestLegStrategyFactory → FundingLegStrategyFactory
- InterestLegStrategyTest → FundingLegStrategyTest
- 命名空间 InterestLegs → FundingLegs
- 目录 InterestLegs/ → FundingLegs/
- SwapDealService 引用同步更新

验证: 编译0错误, 全量503测试7失败(基线一致)。
2026-08-11 10:52:04 +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 e73272042a refactor(return-leg): 新增 ReturnLegSummary 标的端值对象
标的端(Total Return Leg)归档产出的汇总值: 多空名义本金/平仓名义本金/含费全价。
对应原 SwapPositionCompose 里 DealFloatPositions 传给 DealInterests 的4个标量。

命名说明(防歧义):
- 用 ReturnLeg(业界标准 Total Return Leg), 不用 FloatLeg
- 'float'在金融里首要含义是'浮动利率'(如FR007), 用于标的端会产生歧义
- 标的端 = 标的资产的总回报(价格涨跌+票息分红), 与浮动利率无关

纯新增骨架, 零生产改动。
验证: 编译0错误, 3个单测全过, 全量489测试7失败(基线一致)。
2026-08-11 10:15:20 +08:00
hjhan b7469be104 refactor(margin): 保证金去除'计息基数'错误概念, 改用余额建模
保证金就是保证金——有余额、有利率、有利息, 不存在'计息基数/Notional'概念。
现有代码把保证金塞进 InterestPrincipalFix 当计息腿处理是错误建模。

修正:
- 删除 MarginLeg.cs(CalcBalance/accrualFactor 是融资腿的概念, 不该用在保证金)
- 新增 MarginAccount.cs: 管理余额变动(Deposit追加/Withdraw释放), 不含计息
- MarginBalance: 注释去掉'计息基数', 改为'保证金余额'
- IMarginResolver.Resolve: 去掉 accrualFactor 参数(融资腿比例, 非保证金概念)
- CashMargin/CreditMargin/GuaranteeMargin: 同步去掉 accrualFactor
- 枚举注释: '计息余额' → '余额'

保证金利息由 SwapInterest 纯函数按 余额×利率×天数/年化 计算,
MarginAccount 只提供余额, 不掺计息逻辑。

验证: sln编译0错误, 全量486测试7失败(基线一致,零回归)。
2026-08-11 10:06:27 +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 553e3d4c6d refactor(margin): 新增 MarginModes 统一保证金mode判断口径
现状: 同一集合{初始预付金,追加预付金}在代码里复制了至少6次
(ConsTrade.InterestMarginModels + 5处局部marginTypes/premiumModes)。
任何一处漏改(如新增保证金形态)都会导致口径分裂。

本次: Margin 模块新增 MarginModes 静态类, 作为单一判断来源。
- IReadOnlyCollection<int> All: 保证金mode集合
- bool Contains(int): 判断mode是否属于保证金
后续逐个替换散落的marginTypes/premiumModes/InterestMarginModels。

纯新增, 零生产代码改动。
验证: 5个单测全过, 全量485测试7失败(基线一致)。
2026-08-11 09:27:25 +08:00
hjhan 55284fb76b refactor(margin): 抽出独立 Margin 限界上下文,移除 PrepayLeg 错误继承
- 新建 YLErp.Modules.SwapModule.Margin:MarginBalance / MarginLeg / IMarginResolver(Cash/Credit/Guarantee)

- MarginLeg 不继承 IInterestLegStrategy,与利息腿完全解耦(保证金是客户存款/担保,非互换腿)

- 删除 PrepayLeg,工厂不再注册 mode 5/6 预付金

- 预付金用例迁入 MarginLegTest,旧 InterestLegStrategyTest 改为断言预付金已非利息腿
2026-08-10 22:09:09 +08:00
hjhan aca834d8dc refactor(interest): 新增预付金腿策略 + 策略工厂
新增(零生产改动):
- InterestLegs/PrepayLeg.cs
  mode 5 初始预付金 / mode 6 追加预付金 共用。
  计息基数=InterestPrincipalFix, 平仓本金=Fix×closePercent。
  构造时校验mode合法性(只接受5/6)。
  方向翻转/orginPv重映射等独有逻辑后续单独抽。

- InterestLegs/InterestLegStrategyFactory.cs
  按InterestMode返回对应策略, 收敛switch分发。
  死代码mode 3/4/7/8不注册, 传入会抛ArgumentException。

测试(14个全过):
- 预付金: 部分平仓/全平/非法mode构造
- 工厂: 各活跃mode返回正确类型/未注册mode抛异常/int重载等价

fixing接入尝试(已回退):
- 尝试用Fr007IndexFixer.Instance替换SwapDealService的6处取价
- 发现问题: 静态Instance绕过TryGetFloatRate(virtual)接缝,
  破坏测试stub机制(CI_007/CI_008失败)
- 已回退, 下次改用实例级IIndexFixer(委托TryGetFloatRate)方式接入
2026-08-10 18:40:04 +08:00
hjhan 79e9304114 refactor(interest): 新增利息腿策略接口 + 3个活跃mode实现
为拆三类腿做准备,按 Strategy 模式封装 CalcNotionalByMode 的 switch。
本次零生产代码改动,全部为新增小文件,每个类单一职责<50行。

新增(策略接口+值对象):
- InterestLegs/IInterestLegStrategy.cs
  NotionalResult 值对象(closePrincipal/posiPrincipal/closePercent)
  + IInterestLegStrategy 接口(每个mode一个实现)

新增(3个活跃利息腿mode):
- InterestLegs/FixedNotionalLeg.cs        mode 1 固定值
  计息基数恒=InterestPrincipalFix, 不随平仓比例变化(合同写死的固定值)
- InterestLegs/ContractNotionalLeg.cs     mode 2 合约名义本金规模
  平仓本金=posiNotional×closePercent, 按比例线性缩放
- InterestLegs/UnderlyingFullPriceLeg.cs  mode 9 标的期初全价
  主路径公式同mode2, 差异在衡泰路径grossPrice折算+EOD复利反推

确认现状:
- 界面实际只有3个活跃利息腿mode(1/2/9), TradeView.cshtml:330-349
- mode 3(持仓名义本金)/4(持仓市值) 零引用=死代码, 本次不实现
- mode 7/8(多空存续) 界面已注释掉, 本次不实现
- mode 5/6(预付金) 属保证金维度, 后续单独做PrepayLeg

新增测试(8个,全过):
- InterestLegStrategyTest.cs 覆盖各mode的部分平仓/全平/零平仓场景
  验证策略行为与现有CalcNotionalByMode switch完全一致
2026-08-10 18:32:17 +08:00
hjhan 250c41b925 refactor(interest): 抽取 IIndexFixer 取价接缝 + 清理固定值腿错误测试
为后续拆三类腿做准备,新增 FR007 取价的独立接口层(参考 QuantLib IborIndex
分层),本次零生产代码改动,全部为新增小文件。

新增文件(取价接缝,供后续 SwapDealService 6 处 inline 取价迁移用):
- Framework/YLErp.Core/Interest/IIndexFixer.cs
  接口定义:给定取价日和标的代码返回当日利率,取价与计息解耦
- Framework/YLErp.Core/Interest/IndexFixerBase.cs
  取价日计算工具:收敛原散落 6 处的 GetNonHolidayDefore(date.AddDays(rule))
- YLErpDAL/Modules/SwapModule/Fr007IndexFixer.cs
  生产实现 + GetFixingOrThrow 辅助方法,独立文件便于单测

测试清理(删除基于错误假设的测试):
- 删除 SwapFixedInterestLegClosePercentBugTest.cs 整个文件
  该文件假设'固定值腿利息应随平仓比例线性缩放',但固定值是合同写死的、
  永远不随平仓比例变化。d1badfe4 的'修复'本身才是错的,当前分支已正确回退
- 修正 SwapUnwindPrepayPrincipalBugTdd.cs 固定值测试方法
  断言从'应=Fix×0.5'改为'恒=Fix不随比例变化',对齐正确的业务定义

已知失败(非本次引入,留待后续与拆腿一起修):
- BondTrsAutoSwapScenarioTest 的 AS_001/004/008/009/010/011 共 6 个
  原因:SaveAutoSwapDeal 直接调 AddClientCashInCashOut(非virtual)绕过
  AddClientCash(virtual)封装,无库环境抛'客户信息未找到'。
  从 096d2609 引入时即失败,需 AddClientCashInCashOut 加 virtual + 客户数据
  mock,与拆腿那次可测性改造一起做
2026-08-10 18:01:37 +08:00
张名锐 adb1b90c03 fix(swap): 修复预付本金部分平仓后的剩余本金计算
- 修改InterestPrincipalFix字段从PrepayFix调整为PrepayRemaining
- 添加注释说明GetUnwindInterests方法会用实时腿覆盖初始腿本金
- 确保部分平仓后剩余60%本金的正确计算逻辑
2026-08-10 13:17:12 +08:00
张名锐 7e6c4856e6 refactor(swap): 移除测试类中的空方法实现
- 删除 BondTrsAutoSwapScenarioTest 中的空 UpdateInitalPostion 方法
- 删除 BondTrsAutoSwapScenarioTest 中的空 PersistFlowEvent 方法
- 将 TestableSwapEodPositionService 中的 PersistFlowEvent 方法改为非虚方法实现
- 保留 FlowEvents 集合用于收集流事件以便利息计算测试
2026-08-10 11:08:46 +08:00
张名锐 54445c1e38 Merge remote-tracking branch 'origin/glms/feature/zmr-0808' into glms/feature/1.4.2
# Conflicts:
#	YLErpDAL/Modules/SwapModule/SwapDealService.cs
#	YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
2026-08-10 10:56:34 +08:00
张名锐 2ee38384ac fix(swap): 修复预付金腿计息基数计算问题
- 在多个单元测试文件中添加InterestIncomeSum字段以保持数据一致性
- 修改GLMS20260105PartialCloseDividendBugTest测试,改进EOD快照验证逻辑
- 修复SwapDealService中预付金腿的orginPv计算逻辑,使用上一日保证金本金作为基准
- 更新SwapPositionComposeScenarioTest中的测试数据结构和利率设置
- 修正平仓日利息计算精度问题,使用Math.Round确保计算准确性
2026-08-09 22:28:40 +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
hjhan 4916f7207d test(refactor): SwapInterestScenario3And4 诚实化——去掉 return 0m, 从交易开始日逐日真实收盘
- 删除 StubSwapDealService.GetConsumedInterest 的  硬编码(此前注释明写"与生产缺陷态一致",
  等于把唯一会出错的机制整个屏蔽, 断言缺陷态输出, 伪绿)。
- 改为复用生产同一口径: 对真实收盘经 PersistFlowEvent 累积的 swap_flow_event
  (EventType∈{互换,自动互换}, DataState=完成, EventDate<结算日) 求和 —— 数据来自真实代码执行, 非硬编码。
- TestableSwapEodPositionService 新增 FlowEvents 捕获 + override PersistFlowEvent, 供 GetConsumedInterest 真实计算(不连库)。
- 新增 E2EEodService: 从交易开始日(TradeDate)逐日驱动真实 SwapPositionCompose 构建 eod 链,
  再把真实 eod 快照喂给平仓; 平仓走生产同一入口 SaveAutoEodWithCloseInterestPosition。
- 全程无硬编码输入: FR007 曲线/名义本金/日期均来自 Excel 场景真源, 计算全走真实代码。
- 验证: 24/24 通过(SKIP_INITIALIZATION); PrepaidPrincipal 追踪测试 2/2 通过; 基类改动无回归。
- 注: ConsumedInterestScenarioTest.CI_008 既有失败(复利重置日本金继承, 与本回合无关, 未触碰该文件), 另议。
2026-08-09 11:22:42 +08:00
张名锐 691054c57e fix(swap): 修复部分平仓后跨日复利本金计算逻辑(算头算尾T+1复利合约)
- 修复了5/11 EOD跨日复利本金应保留剩余70%动态本金的计算
- 调整了calcLast=true时已平部分动态本金的处理逻辑
- 修正了部分平仓后剩余仓位跨日携带的本金缩放算法
- 添加了针对不同计算路径的本金比例调整机制
2026-08-08 18:09:31 +08:00
张名锐 d3afa6d27c fix(swap): 修复部分平仓后复利本金计算逻辑(修复T+1)
- 修复部分平仓后下一日复利本金未按剩余比例继承的问题
- 添加对最终日不算尾时历史差分重放的日期边界控制
- 修复算头不算尾快速路径中已平部分进入下一日复利的错误
- 确保重置日动态本金不会被二次缩放导致剩余本金计算错误
- 添加单元测试验证部分平仓后复利本金按剩余70%本金计提的逻辑
- 补充最终全平重放时历史终点包含当日利息后再做差额的测试用例
2026-08-08 17:10:29 +08:00
张名锐 aa5a5ed879 fix(swap): 修复复利计算中部分平仓场景下的利息处理逻辑(算头不算尾期初复利)
- 修改单元测试为数据驱动测试,支持多种利息模式验证
- 更新复利计算注释,明确最终日重放时的calcLast规则
- 扩展复利计算条件判断,支持合约名义本金规模和标的期初全价两种模式
- 优化部分平仓日终复利计算逻辑,确保未平仓本金贡献正确保留
2026-08-08 16:32:50 +08:00
张名锐 54a86fccc1 fix(swap): 修复部分平仓后复利计算问题(算头不算尾合约复利)
- 当calcLast为false时,部分平仓日终新增复利使用剩余本金计算
- 修复最终全平仓时历史终点利息计算逻辑
- 添加测试用例验证部分平仓后复利计算准确性
- 修正日终待实现利息累加时的历史终点处理方式
- 调整复利部分平仓金额计算方式,确保未平仓部分正确参与后续计算
2026-08-08 16:11:53 +08:00
张名锐 6fdc7d80b2 fix(swap): 修复复利计算和部分平仓处理中的多个问题(算头算尾合约复利平仓)
- 修复合约名义本金规模模式下部分平仓时名义本金计算错误
- 修复最终全平时复利利息计算中历史平仓尾差处理问题
- 修复复利重置日处理中利息重复注入历史本金的错误
- 修复部分平仓后日终待实现利息计算中本金比例应用问题
- 修复全平且实际金额覆盖应结利息后待实现利息清零逻辑
- 新增复合复利交换服务用于单元测试验证
- 添加多个测试用例覆盖复利计算边界场景
2026-08-08 15:51:29 +08:00
hjhan f6a5c1dc83 test(swap): 预付金腿收盘递推链trace——证明ValueDate正确推进到8.4(非公式bug)
- 新增 PrepaidPrincipalClosingChainTraceTest:纯内存驱动 SwapPositionCompose,
  从交易开始日 7.28 逐日收盘到部分平仓日 8.4(含 7.31互换/8.3重置/8.4平仓),
  捕获预付金腿每日 eod.ValueDate。
- 实测 ValueDate 逐日推进 7.28→7.31→8.3→8.4,证明收盘代码(DealInterests 四分支
  均 newEodPayPosition.ValueDate=settleDate)本身正确。
- 结论:8.7 平仓预付金端系统值 20.83(≈6天) 对应 eod.ValueDate≈8.1,说明该笔交易
  预付金腿 eod 在 8.1 之后未被收盘链重新生成(递推链在部分平仓日断了/收盘缺失滞后),
  属数据/流程问题而非利息公式 bug;收盘链若正常推进到 8.4,8.7 平仓应为 3 天=10.41(Excel)。
2026-08-08 15:46:54 +08:00
hjhan cd8c3b6c95 test(swap): 预付金腿两段式平仓计息过程暴露 + SwapCalcTrace追踪器
- 新增 SwapCalcTrace(零成本可开关追踪器,默认关闭,对生产零行为影响):
  在 CalcDailySimpleInterest 埋点,逐日记录计息起点/日终归档 ValueDate 地板/
  计息基数 dynomicPrincipal/当日利率/当日利息/累计,便于定位计息异常根因。
- 新增 PrepaidPrincipalCloseTraceTest:用截图参数(本金100000.23/利率2.1111%/
  8.4平40%→8.7全平)暴露计息过程,证明第二次平仓利息完全由日终归档 ValueDate
  决定——正确归档(ValueDate=8.4)+算尾=3天=10.41(Excel本次利息);
  错误归档(ValueDate=8.1)复现系统截图 6天=20.83。守卫1钉正确值10.41,
  守卫2复现20.83并证明 ValueDate 即『缺的要素』。
- 修正覆盖结论:浮动端/利息腿已有两段式覆盖,预付金腿两段式此前缺失(缺口
  与截图坏『预付金端』一行精确对应)。
2026-08-08 15:02:54 +08:00
hjhan 096d2609eb test(swap): 为债券TRS期间结算自动互换10场景补单测 + SaveAutoSwapDeal接缝可测化
- 新增 BondTrsAutoSwapScenarioTest:覆盖测试场景/测试场景-0702复测两页
  10个自动互换场景(含付息日历登记日2/28→支付日3/2、资金发生日3/3/3/4)、
  部分平仓后按登记日持仓数量计算(剩余60%为54240)、同日多腿合并、
  分红支付日偏移、无结算观察日不得凭空产生互换等,共11条断言全绿。
- SaveAutoSwapDeal 改为走 AddClientCash/AddSwapEvent/PersistFlowEvent 接缝
  (默认实现与重构前行为一致,零行为变更);UpdateInitalPostion 由 private
  改 protected virtual;GetPreDealDate 改 virtual,便于无DB单测。
2026-08-08 13:32:22 +08:00
hjhan 5ca297a73c test(swap): 补充固定值腿业务场景4-2两段式平仓覆盖(GLMS-债券TRS期间结算260702缺口)
- 新增 业务场景4_2_固定值腿_部分平仓后再全平_两段利息均随比例线性缩放
  覆盖「国联民生-债券TRS期间结算功能测试260702.xlsx」Sheet1 矩阵中唯一标记为
  「未测」的格子:固定值腿(mode=1) 部分平仓一次后隔数日再全平。
- 断言两段利息各自随平仓比例线性缩放(30%/70%对照同日期全平),守护 d1badfe4
  的固定值腿平仓比例缩放修复;修复前 newClosePercent=1 会让部分平仓利息等于全平。
- 现有利息测试 75 例全绿(场景1/2/3/4 + 单笔 + 固定值腿 + 多步守恒)。
- 0601 缺陷测试-利息(场景1-4 + 单笔0007/0006) 与 20260807 同源,已由上述套件覆盖。
2026-08-08 12:26:27 +08:00
hjhan d1badfe48f fix(swap): 固定值利息腿平仓比例缩放缺陷(GLMS) + 证明测试
- SwapDealService.CalcNotionalByMode 固定值分支原实现把 closePrincipal 钉成 Fix 全量
  且 newClosePercent 强制置 1,导致界面『全部平仓→部分平仓』改比例时利息腿数据
  完全不变。修复为 closePrincipal = InterestPrincipalFix * closePercent(与预付金/
  多头/空头/标的期初全价等模式一致),posiPrincipal 仍保留 Fix 全量,newClosePercent
  保留真实平仓比例,两个缩放入口作用于不同项不双重缩放。
- EOD 结算路径 SwapEodPositionService 传 closePrecent=1 字面量,Fix*1=Fix,日终行为不变。
- 新增 SwapFixedInterestLegClosePercentBugTest(9 例真实函数复现+证明)。
- 纠正 SwapUnwindPrepayPrincipalBugTdd 中把『免疫』当期望的断言为线性缩放。
- 引入溯源:95686f4c(吴方海, EQD-5718, 2026-05-08);newClosePercent=1 祖传自 acbd2e76(2024-06-04)。
2026-08-08 10:34:10 +08:00
hjhan 994429d3b7 test(interest): 补充场景1固定/浮动+场景2+单笔GLMS利息回归测试
- SwapInterestScenario1And2Test: 场景1浮动(8,利息=0) + 场景1固定(12) + 场景2第一重置期内平仓(12),共32例
- SwapSingleTradeVerificationTest: 单笔GLMS-0007/0006 第三重置期/到期平仓 + 30%+70%守恒,共4例
- 全部走真实生产函数(GetInterests / SaveAutoEodWithCloseInterestPosition),对照 Excel oracle(AO/BL/BN/累计利息)
- 与场景3/4 合计 60 例全绿(容差0.01),非 re-baseline
2026-08-08 09:31:43 +08:00
hjhan feffc196c6 fix(interest): 修复浮动利率部分/全平利息尾差(Bug A/B/C) 并补充回归测试
- Bug A(SwapDealService): 复利早退分支 TdInterestAmount 未乘 closePrecent
- Bug B(SwapDealService): CalcDailyCompoundInterest 用 interest 而非 EOD 四舍五入快照
- Bug C(SwapEodPositionService): 用 oriPosiNotionalValue(平仓前原始本金) 重算平仓利息
- 新增 SwapInterestScenario3And4FloatingTest: 24 个浮动利率用例, 走真实生产函数
  (GetInterests / SaveAutoEodWithCloseInterestPosition), 对照 Excel 手算 oracle(AO/BL/BN),
  断言容差 0.01, 非 re-baseline; 含 DebugCompare 调试输出便于与生产/Excel 逐项对比
- 附 缺陷分析-利息部分平仓尾差20260807.md 与 oracle 源 xlsx
2026-08-08 09:02:05 +08:00
张名锐 253a89b799 test(swap): 添加消费利息场景测试用例并修复重置日利息计算逻辑
- 添加CI_010_EodResetWithoutCloseCarriesFullPendingInterest测试方法
- 验证无平仓重置日必须完整并入上一期累计待实现利息的场景
- 修复CalcDailyCompoundInterestByEod方法中剩余百分比计算逻辑
- 使用posiPrincipal替代preEodPosition.TdInterestPrincipal进行计算
- 确保重置日期计算中本金比例的准确性
2026-08-07 23:00:28 +08:00
张名锐 e819ad02c5 fix(swap): 修复复利计算中的利息处理逻辑
- 添加了从开始日期到结束日期的天数计算
- 添加了从前一日末到结束日期的天数计算
- 修复了特定条件下利息本金和浮动利率的赋值
- 修正了利息金额和累计利息金额的计算
- 添加了四舍五入处理以确保精度准确性
- 修复了利息平仓损益的计算逻辑
2026-08-07 22:13:58 +08:00
张名锐 569002e551 fix(swap): 修复重置日期利息计算逻辑
- 修正了 calcLast=false 时重置日取价被跳过的问题
- 确保重置日之前的复利能够正确并入本金
- 调整了计息日判断逻辑的位置以保证本金重置正常执行
- 修复了重置日当天利息不应被计入的逻辑错误
2026-08-07 21:54:04 +08:00
张名锐 19d8b2a926 Merge remote-tracking branch 'origin/glms/feature/1.4.2' into glms/feature/1.4.2 2026-08-07 20:52:13 +08:00
张名锐 5539bd9c9a ```
fix(swap): 修复复利模式下部分平仓后EOD本金计算问题

- 在复利模式部分平仓场景中确保使用计算得出的复利本金
- 添加了针对复利重置日期部分平仓的单元测试验证
- 修复了EOD本金重置逻辑,避免复利计算被错误覆盖
- 确保CloseInterestPosition执行后保留正确的复利本金值
```
2026-08-07 20:51:56 +08:00
hjhan 66a97e03ef fix(swap): 复利重置日=平仓日时 calcLast 不再跳过 FR007 取价
根因(GLMS-JIATT-20260805):InterestCalcMode='10'(算头不算尾,calcLast=false)时,
CalcDailyCompoundInterest 循环的 'if(!calcLast && accrueDate==endDate) continue'
会跳过平仓日。若平仓日恰好是重置日(i%period==0),取价代码块被一并跳过,
导致 flowEvent.FloatRate 落库为旧周期利率,传染后续 EOD 复利计算。

修复:把重置日的 FR007 取价提前到 calcFirst/calcLast 跳过判断之前——
calcLast 只应跳过'计息',不应跳过'重置日利率取价'。同时循环外用最终
floatRate 兜底赋值 flowEvent.FloatRate,确保落库值反映最后重置日的利率。

验证:
- CI_007 合成测试(平仓日=重置日):修复前 FloatRate=旧值(FAIL),修复后=新值(PASS)
- 连库验证(GLMS-JIATT-20260805 8/4平仓):FloatRate 0.0123→0.0213(8/3新值)
- 利息金额不变(calcLast 不计当天利息,Amount 不受影响,只修正 FloatRate 字段)
- 全套 swap 测试无新增回归(334通过,2失败均为pre-existing单利/EOD路径)

附:CI_007 复现测试 + GLMS20260805 FR007/EOD 诊断工具 + 文档 longRatio 状态更新
2026-08-07 20:43:16 +08:00
hjhan 75b033dd7b test(swap): 添加 GLMS-JIATT-20260805 复利部分平仓利息诊断测试
连 96 测试库的诊断工具,用于定位'100%平仓 vs 部分平仓利息差异异常'。
对同一笔交易分别调 GetUnwindInterests(100%) 和 (40%),逐腿打印本金/利息并对比,
输出比值以判断是否线性。复现并确认了 consumedInterest 未按 closePercent 缩放的根因
(已由 a0be0eb0 修复,本测试作回归诊断保留)。

模式同 GLMS20260701DbDiagnoseTest:TestCategory(DbDiagnose),连不上库自动 Inconclusive。
2026-08-07 19:00:31 +08:00
张名锐 a0be0eb003 fix(swap): 修复复利平仓时已结利息扣除计算问题
- 修改 CalcCompoundUnwind 方法添加 closePercent 参数用于部分平仓场景
- 更新复利平仓逻辑,将已结利息按平仓比例进行缩放扣除
- 添加部分平仓测试用例验证已结利息按比例扣除的正确性
- 修复了全部已结利息在部分平仓时被全额扣除的问题
2026-08-07 18:36:32 +08:00
张名锐 d78d1f48e7 fix(swap): 修复互换价格变动时盈亏计算错误
- 在后端计算逻辑中添加 longRatio 参数用于区分多空头寸类型
- 修改前端 JavaScript 代码中的盈亏计算公式,加入 longRatio 参与计算
- 更新单元测试,增加空头头寸价格上涨时亏损的测试用例
- 补充前端测试用例验证空头头寸计算逻辑的准确性
- 修复了空头头寸在价格上涨时显示盈利而非亏损的计算错误
2026-08-07 17:44:04 +08:00
hjhan acc37bdb99 test(swap): 补算尾/不算尾部分平仓的 InterestIncomeSum 递推断言
DI_MANUAL_PARTIAL_CLOSE_CalcLast/NoCalcLast 原仅断言 TdInterestIncome(当日新计利息
按全额/剩余本金计提),未钉死该差异是否传导到待实现利息总额 InterestIncomeSum。
补一条递推断言:InterestIncomeSum = 前日待实现 + 当日新计 - 当日实现,
锁定"算尾 → 被平仓部分多1天利息 → 进入待实现总额"完整链条,不算尾同理对照。

纯测试改动,生产代码无改动,双绿通过。
2026-08-07 15:43:11 +08:00