diff --git a/UnitTestProject/Modules/SwapModule/ReturnLegs/PositionValueCalcTest.cs b/UnitTestProject/Modules/SwapModule/ReturnLegs/PositionValueCalcTest.cs
new file mode 100644
index 00000000..d65db05d
--- /dev/null
+++ b/UnitTestProject/Modules/SwapModule/ReturnLegs/PositionValueCalcTest.cs
@@ -0,0 +1,25 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using YLErp.Modules.SwapModule.ReturnLegs;
+
+namespace UnitTestProject.Modules.SwapModule.ReturnLegs
+{
+ [TestClass]
+ public class PositionValueCalcTest
+ {
+ [TestMethod]
+ public void 无方向因子_利息加浮动()
+ => Assert.AreEqual(1500m, PositionValueCalc.Calc(1000m, 500m));
+
+ [TestMethod]
+ public void 收取方向_利息乘1()
+ => Assert.AreEqual(1500m, PositionValueCalc.Calc(1000m, 500m, 1m));
+
+ [TestMethod]
+ public void 支付方向_利息乘负1()
+ => Assert.AreEqual(-500m, PositionValueCalc.Calc(1000m, 500m, -1m));
+
+ [TestMethod]
+ public void 零利息_等于浮动端()
+ => Assert.AreEqual(500m, PositionValueCalc.Calc(0m, 500m));
+ }
+}
diff --git a/YLErpDAL/Modules/SwapModule/ReturnLegs/PositionValueCalc.cs b/YLErpDAL/Modules/SwapModule/ReturnLegs/PositionValueCalc.cs
new file mode 100644
index 00000000..dd4a4d2d
--- /dev/null
+++ b/YLErpDAL/Modules/SwapModule/ReturnLegs/PositionValueCalc.cs
@@ -0,0 +1,15 @@
+namespace YLErp.Modules.SwapModule.ReturnLegs;
+
+///
+/// 持仓价值(SwapPositionValue)汇总。
+///
+/// SwapPositionValue = 利息端收益 + 浮动端收益。
+/// 利息端可能带方向因子(收取/支付),浮动端不含方向因子。
+/// 原代码在 SwapEodPositionService 8处重复此公式(1115/1258/1519/1647/1746/1830/1938/2113)。
+///
+public static class PositionValueCalc
+{
+ /// 持仓价值 = 利息端 × 方向因子 + 浮动端。
+ public static decimal Calc(decimal interestProfitSum, decimal posiProfitSum, decimal ratio = 1m)
+ => interestProfitSum * ratio + posiProfitSum;
+}
diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
index 4aa6adc0..9d5f345b 100644
--- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
+++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
@@ -1112,7 +1112,7 @@ namespace YLErp.Modules.SwapModule
}
newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum;
//持仓价值
- newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
+ newEodPayPosition.SwapPositionValue = PositionValueCalc.Calc(newEodPayPosition.InterestProfitSum, newEodPayPosition.PosiProfitSum, ratio);
//累计已实现
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio;
@@ -1255,7 +1255,7 @@ namespace YLErp.Modules.SwapModule
: RoundEodInterest(eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee);
newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum;
//持仓价值
- newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
+ newEodPayPosition.SwapPositionValue = PositionValueCalc.Calc(newEodPayPosition.InterestProfitSum, newEodPayPosition.PosiProfitSum, ratio);
//累计已实现
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio;
@@ -1516,7 +1516,7 @@ namespace YLErp.Modules.SwapModule
// InterestProfitSum 是利息腿待实现总额,包含利息和费用;无费用时等于 InterestIncomeSum。
newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum;
//持仓价值
- newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
+ newEodPayPosition.SwapPositionValue = PositionValueCalc.Calc(newEodPayPosition.InterestProfitSum, newEodPayPosition.PosiProfitSum, ratio);
Log.Info($"InterestIncomeSum is {eodPayPosition.InterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" +
$",TdCloseInterest is {newEodPayPosition.TdCloseInterest}");
@@ -1644,7 +1644,7 @@ namespace YLErp.Modules.SwapModule
newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee;
newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum;
//持仓价值
- newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
+ newEodPayPosition.SwapPositionValue = PositionValueCalc.Calc(newEodPayPosition.InterestProfitSum, newEodPayPosition.PosiProfitSum, ratio);
//累计已实现
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio;
@@ -1743,7 +1743,7 @@ namespace YLErp.Modules.SwapModule
newEodPayPosition.PosiProfitSum = newEodPayPosition.PosiMtmPnL + newEodPayPosition.PosiDividendSum + newEodPayPosition.PosiFeePending;
//持仓价值
- newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum + newEodPayPosition.PosiProfitSum;
+ newEodPayPosition.SwapPositionValue = PositionValueCalc.Calc(newEodPayPosition.InterestProfitSum, newEodPayPosition.PosiProfitSum);
//累计已实现
newEodPayPosition.RealizedFee = closeFee;
newEodPayPosition.RealizedMtmPnL = newEodPayPosition.TdCloseMtmPnl;
@@ -1827,7 +1827,7 @@ namespace YLErp.Modules.SwapModule
, seekPreday: true, currencyRateType: curretEod.PosiDirection == (int)SwapDirectionEnum.收取 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
curretEod.TdCurrency = Convert.ToDecimal(currencyRate);
//持仓价值
- curretEod.SwapPositionValue = curretEod.InterestProfitSum + curretEod.PosiProfitSum;
+ curretEod.SwapPositionValue = PositionValueCalc.Calc(curretEod.InterestProfitSum, curretEod.PosiProfitSum);
UpdateDbOption(curretEod);
curretEod.Invalid = false;
if (curretEod.id == 0)
@@ -1935,7 +1935,7 @@ namespace YLErp.Modules.SwapModule
, seekPreday: true, currencyRateType: curretEod.PosiDirection == (int)SwapDirectionEnum.收取 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
curretEod.TdCurrency = Convert.ToDecimal(currencyRate);
//持仓价值
- curretEod.SwapPositionValue = curretEod.InterestProfitSum + curretEod.PosiProfitSum;
+ curretEod.SwapPositionValue = PositionValueCalc.Calc(curretEod.InterestProfitSum, curretEod.PosiProfitSum);
UpdateDbOption(curretEod);
curretEod.Invalid = false;
if (curretEod.id == 0)
@@ -2110,7 +2110,7 @@ namespace YLErp.Modules.SwapModule
curretEod.PosiNotionalValue = 0;
}
//持仓价值
- curretEod.SwapPositionValue = curretEod.InterestProfitSum + curretEod.PosiProfitSum;
+ curretEod.SwapPositionValue = PositionValueCalc.Calc(curretEod.InterestProfitSum, curretEod.PosiProfitSum);
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.StartDate.Value
, seekPreday: true, currencyRateType: curretEod.PosiDirection == (int)SwapDirectionEnum.收取 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
curretEod.TdCurrency = Convert.ToDecimal(currencyRate);