From 313dade65b5ead1b19b9243fd04a026b033780d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=86=B0=E5=86=B0?= <437394478@qq.com> Date: Wed, 26 Aug 2026 21:21:55 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BB=93=E7=AE=97=E5=8D=95=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E5=87=80=E9=A2=9D=E7=BB=93=E7=AE=97=E9=87=91=E9=A2=9D?= =?UTF-8?q?=E7=9A=84=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TradeSettleBillGenerator.cs | 6 +++++ .../SwapSettlementBillRowBuilder.cs | 25 ++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs b/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs index 7d851a7f..53d448db 100644 --- a/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs +++ b/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs @@ -74,6 +74,11 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator var underlying = Context.GetTradeUnderlying(flowEventGroup.UnderlyingCode); var closeNotionalValue = unwindData?.CloseNotionalValue ?? flowEventGroup.Quantity * flowEventGroup.ContractSize * posi.PosiGrossPrice; + var settlementDate = flowEventGroup.UnwindDate + ?? throw new ServiceException($"平仓事件{flowEventGroup.id}缺少结算日"); + var currentDayFloatingDividend = Context.GetEodPositions(tradeId, settlementDate) + .FirstOrDefault(x => x.PositionId == flowEventGroup.PositionId) + ?.TdPosiDividend ?? 0m; // 行构造器统一处理客户视角、结算公式、品种差异和模板展示精度。 var row = SwapSettlementBillRowBuilder.Build(new SwapSettlementBillRowInput @@ -86,6 +91,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator Positions = positions, UnderlyingInstrumentType = underlying?.UnderlyingInstrumentType, CloseNotionalValue = closeNotionalValue, + CurrentDayFloatingDividend = currentDayFloatingDividend, ExitYtm = unwindData?.FlowEvents? .FirstOrDefault(x => x.PositionType > 0)?.ExitYtm, IncludePeriodPaymentInNetting = (tradeExtend?.ExtendObj?.DividendPayDate ?? 1) == 0 diff --git a/YLErpDAL/Modules/TradeModule/DocGenerateModule/SwapSettlementBillRowBuilder.cs b/YLErpDAL/Modules/TradeModule/DocGenerateModule/SwapSettlementBillRowBuilder.cs index 45a8497e..36fe722e 100644 --- a/YLErpDAL/Modules/TradeModule/DocGenerateModule/SwapSettlementBillRowBuilder.cs +++ b/YLErpDAL/Modules/TradeModule/DocGenerateModule/SwapSettlementBillRowBuilder.cs @@ -9,7 +9,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule; /// /// 构造普通收益互换结算单单行数据所需的业务输入。 -/// 数据均来自平仓事件及其关联交易,避免依赖平仓后可能已不存在的日终持仓。 +/// 数据来自平仓事件、关联交易及结算日日终持仓。 /// public sealed class SwapSettlementBillRowInput { @@ -40,6 +40,9 @@ public sealed class SwapSettlementBillRowInput /// 平仓事件浮动腿记录的期末结算收益率(展示态数值)。 public decimal? ExitYtm { get; set; } + /// 结算日日终持仓中的当日浮动端分红,保留原始收付方向。 + public decimal CurrentDayFloatingDividend { get; set; } + /// 期间付息或分红是否计入本次净额结算。 public bool IncludePeriodPaymentInNetting { get; set; } } @@ -87,25 +90,19 @@ public static class SwapSettlementBillRowBuilder var floatingAmount = -input.CloseFlow.MarkClosePnl; var fee = -(input.CloseFlow.TradingFee + input.CloseFlow.TradingFeePending); var marginInterest = -marginEvents.Sum(x => x.InterestClosePnL); - var periodAmount = -input.CloseFlow.DividendIn; var initialMargin = SumMargin(effectiveMargins, InterestModeEnum.初始预付金); var additionalMargin = SumMargin(effectiveMargins, InterestModeEnum.追加预付金); - var marginBackAmount = marginEvents.Sum(x => x.InterestPrincipal); - // 沿用原结算单口径:全部事件利息、浮动盈亏和预付金返还本金参与净额结算。 + // 净额结算仅包含全部事件利息和浮动盈亏,不包含预付金返还本金。 var netSettlementAmount = -eventFlows.Sum(x => x.InterestClosePnL) - - input.CloseFlow.FloatPnlSum - + marginBackAmount; + - input.CloseFlow.FloatPnlSum; var maturitySettlementAmount = netSettlementAmount + initialMargin + additionalMargin; var floatRateAbs = input.CloseNotionalValue == 0m ? 0m : interestAmount / input.CloseNotionalValue; - // 同一数据库字段在模板中按标的类型拆分:现券展示期间付息,ETF 展示期间分红。 + // 日终持仓的当日浮动端分红按标的类型拆分:债券展示期间付息,非债券展示期间分红。 var isCashBond = ConsGlobal.InstrumentType.IsBond(input.UnderlyingInstrumentType); - var isEtf = ConsGlobal.InstrumentType.Fund.Equals( - input.UnderlyingInstrumentType, - StringComparison.OrdinalIgnoreCase); // 此处集中完成模板字段映射和展示精度处理,生成器只负责组装原始业务数据。 return new ExcelReportModel @@ -120,8 +117,12 @@ public static class SwapSettlementBillRowBuilder InterestRate = interestEvents.Sum(x => x.InterestRate).ToString("0.00%"), PosiNotionalValue = input.CloseNotionalValue.ToString("0.00"), Quantity = input.CloseFlow.Quantity.ToString("0.00"), - DividendIn = periodAmount.ToString("0.00"), - PeriodDividend = isEtf ? periodAmount.ToString("0.00") : string.Empty, + DividendIn = isCashBond + ? input.CurrentDayFloatingDividend.ToString("0.00") + : string.Empty, + PeriodDividend = isCashBond + ? string.Empty + : input.CurrentDayFloatingDividend.ToString("0.00"), PosiNetPrice = ((settlementPosition?.PosiGrossPrice ?? 0m) * 100m).ToString("0.00000000"), InitYtm = isCashBond && input.Trade.InitYtm.HasValue ? input.Trade.InitYtm.Value.ToString("0.####%")