From 692b8d753bd78662db5ff395397dde3323d873de Mon Sep 17 00:00:00 2001 From: hjhan Date: Thu, 13 Aug 2026 18:31:34 +0800 Subject: [PATCH] =?UTF-8?q?docs(margin):=20=E8=A1=A5=E5=BC=BA=20CalcMargin?= =?UTF-8?q?Interest=20=E9=9A=90=E5=BC=8F=E5=81=87=E8=AE=BE/=E5=A5=91?= =?UTF-8?q?=E7=BA=A6=E6=B3=A8=E9=87=8A=20+=20SwapEodPositionService=20orgi?= =?UTF-8?q?nPv=20=E5=86=97=E4=BD=99=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CalcMarginInterest 加 :显性化 4 点——InterestType 必须单利、SwapIntervalList 必须单段(违反静默算错、无 assert,前端保证)、方向须调用方翻转、preEod 首日就地修改;附定位指引(SwapCalcTrace 反推 accrualBasis) - SwapEodPositionService 三处 FixedAmountAndMargin 的 orginPv 赋值加注释:仅固定值腿(mode 1)生效,保证金(5/6)被 CalcMarginInterest 忽略 纯注释,零代码行为变化;全量 SwapModule 524/524 通过。 --- YLErpDAL/Modules/SwapModule/SwapDealService.cs | 11 +++++++++++ YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 13cf78d8..96648fc4 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -953,6 +953,17 @@ namespace YLErp.Modules.SwapModule /// 本方法内部按保证金维度计算(PreviousBalance),消除原 InitSwapDealInterest 的外部维度 hack /// (融资腿 orginPv=浮动端名义本金)。保留累计语义(priorAccrued + 增量),满足下游字段契约。 /// + /// + /// 隐式假设(违反会静默算错、无 assert 防护——由前端保证金表单保证;诊断时先核对这两条): + /// 1. InterestType 必须为单利。本方法恒走 SimpleInterestAccrual 单利,不查 InterestType; + /// 若库内 InterestMode=5/6 且 InterestType=复利(脏数据),会与旧 CalcEodInterest 的复利分支不一致。 + /// 2. SwapIntervalList 必须单段。盘中用 [(PosiStartDate, rate)] 单段,不做 BuildSegmentRates 多段; + /// rate 入参须已是生效固定利率(GetInterests:746 GetFixedRate)。若保证金利率表被改成多段会漏分段。 + /// 契约与副作用: + /// 3. position.InterestDirection 须已由调用方翻转(GetInterests:742 FlipDirection);本方法不翻转。 + /// 4. preEod 在 id==0 时被就地修改(设 TdInterestPrincipal/PosiNotionalValue/FloatRate),与旧 CalcEodInterest 一致。 + /// 定位:SwapCalcTrace 落盘 AccrueEod/AccrualPeriod 的 notional/days/rate/accrued;盘中 accrualBasis 可从 trace 的 notional 反推。 + /// /// true=收盘归档(EOD),false=盘中平仓/互换。 /// 互换事件(仅盘中生效,true 时利息归零,同 InitSwapDealInterest)。 public swap_flow_event CalcMarginInterest( diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 9bf583aa..be097caf 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1138,6 +1138,8 @@ namespace YLErp.Modules.SwapModule positions.Add(position); List preEodPositions = new List(); preEodPositions.Add(eodPayPosition); + // orginPv 在此仅对固定值腿(mode 1)生效;保证金腿(5/6)的 orginPv 虽在此赋值, + // 但 GetInterests 保证金分支已走 CalcMarginInterest(内部自算 orginPv=PreviousBalance),忽略此处传入值。 var interestModes = MarginModes.FixedAmountAndMargin; if (interestModes.Contains(position.InterestMode)) { @@ -1276,6 +1278,8 @@ namespace YLErp.Modules.SwapModule newEodPayPosition = eodPayPosition.Clone(); newEodPayPosition.id = 0; } + // orginPv 在此仅对固定值腿(mode 1)生效;保证金腿(5/6)的 orginPv 虽在此赋值, + // 但 GetInterests 保证金分支已走 CalcMarginInterest(内部自算 orginPv=PreviousBalance),忽略此处传入值。 var interestModes = MarginModes.FixedAmountAndMargin; if (interestModes.Contains(position.InterestMode)) { @@ -1489,6 +1493,8 @@ namespace YLErp.Modules.SwapModule Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}"); List intervals = position.SwapIntervalList; var tradeExtend = td.trade_extend.ExtendObj; + // orginPv 在此仅对固定值腿(mode 1)生效;保证金腿(5/6)的 orginPv 虽在此赋值, + // 但 GetInterests 保证金分支已走 CalcMarginInterest(内部自算 orginPv=PreviousBalance),忽略此处传入值。 var interestModes = MarginModes.FixedAmountAndMargin; if (eodPayPosition == null) {