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);