diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index d4b14f00..ead71307 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -2168,8 +2168,6 @@ namespace YLErp.Modules.SwapModule var positions = eodSwapPositions.Where(x => !string.IsNullOrEmpty(x.UnderlyingCode)).ToList();//持仓腿 // 框架合约的方向约定:多头为正、空头为负;总名义本金取交易原始规模, // 不能直接用多空腿相加,否则会把对冲方向误当成合约规模变化。 - eod_Swap.NotionalValueLong = Math.Round(positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); - eod_Swap.NotionalValueShort = Math.Round(-Math.Abs(positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue)), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); eod_Swap.NotionalValue = Math.Round(Convert.ToDecimal(td.OriginalStockEqvNotional ?? td.StockEqvNotional), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); eod_Swap.SwapTradeId = td.id; eod_Swap.SwapTradeNo = td.TradeNumber; @@ -2177,19 +2175,8 @@ namespace YLErp.Modules.SwapModule eod_Swap.BookId = td.AssetId; eod_Swap.ValueDate = settleDate; eod_Swap.StructureType = td.StructureType; - eod_Swap.MarketValueLong = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.UnderlyingMarketValue); - eod_Swap.MarketValueShort = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.UnderlyingMarketValue); - eod_Swap.FloatingPnL = positions.Sum(s => s.PosiProfitSum); - eod_Swap.dv01 = positions.Sum(s => s.dv01 ?? 0); - decimal interestPnL = 0; - // 利息腿按我方视角归集。保证金腿的利息现金流方向与普通利息腿相反, - // 因此保证金腿需要额外反转符号,确保 InterestPnL 表示我方的合约利率端收益。 - interestPositions.ForEach(x => - { - var ratio = DirectionRatio.InterestLegPnl(x.InterestDirection, x.InterestMode); - interestPnL += x.InterestProfitSum * ratio; - }); - eod_Swap.InterestPnL = interestPnL; + FillPositionLegSummary(eod_Swap, positions); + eod_Swap.InterestPnL = SumInterestPnL(interestPositions); eod_Swap.PostionValue = eodSwapPositions.Sum(s => s.SwapPositionValue); // 保证金腿的利息现金流方向与保证金本金方向相反。 // 不能直接汇总 RealizedPnl,否则“收取客户保证金”的腿会把应支付给客户的 @@ -2242,17 +2229,8 @@ namespace YLErp.Modules.SwapModule var interestPositions = eodSwapPositions.Where(x => string.IsNullOrEmpty(x.UnderlyingCode)).ToList();//利息腿 var positions = eodSwapPositions.Where(x => !string.IsNullOrEmpty(x.UnderlyingCode)).ToList();//持仓腿 eod_Swap.NotionalValue = Math.Round(Convert.ToDecimal(td.OriginalStockEqvNotional ?? td.StockEqvNotional), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); - eod_Swap.NotionalValueLong = Math.Round(positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); - eod_Swap.NotionalValueShort = Math.Round(-Math.Abs(positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue)), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); - eod_Swap.MarketValueLong = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.UnderlyingMarketValue); - eod_Swap.MarketValueShort = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.UnderlyingMarketValue); - eod_Swap.FloatingPnL = positions.Sum(s => s.PosiProfitSum); - eod_Swap.dv01 = positions.Sum(s => s.dv01 ?? 0); - interestPositions.ForEach(x => - { - var ratio = DirectionRatio.InterestLegPnl(x.InterestDirection, x.InterestMode); - eod_Swap.InterestPnL += x.InterestProfitSum * ratio; - }); + FillPositionLegSummary(eod_Swap, positions); + eod_Swap.InterestPnL += SumInterestPnL(interestPositions); eodSwapPositions.ForEach(x => { var ratio = DirectionRatio.InterestLegPnl(x.InterestDirection, x.InterestMode); @@ -2260,7 +2238,6 @@ namespace YLErp.Modules.SwapModule }); eod_Swap.PostionValue = eodSwapPositions.Sum(s => s.SwapPositionValue); eod_Swap.RealizedPnL = eodSwapPositions.Sum(CalculateSwapRealizedPnl); - eod_Swap.TdCloseQty = positions.Sum(s => s.TdCloseQty); var tradeInitMarginObj = DbContext.trade_initial_margin.FirstOrDefault(x => x.TradeId == td.id); var initMarginList = interestPositions.Where(x => x.InterestMode == (int)InterestModeEnum.初始预付金 && x.HappenDate == settleDate).ToList(); var addMarginList = interestPositions.Where(x => x.InterestMode == (int)InterestModeEnum.追加预付金 && x.HappenDate == settleDate).ToList(); @@ -2290,6 +2267,28 @@ namespace YLErp.Modules.SwapModule + position.RealizedInterestFee; } + /// 填充框架合约的持仓腿汇总字段(多空名义本金/市值/浮动盈亏/dv01/平仓量)。 + /// SaveEodSwap 与 UpdateEodSwap 共用,消除 ~10 行重复。 + private static void FillPositionLegSummary(eod_swap eod_Swap, List positions) + { + eod_Swap.NotionalValueLong = Math.Round(positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + eod_Swap.NotionalValueShort = Math.Round(-Math.Abs(positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue)), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + eod_Swap.MarketValueLong = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.UnderlyingMarketValue); + eod_Swap.MarketValueShort = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.UnderlyingMarketValue); + eod_Swap.FloatingPnL = positions.Sum(s => s.PosiProfitSum); + eod_Swap.dv01 = positions.Sum(s => s.dv01 ?? 0); + eod_Swap.TdCloseQty = positions.Sum(s => s.TdCloseQty); + } + + /// 利息腿 PnL 汇总(按方向比例 + 保证金翻转)。原 SaveEodSwap/UpdateEodSwap 各一段 ForEach。 + private static decimal SumInterestPnL(List interestPositions) + { + decimal interestPnL = 0; + foreach (var x in interestPositions) + interestPnL += x.InterestProfitSum * DirectionRatio.InterestLegPnl(x.InterestDirection, x.InterestMode); + return interestPnL; + } + /// /// 风险报表符号归一化:把历史两种符号口径的 TdCloseInterest/RealizedInterest /// 统一按"绝对金额 × 业务方向"重写。普通利息腿收取为正、支付为负;