diff --git a/UnitTestProject/Modules/SwapModule/SwapUnwindFloatingLegDiagnosticTdd.cs b/UnitTestProject/Modules/SwapModule/SwapUnwindFloatingLegDiagnosticTdd.cs
index 9340fe93..84a7230d 100644
--- a/UnitTestProject/Modules/SwapModule/SwapUnwindFloatingLegDiagnosticTdd.cs
+++ b/UnitTestProject/Modules/SwapModule/SwapUnwindFloatingLegDiagnosticTdd.cs
@@ -66,33 +66,5 @@ namespace YLErp.Modules.SwapModule
TradeDate = D0, StartDate = D0, ExerciseDate = D1, TradeStatus = "确认成交", ValidState = "Valid",
StockEqvNotional = (double)RealLong, Notional = (double)RealLong, trade_extend = extend };
}
-
- /// 用反射调用 private CalcNotionalByMode,直接证明各 mode 的 closePrincipal 是否依赖 posiLong/posiShort。
- private (decimal close, decimal posi, decimal pct) CallCalcNotionalByMode(swap_position position, decimal closePct, decimal posiNotional, decimal posiLong, decimal posiShort)
- {
- var m = typeof(SwapDealService).GetMethod("CalcNotionalByMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- return ((decimal, decimal, decimal))m.Invoke(_svc, new object[] { position, closePct, posiNotional, posiLong, posiShort });
- }
-
- [TestMethod]
- public void 诊断_mode9_标的期初全价_closePrincipal_不依赖posiLong_而用posiNotional()
- {
- // mode 9 分支:closePrincipal = posiNotional * closePercent
- var baseP = OrigBasePrice();
- var (close, posi, _) = CallCalcNotionalByMode(baseP, ClosePct, RealLong * ClosePct, OrigLong, 0m);
- Console.WriteLine($"[mode9] posiNotional={RealLong * ClosePct} posiLong(orig)={OrigLong} → closePrincipal={close}");
- Assert.AreEqual(RealLong * ClosePct * ClosePct, close, "mode9 应 = posiNotional(=real剩余*closePct) * closePct,与 posiLong(orig 100M) 无关");
- }
-
- [TestMethod]
- public void 诊断_mode5_预付金_closePrincipal_用自身Fix_不依赖posiLong()
- {
- // mode 5 分支:closePrincipal = position.InterestPrincipalFix * closePercent(用 Clone 后的 real Fix)
- var prepay = RealPrepay(); // Fix = RealFix(66,813.12)
- var (close, posi, _) = CallCalcNotionalByMode(prepay, ClosePct, RealLong * ClosePct, OrigLong, 0m);
- Console.WriteLine($"[mode5] Fix(cloned real)={RealFix} posiLong(orig)={OrigLong} → closePrincipal={close}");
- Assert.AreEqual(RealFix * ClosePct, close, "mode5 应 = 实时腿剩余本金(real Fix) * closePct,与 posiLong(orig 100M) 无关");
- Assert.AreNotEqual(OrigFix * ClosePct, close, "务必不是期初 99,000 * closePct(证明后端修复生效)");
- }
}
}
diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs
index 6e4aa810..e95b395b 100644
--- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs
+++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs
@@ -840,7 +840,26 @@ namespace YLErp.Modules.SwapModule
bool swap = InitInterestDate(unwindDate, preDealDate, td, tdClose, out DateTime startDate, out DateTime endDate);
// 计算名义本金
- var (closePrincipal, posiPrincipal, newClosePercent) = CalcNotionalByMode(position, closePrecent, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue);
+ decimal closePrincipal;
+ decimal posiPrincipal;
+ decimal newClosePercent = closePrecent;
+ var mode = (InterestModeEnum)position.InterestMode;
+
+ if (MarginModes.Contains(position.InterestMode))
+ {
+ // 保证金腿: 计息基数 = InterestPrincipalFix(保证金余额)
+ closePrincipal = position.InterestPrincipalFix * closePrecent;
+ posiPrincipal = position.InterestPrincipalFix;
+ }
+ else
+ {
+ // 融资腿(1/2/9): 走策略工厂
+ var r = FundingLegStrategyFactory.Get(mode)
+ .CalcNotional(position.InterestPrincipalFix, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue, closePrecent);
+ closePrincipal = r.ClosePrincipal;
+ posiPrincipal = r.PosiPrincipal;
+ newClosePercent = r.ClosePercent;
+ }
if ((InterestModeEnum)position.InterestMode == InterestModeEnum.合约名义本金规模
|| (InterestModeEnum)position.InterestMode == InterestModeEnum.标的期初全价
&& posiNotionalValue == 0m)
@@ -904,51 +923,9 @@ namespace YLErp.Modules.SwapModule
return interests;
}
- ///
- /// 根据计息模式计算名义本金。
- ///
- /// 现状(过渡期):
- /// - 融资腿(mode 1/2/9)已委托 FundingLegStrategyFactory,走新策略体系。
- /// - 保证金(mode 5/6)暂保留——待 Margin 独立计息入口建成后迁出。
- /// - 多空存续(mode 7/8)界面已禁用,保留 case 仅为防御性兜底。
- /// - 死代码(mode 3/4)走 default。
- ///
- /// 待保证金(mode 5/6)迁入 Margin 上下文后,本方法可整体删除,
- /// 调用点直接走 FundingLegStrategyFactory.Get(mode)。
- ///
- private (decimal close, decimal posi, decimal closePct) CalcNotionalByMode(swap_position position, decimal closePercent, decimal posiNotional, decimal posiLong, decimal posiShort)
- {
- var mode = (InterestModeEnum)position.InterestMode;
-
- // 融资腿(1/2/9)走策略工厂
- if (mode == InterestModeEnum.固定值
- || mode == InterestModeEnum.合约名义本金规模
- || mode == InterestModeEnum.标的期初全价)
- {
- var r = FundingLegStrategyFactory.Get(mode)
- .CalcNotional(position.InterestPrincipalFix, posiNotional, posiLong, posiShort, closePercent);
- return (r.ClosePrincipal, r.PosiPrincipal, r.ClosePercent);
- }
-
- // 以下 mode 尚未迁入新架构,保留原逻辑
- decimal closePrincipal = posiNotional;
- decimal posiPrincipal = posiNotional;
- decimal newClosePercent = closePercent;
-
- switch (mode)
- {
- case InterestModeEnum.追加预付金:
- case InterestModeEnum.初始预付金:
- closePrincipal = position.InterestPrincipalFix * closePercent;
- posiPrincipal = position.InterestPrincipalFix;
- break;
- }
- return (closePrincipal, posiPrincipal, newClosePercent);
- }
-
///
/// 平仓比例口径转换(解决"显示占期初 / 计算占剩余"双语义问题)。
- /// 前端与事件列表展示用"占期初(original)"语义(A);后端 CalcNotionalByMode / 费用递减 /
+ /// 前端与事件列表展示用"占期初(original)"语义(A);后端计息基数计算 / 费用递减 /
/// 全平判定均按"占剩余(remaining)"语义(B)消费。
/// A → B:B = A × 期初名义本金(NotionalValue) / 剩余名义本金(PosiNotionalValue),并 cap 到 1。
/// B → A:A = B × 剩余名义本金 / 期初名义本金。
diff --git a/YLErpWeb/Properties/launchSettings.json b/YLErpWeb/Properties/launchSettings.json
index be61e851..6b0464ba 100644
--- a/YLErpWeb/Properties/launchSettings.json
+++ b/YLErpWeb/Properties/launchSettings.json
@@ -5,7 +5,7 @@
"launchBrowser": true,
"launchUrl": "http://localhost:49462",
"environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "dev"
+ "ASPNETCORE_ENVIRONMENT": "local"
},
"applicationUrl": "http://localhost:49462"
}