diff --git a/UnitTestProject/Modules/SwapModule/InterestLegs/InterestLegStrategyTest.cs b/UnitTestProject/Modules/SwapModule/FundingLegs/FundingLegStrategyTest.cs
similarity index 58%
rename from UnitTestProject/Modules/SwapModule/InterestLegs/InterestLegStrategyTest.cs
rename to UnitTestProject/Modules/SwapModule/FundingLegs/FundingLegStrategyTest.cs
index 995f3d59..cae1d332 100644
--- a/UnitTestProject/Modules/SwapModule/InterestLegs/InterestLegStrategyTest.cs
+++ b/UnitTestProject/Modules/SwapModule/FundingLegs/FundingLegStrategyTest.cs
@@ -1,24 +1,23 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using YLErp.DBModels.Enums;
-using YLErp.Modules.SwapModule.InterestLegs;
+using YLErp.Modules.SwapModule.FundingLegs;
-namespace UnitTestProject.Modules.SwapModule.InterestLegs
+namespace UnitTestProject.Modules.SwapModule.FundingLegs
{
///
- /// 利息腿策略单测。验证每个策略的 CalcNotional 与现有 CalcNotionalByMode switch 完全一致。
+ /// 融资腿策略单测。验证每个策略的 CalcNotional 与现有 CalcNotionalByMode switch 完全一致。
/// 这组测试是后续"迁移调用点"的安全网——迁移前后行为必须不变。
- /// 注:原预付金(PrepayLeg)用例已迁出,见 MarginLegTest(保证金独立限界上下文)。
///
[TestClass]
- public class InterestLegStrategyTest
+ public class FundingLegStrategyTest
{
- private const decimal Fix = 2_000_000m; // 合约固定本金
- private const decimal Notional = 100_000_000m; // 剩余名义本金 1 亿
+ private const decimal Fix = 2_000_000m;
+ private const decimal Notional = 100_000_000m;
private const decimal LongNotional = 60_000_000m;
private const decimal ShortNotional = 40_000_000m;
- #region 固定值(mode 1):恒=Fix,不随比例变
+ #region 固定值(mode 1)
[TestMethod]
public void 固定值_部分平仓_计息基数恒等于Fix()
@@ -28,7 +27,7 @@ namespace UnitTestProject.Modules.SwapModule.InterestLegs
Assert.AreEqual(Fix, r.ClosePrincipal, "平仓本金恒=Fix");
Assert.AreEqual(Fix, r.PosiPrincipal, "持仓本金恒=Fix");
- Assert.AreEqual(1m, r.ClosePercent, "有效比例恒=1(固定值不随比例缩放)");
+ Assert.AreEqual(1m, r.ClosePercent);
}
[TestMethod]
@@ -36,13 +35,12 @@ namespace UnitTestProject.Modules.SwapModule.InterestLegs
{
var leg = new FixedNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 1m);
-
- Assert.AreEqual(Fix, r.ClosePrincipal, "全平本金仍=Fix");
+ Assert.AreEqual(Fix, r.ClosePrincipal);
}
#endregion
- #region 合约名义本金规模(mode 2):按比例线性缩放
+ #region 合约名义本金规模(mode 2)
[TestMethod]
public void 合约名义本金_部分平仓_本金按比例缩放()
@@ -50,9 +48,9 @@ namespace UnitTestProject.Modules.SwapModule.InterestLegs
var leg = new ContractNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 0.5m);
- Assert.AreEqual(50_000_000m, r.ClosePrincipal, "平仓本金=Notional×50%");
- Assert.AreEqual(Notional, r.PosiPrincipal, "持仓本金=Notional全额");
- Assert.AreEqual(0.5m, r.ClosePercent, "有效比例=入参");
+ Assert.AreEqual(50_000_000m, r.ClosePrincipal);
+ Assert.AreEqual(Notional, r.PosiPrincipal);
+ Assert.AreEqual(0.5m, r.ClosePercent);
}
[TestMethod]
@@ -60,8 +58,7 @@ namespace UnitTestProject.Modules.SwapModule.InterestLegs
{
var leg = new ContractNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 1m);
-
- Assert.AreEqual(Notional, r.ClosePrincipal, "全平本金=Notional");
+ Assert.AreEqual(Notional, r.ClosePrincipal);
}
[TestMethod]
@@ -70,13 +67,13 @@ namespace UnitTestProject.Modules.SwapModule.InterestLegs
var leg = new ContractNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 0m);
- Assert.AreEqual(0m, r.ClosePrincipal, "零平仓本金=0");
- Assert.AreEqual(Notional, r.PosiPrincipal, "持仓本金仍=Notional");
+ Assert.AreEqual(0m, r.ClosePrincipal);
+ Assert.AreEqual(Notional, r.PosiPrincipal);
}
#endregion
- #region 标的期初全价(mode 9):主路径公式与mode2相同
+ #region 标的期初全价(mode 9)
[TestMethod]
public void 标的期初全价_部分平仓_主路径公式同mode2()
@@ -84,7 +81,7 @@ namespace UnitTestProject.Modules.SwapModule.InterestLegs
var leg = new UnderlyingFullPriceLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 0.5m);
- Assert.AreEqual(50_000_000m, r.ClosePrincipal, "平仓本金=Notional×50%(与mode2主路径一致)");
+ Assert.AreEqual(50_000_000m, r.ClosePrincipal);
Assert.AreEqual(Notional, r.PosiPrincipal);
Assert.AreEqual(0.5m, r.ClosePercent);
}
@@ -94,13 +91,12 @@ namespace UnitTestProject.Modules.SwapModule.InterestLegs
{
var leg = new UnderlyingFullPriceLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 1m);
-
Assert.AreEqual(Notional, r.ClosePrincipal);
}
#endregion
- #region 守卫:策略对应各自mode
+ #region 守卫
[TestMethod]
public void 各策略对应正确枚举值()
@@ -112,35 +108,34 @@ namespace UnitTestProject.Modules.SwapModule.InterestLegs
#endregion
- #region 工厂:按mode分发
+ #region 工厂
[TestMethod]
public void 工厂_返回各活跃mode的策略()
{
- Assert.IsInstanceOfType(InterestLegStrategyFactory.Get(InterestModeEnum.固定值), typeof(FixedNotionalLeg));
- Assert.IsInstanceOfType(InterestLegStrategyFactory.Get(InterestModeEnum.合约名义本金规模), typeof(ContractNotionalLeg));
- Assert.IsInstanceOfType(InterestLegStrategyFactory.Get(InterestModeEnum.标的期初全价), typeof(UnderlyingFullPriceLeg));
+ Assert.IsInstanceOfType(FundingLegStrategyFactory.Get(InterestModeEnum.固定值), typeof(FixedNotionalLeg));
+ Assert.IsInstanceOfType(FundingLegStrategyFactory.Get(InterestModeEnum.合约名义本金规模), typeof(ContractNotionalLeg));
+ Assert.IsInstanceOfType(FundingLegStrategyFactory.Get(InterestModeEnum.标的期初全价), typeof(UnderlyingFullPriceLeg));
}
[TestMethod]
public void 工厂_未注册mode抛异常()
{
Assert.ThrowsException(() =>
- InterestLegStrategyFactory.Get(InterestModeEnum.持仓名义本金));
+ FundingLegStrategyFactory.Get(InterestModeEnum.持仓名义本金));
Assert.ThrowsException(() =>
- InterestLegStrategyFactory.Get(InterestModeEnum.持仓市值));
- // 预付金 5/6 已不再是利息腿,工厂不再注册,按未注册处理
+ FundingLegStrategyFactory.Get(InterestModeEnum.持仓市值));
Assert.ThrowsException(() =>
- InterestLegStrategyFactory.Get(InterestModeEnum.初始预付金));
+ FundingLegStrategyFactory.Get(InterestModeEnum.初始预付金));
Assert.ThrowsException(() =>
- InterestLegStrategyFactory.Get(InterestModeEnum.追加预付金));
+ FundingLegStrategyFactory.Get(InterestModeEnum.追加预付金));
}
[TestMethod]
public void 工厂_int重载和枚举重载等价()
{
- var byEnum = InterestLegStrategyFactory.Get(InterestModeEnum.固定值);
- var byInt = InterestLegStrategyFactory.Get((int)InterestModeEnum.固定值);
+ var byEnum = FundingLegStrategyFactory.Get(InterestModeEnum.固定值);
+ var byInt = FundingLegStrategyFactory.Get((int)InterestModeEnum.固定值);
Assert.AreEqual(byEnum.Mode, byInt.Mode);
}
diff --git a/YLErpDAL/Modules/SwapModule/InterestLegs/ContractNotionalLeg.cs b/YLErpDAL/Modules/SwapModule/FundingLegs/ContractNotionalLeg.cs
similarity index 76%
rename from YLErpDAL/Modules/SwapModule/InterestLegs/ContractNotionalLeg.cs
rename to YLErpDAL/Modules/SwapModule/FundingLegs/ContractNotionalLeg.cs
index c2dff484..f1d62dd0 100644
--- a/YLErpDAL/Modules/SwapModule/InterestLegs/ContractNotionalLeg.cs
+++ b/YLErpDAL/Modules/SwapModule/FundingLegs/ContractNotionalLeg.cs
@@ -1,13 +1,13 @@
using YLErp.DBModels;
-namespace YLErp.Modules.SwapModule.InterestLegs;
+namespace YLErp.Modules.SwapModule.FundingLegs;
///
-/// 合约名义本金规模利息腿(InterestMode=合约名义本金规模)。
+/// 合约名义本金规模融资腿(InterestMode=合约名义本金规模)。
/// 站在"合约规模"视角:平仓本金 = 剩余名义本金 × 平仓比例。
/// 与标的期初全价(9)在 CalcNotionalByMode 里公式相同,差异在衡泰路径 grossPrice 折算和 EOD 复利反推。
///
-public sealed class ContractNotionalLeg : IInterestLegStrategy
+public sealed class ContractNotionalLeg : IFundingLegStrategy
{
public InterestModeEnum Mode => InterestModeEnum.合约名义本金规模;
diff --git a/YLErpDAL/Modules/SwapModule/InterestLegs/FixedNotionalLeg.cs b/YLErpDAL/Modules/SwapModule/FundingLegs/FixedNotionalLeg.cs
similarity index 69%
rename from YLErpDAL/Modules/SwapModule/InterestLegs/FixedNotionalLeg.cs
rename to YLErpDAL/Modules/SwapModule/FundingLegs/FixedNotionalLeg.cs
index c77c8203..fd85793c 100644
--- a/YLErpDAL/Modules/SwapModule/InterestLegs/FixedNotionalLeg.cs
+++ b/YLErpDAL/Modules/SwapModule/FundingLegs/FixedNotionalLeg.cs
@@ -1,13 +1,14 @@
using YLErp.DBModels;
+using YLErp.Modules.SwapModule.FundingLegs;
-namespace YLErp.Modules.SwapModule.InterestLegs;
+namespace YLErp.Modules.SwapModule.FundingLegs;
///
-/// 固定值利息腿(InterestMode=固定值)。
+/// 固定值融资腿(InterestMode=固定值)。
/// 计息基数由合约约定(InterestPrincipalFix),无论平仓比例多少都恒等于该值。
/// 业务规则:固定值就是合同写死的固定值,永远不变。
///
-public sealed class FixedNotionalLeg : IInterestLegStrategy
+public sealed class FixedNotionalLeg : IFundingLegStrategy
{
public InterestModeEnum Mode => InterestModeEnum.固定值;
diff --git a/YLErpDAL/Modules/SwapModule/InterestLegs/InterestLegStrategyFactory.cs b/YLErpDAL/Modules/SwapModule/FundingLegs/FundingLegStrategyFactory.cs
similarity index 61%
rename from YLErpDAL/Modules/SwapModule/InterestLegs/InterestLegStrategyFactory.cs
rename to YLErpDAL/Modules/SwapModule/FundingLegs/FundingLegStrategyFactory.cs
index 0826023e..a909ec5e 100644
--- a/YLErpDAL/Modules/SwapModule/InterestLegs/InterestLegStrategyFactory.cs
+++ b/YLErpDAL/Modules/SwapModule/FundingLegs/FundingLegStrategyFactory.cs
@@ -2,20 +2,20 @@ using System;
using System.Collections.Generic;
using YLErp.DBModels;
-namespace YLErp.Modules.SwapModule.InterestLegs;
+namespace YLErp.Modules.SwapModule.FundingLegs;
///
-/// 利息腿策略工厂。按 InterestMode 返回对应策略实例。
+/// 融资腿策略工厂。按 InterestMode 返回对应策略实例。
/// 替换原 SwapDealService.CalcNotionalByMode 的 switch,收敛 mode 分发逻辑到一处。
///
-/// 当前界面活跃 mode:1 固定值 / 2 合约名义本金规模 / 9 标的期初全价。
-/// 注:mode 5/6 预付金已迁出本上下文(见 YLErp.Modules.SwapModule.Margin / MarginLeg),不再作为利息腿注册。
+/// 只管融资腿(funding leg),不管保证金——保证金是独立的资金管理体系,
+/// 不应该出现在融资腿策略里。mode 5/6(预付金)属于保证金,不在此注册。
/// 死代码 mode 3/4 不注册;半死 mode 7/8 不注册(界面已注释)。
/// 传入未注册的 mode 会抛异常,防止静默走默认分支。
///
-public static class InterestLegStrategyFactory
+public static class FundingLegStrategyFactory
{
- private static readonly Dictionary _strategies = new()
+ private static readonly Dictionary _strategies = new()
{
[InterestModeEnum.固定值] = new FixedNotionalLeg(),
[InterestModeEnum.合约名义本金规模] = new ContractNotionalLeg(),
@@ -23,7 +23,7 @@ public static class InterestLegStrategyFactory
};
/// 按 mode 返回对应策略。未注册的 mode 抛 ArgumentException。
- public static IInterestLegStrategy Get(InterestModeEnum mode)
+ public static IFundingLegStrategy Get(InterestModeEnum mode)
{
if (_strategies.TryGetValue(mode, out var strategy))
return strategy;
@@ -31,5 +31,5 @@ public static class InterestLegStrategyFactory
}
/// 按 mode 值返回对应策略,便于调用方直接传 int。
- public static IInterestLegStrategy Get(int mode) => Get((InterestModeEnum)mode);
+ public static IFundingLegStrategy Get(int mode) => Get((InterestModeEnum)mode);
}
diff --git a/YLErpDAL/Modules/SwapModule/InterestLegs/IInterestLegStrategy.cs b/YLErpDAL/Modules/SwapModule/FundingLegs/IFundingLegStrategy.cs
similarity index 78%
rename from YLErpDAL/Modules/SwapModule/InterestLegs/IInterestLegStrategy.cs
rename to YLErpDAL/Modules/SwapModule/FundingLegs/IFundingLegStrategy.cs
index b3e640b2..2d29f8c0 100644
--- a/YLErpDAL/Modules/SwapModule/InterestLegs/IInterestLegStrategy.cs
+++ b/YLErpDAL/Modules/SwapModule/FundingLegs/IFundingLegStrategy.cs
@@ -1,9 +1,35 @@
using YLErp.DBModels;
-namespace YLErp.Modules.SwapModule.InterestLegs;
+namespace YLErp.Modules.SwapModule.FundingLegs;
///
-/// 计息腿策略的计算结果。对应原 CalcNotionalByMode 返回的三元组,用自描述名。
+/// 融资腿(Funding Leg)计息基数策略。每个 InterestMode 一个实现。
+///
+/// 命名说明:用 FundingLeg(业界标准 Financing/Funding Leg),不用 InterestLeg——
+/// "interest"易和通用"利息"混淆;funding 精确表达"融资成本"。
+/// 融资腿 = 客户付给券商的杠杆成本(spread + FR007),与保证金(Margin)、标的端(ReturnLeg)各自独立。
+///
+/// 职责单一:给定持仓参数与平仓比例,算出"平仓本金 / 存续本金 / 有效比例"。
+/// 不做计息(计息由 SwapInterest 纯函数完成),不取价(取价由 IIndexFixer 完成)。
+///
+public interface IFundingLegStrategy
+{
+ /// 该策略对应的计息模式。
+ InterestModeEnum Mode { get; }
+
+ ///
+ /// 根据持仓参数与平仓比例计算计息本金三元组。
+ ///
+ /// 合约固定本金(固定值/预付金腿用;其余腿忽略)。
+ /// 当前剩余名义本金(数量 × 全价)。
+ /// 多头剩余名义本金(多空存续腿用,当前界面已禁用)。
+ /// 空头剩余名义本金。
+ /// 平仓比例(占剩余,0~1)。
+ NotionalResult CalcNotional(decimal fix, decimal posiNotional, decimal posiLong, decimal posiShort, decimal closePercent);
+}
+
+///
+/// 融资腿策略的计算结果。对应原 CalcNotionalByMode 返回的三元组,用自描述名。
///
public readonly struct NotionalResult
{
@@ -22,25 +48,3 @@ public readonly struct NotionalResult
public void Deconstruct(out decimal close, out decimal posi, out decimal pct)
=> (close, posi, pct) = (ClosePrincipal, PosiPrincipal, ClosePercent);
}
-
-///
-/// 利息腿计息基数策略。每个 InterestMode 一个实现,替换原 CalcNotionalByMode 的 switch。
-///
-/// 职责单一:给定持仓参数与平仓比例,算出"平仓本金 / 存续本金 / 有效比例"。
-/// 不做计息(计息由 SwapInterest 纯函数完成),不取价(取价由 IIndexFixer 完成)。
-///
-public interface IInterestLegStrategy
-{
- /// 该策略对应的计息模式。
- InterestModeEnum Mode { get; }
-
- ///
- /// 根据持仓参数与平仓比例计算计息本金三元组。
- ///
- /// 合约固定本金(固定值/预付金腿用;其余腿忽略)。
- /// 当前剩余名义本金(数量 × 全价)。
- /// 多头剩余名义本金(多空存续腿用,当前界面已禁用)。
- /// 空头剩余名义本金。
- /// 平仓比例(占剩余,0~1)。
- NotionalResult CalcNotional(decimal fix, decimal posiNotional, decimal posiLong, decimal posiShort, decimal closePercent);
-}
diff --git a/YLErpDAL/Modules/SwapModule/InterestLegs/UnderlyingFullPriceLeg.cs b/YLErpDAL/Modules/SwapModule/FundingLegs/UnderlyingFullPriceLeg.cs
similarity index 80%
rename from YLErpDAL/Modules/SwapModule/InterestLegs/UnderlyingFullPriceLeg.cs
rename to YLErpDAL/Modules/SwapModule/FundingLegs/UnderlyingFullPriceLeg.cs
index 486695c5..725717fd 100644
--- a/YLErpDAL/Modules/SwapModule/InterestLegs/UnderlyingFullPriceLeg.cs
+++ b/YLErpDAL/Modules/SwapModule/FundingLegs/UnderlyingFullPriceLeg.cs
@@ -1,15 +1,15 @@
using YLErp.DBModels;
-namespace YLErp.Modules.SwapModule.InterestLegs;
+namespace YLErp.Modules.SwapModule.FundingLegs;
///
-/// 标的期初全价利息腿(InterestMode=标的期初全价)。
+/// 标的期初全价融资腿(InterestMode=标的期初全价)。
/// 站在"持仓全价"视角:计息基数 = 标的含费全价(PosiGrossPrice/EntryDirtyPrice) × 数量。
/// 主路径 CalcNotionalByMode 公式与合约名义本金规模(2)相同;
/// 差异在衡泰路径会乘 grossPrice 折算(SwapDealService.GetUnwindInterestsByHT),
/// 以及 EOD 复利部分平仓后直接返回剩余本金(禁止反推,SwapEodPositionService:1458-1465)。
///
-public sealed class UnderlyingFullPriceLeg : IInterestLegStrategy
+public sealed class UnderlyingFullPriceLeg : IFundingLegStrategy
{
public InterestModeEnum Mode => InterestModeEnum.标的期初全价;
diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs
index 5476b778..152c0176 100644
--- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs
+++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs
@@ -11,7 +11,7 @@ using YLErp.Modules.DataProviderModule;
using YLErp.Modules.EodModule;
using YLErp.Modules.TradeModule;
using YLErp.Modules.TradeModule.DealModule;
-using YLErp.Modules.SwapModule.InterestLegs;
+using YLErp.Modules.SwapModule.FundingLegs;
using YLErp.Modules.SwapModule.Margin;
using YLErp.QdpModule;
@@ -905,7 +905,7 @@ namespace YLErp.Modules.SwapModule
///
/// 根据计息模式计算名义本金。
- /// 融资腿(mode 1/2/9)已委托 InterestLegStrategyFactory;保证金(mode 5/6)和
+ /// 融资腿(mode 1/2/9)已委托 FundingLegStrategyFactory;保证金(mode 5/6)和
/// 半禁用的多空存续(mode 7/8)暂保留原逻辑,待 Margin 上下文接入后再迁出。
///
private (decimal close, decimal posi, decimal closePct) CalcNotionalByMode(swap_position position, decimal closePercent, decimal posiNotional, decimal posiLong, decimal posiShort)
@@ -917,7 +917,7 @@ namespace YLErp.Modules.SwapModule
|| mode == InterestModeEnum.合约名义本金规模
|| mode == InterestModeEnum.标的期初全价)
{
- var r = InterestLegStrategyFactory.Get(mode)
+ var r = FundingLegStrategyFactory.Get(mode)
.CalcNotional(position.InterestPrincipalFix, posiNotional, posiLong, posiShort, closePercent);
return (r.ClosePrincipal, r.PosiPrincipal, r.ClosePercent);
}