From 963f7a04e587c17da7734338ff5a0d1961dc9695 Mon Sep 17 00:00:00 2001 From: hjhan Date: Tue, 11 Aug 2026 11:04:08 +0800 Subject: [PATCH] =?UTF-8?q?refactor(return-leg):=20=E6=96=B0=E5=A2=9E=20Di?= =?UTF-8?q?videndCalc=20=E5=88=86=E7=BA=A2=E5=A2=9E=E5=80=BC=E7=A8=8E?= =?UTF-8?q?=E5=90=8E=E8=AE=A1=E7=AE=97=20+=20=E4=BF=AE=E5=A4=8D=20MtmCalc?= =?UTF-8?q?=20=E5=8F=82=E6=95=B0=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DividendCalc: 增值税后票息 = payment/(1+tax)*(1-tax), 原 SwapEodPositionService 4处重复此公式(1804/1894/1906/2095)。 本次先建纯函数+测试, 4处inline替换下次做。 附带修复: MtmCalc shortRatio 参数从 decimal 改为 int (原代码6处声明中5处是int, 仅1696是decimal, 统一为int)。 1696行 shortRatio 声明同步改为 int。 验证: 编译0错误, DividendCalc 4个测试全过, 全量507测试7失败(基线一致)。 --- .../SwapModule/ReturnLegs/DividendCalcTest.cs | 37 +++++++++++++++++++ .../SwapModule/ReturnLegs/DividendCalc.cs | 18 +++++++++ .../Modules/SwapModule/ReturnLegs/MtmCalc.cs | 4 +- .../SwapModule/SwapEodPositionService.cs | 2 +- 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 UnitTestProject/Modules/SwapModule/ReturnLegs/DividendCalcTest.cs create mode 100644 YLErpDAL/Modules/SwapModule/ReturnLegs/DividendCalc.cs diff --git a/UnitTestProject/Modules/SwapModule/ReturnLegs/DividendCalcTest.cs b/UnitTestProject/Modules/SwapModule/ReturnLegs/DividendCalcTest.cs new file mode 100644 index 00000000..20a842ad --- /dev/null +++ b/UnitTestProject/Modules/SwapModule/ReturnLegs/DividendCalcTest.cs @@ -0,0 +1,37 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using YLErp.Modules.SwapModule.ReturnLegs; + +namespace UnitTestProject.Modules.SwapModule.ReturnLegs +{ + [TestClass] + public class DividendCalcTest + { + [TestMethod] + public void AfterTax_零税率_等于原值() + { + Assert.AreEqual(1000m, DividendCalc.AfterTax(1000m, 0m)); + } + + [TestMethod] + public void AfterTax_6pct增值税() + { + // 1000 / 1.06 * 0.94 = 886.79... + Assert.AreEqual(886.79m, DividendCalc.AfterTax(1000m, 0.06m)); + } + + [TestMethod] + public void AfterTax_负票息() + { + // -500 / 1.06 * 0.94 = -443.40 + Assert.AreEqual(-443.40m, DividendCalc.AfterTax(-500m, 0.06m)); + } + + [TestMethod] + public void AfterTaxRaw_不四舍五入() + { + var raw = DividendCalc.AfterTaxRaw(1000m, 0.06m); + Assert.AreNotEqual(886.79m, raw, "Raw 版本不四舍五入"); + Assert.IsTrue(raw > 886.79m && raw < 886.80m); + } + } +} diff --git a/YLErpDAL/Modules/SwapModule/ReturnLegs/DividendCalc.cs b/YLErpDAL/Modules/SwapModule/ReturnLegs/DividendCalc.cs new file mode 100644 index 00000000..1b9f898f --- /dev/null +++ b/YLErpDAL/Modules/SwapModule/ReturnLegs/DividendCalc.cs @@ -0,0 +1,18 @@ +namespace YLErp.Modules.SwapModule.ReturnLegs; + +/// +/// 标的端分红(票息)计算。 +/// +/// 增值税后票息 = 税前票息 / (1+税率) × (1-税率) +/// 原代码在 SwapEodPositionService 4处重复此公式(1804/1894/1906/2095)。 +/// +public static class DividendCalc +{ + /// 增值税后票息,四舍五入到 2 位。 + public static decimal AfterTax(decimal payment, decimal tax) + => Math.Round(payment / (1 + tax) * (1 - tax), 2); + + /// 增值税后票息(不四舍五入,供中间计算用)。 + public static decimal AfterTaxRaw(decimal payment, decimal tax) + => payment / (1 + tax) * (1 - tax); +} diff --git a/YLErpDAL/Modules/SwapModule/ReturnLegs/MtmCalc.cs b/YLErpDAL/Modules/SwapModule/ReturnLegs/MtmCalc.cs index 482fbe90..82701e11 100644 --- a/YLErpDAL/Modules/SwapModule/ReturnLegs/MtmCalc.cs +++ b/YLErpDAL/Modules/SwapModule/ReturnLegs/MtmCalc.cs @@ -10,11 +10,13 @@ namespace YLErp.Modules.SwapModule.ReturnLegs; /// public static class MtmCalc { - /// 标的市值。多头为正、空头为负。 + /// 标的市值。多头为正、空头为负。shortRatio: 多头=1, 空头=-1。 public static decimal MarketValue(decimal price, decimal qty, decimal contractSize, int shortRatio) => price * qty * contractSize * shortRatio; /// 盯市未实现盈亏 = (标的价 - 成本全价) × 数量 × 合约乘数 × 多空 × 收付。 + /// 多头=1, 空头=-1。 + /// 收取=1, 支付=-1。 public static decimal UnrealizedPnl(decimal price, decimal costGrossPrice, decimal qty, decimal contractSize, int shortRatio, decimal ratio) => (price - costGrossPrice) * qty * contractSize * shortRatio * ratio; } diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index af4a85bc..5a4b46e8 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1693,7 +1693,7 @@ namespace YLErp.Modules.SwapModule { payQty = Math.Abs(payQty); decimal ratio = eventFlow.PayDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负 - decimal shortRatio = newEodPayPosition.PositionType == (int)PositionTypeFlag.Long ? 1 : -1;//多空方向 + int shortRatio = newEodPayPosition.PositionType == (int)PositionTypeFlag.Long ? 1 : -1;//多空方向 newEodPayPosition.ValueDate = eventFlow.PayDate.Value; newEodPayPosition.PositionId = eventFlow.PositionId; newEodPayPosition.ClientId = td.ClientId;