diff --git a/Framework/YLErp.Core/DBModels/EodSwap.cs b/Framework/YLErp.Core/DBModels/EodSwap.cs index 783f0ccc..9c058366 100644 --- a/Framework/YLErp.Core/DBModels/EodSwap.cs +++ b/Framework/YLErp.Core/DBModels/EodSwap.cs @@ -179,6 +179,26 @@ namespace YLErp.DBModels public decimal PeriodAmount { get; set; } + /// + /// 合约浮动端待实现收益,不包含期间付息/分红 + /// + public decimal FloatingUnrealizedPnl { get; set; } + + /// + /// 付息方式 + /// + public string InterestPaymentMethod { get; set; } + + /// + /// 合约估值(到期轧差口径) + /// + public decimal? MaturityNettingValuation { get; set; } + + /// + /// 合约估值(期间支付派息口径) + /// + public decimal? PeriodPaymentValuation { get; set; } + public decimal MarginInterestGain { get; set; } public decimal MarginInterestLoss { get; set; } diff --git a/Framework/YLErp.Core/DBModels/EodSwapPositionResponse.cs b/Framework/YLErp.Core/DBModels/EodSwapPositionResponse.cs index 18533989..18caa892 100644 --- a/Framework/YLErp.Core/DBModels/EodSwapPositionResponse.cs +++ b/Framework/YLErp.Core/DBModels/EodSwapPositionResponse.cs @@ -36,6 +36,14 @@ namespace YLErp.DBModels /// 期间付息 /// public decimal PeriodAmount { get; set; } + /// + /// 到期结算日 + /// + public DateTime? MaturitySettlementDate { get; set; } + /// + /// 期间分红 + /// + public decimal DividendAmount { get; set; } public decimal? InitYtm { get; set; } /// @@ -55,6 +63,10 @@ namespace YLErp.DBModels /// public decimal MarginInterestAmount { get; set; } /// + /// 追加预付金 取轧差 + /// + public decimal AdditionalMarginAmount { get; set; } + /// /// 浮动利率(绝对)利率端待实现收益/(标的名义金额/期初标的交割价格全价) /// public decimal FloatRateAbs { get; set; } @@ -71,6 +83,10 @@ namespace YLErp.DBModels /// public decimal NetSettmentAmount { get; set; } /// + /// TRS估值 + /// + public decimal TrsValue { get; set; } + /// /// 交易费用 /// public decimal TradingFee { get; set; } diff --git a/YLErpDAL/Model/ClientSwapPositionRequest.cs b/YLErpDAL/Model/ClientSwapPositionRequest.cs index c4883a06..7922a490 100644 --- a/YLErpDAL/Model/ClientSwapPositionRequest.cs +++ b/YLErpDAL/Model/ClientSwapPositionRequest.cs @@ -20,6 +20,7 @@ namespace YLErp.Model public DateTime? ValueDate { get; set; } public DateTime? ValueDateFrom { get; set; } public int? ClientId { get; set; } + public int? BookId { get; set; } public string StructureType { get; set; } } diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 319666ef..37989e5d 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1902,8 +1902,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.NotionalValueLong = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue); - eod_Swap.NotionalValueShort = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue); - eod_Swap.NotionalValue = eod_Swap.NotionalValueLong + eod_Swap.NotionalValueShort; + eod_Swap.NotionalValueShort = -Math.Abs(positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue)); + eod_Swap.NotionalValue = Convert.ToDecimal(td.OriginalStockEqvNotional ?? td.StockEqvNotional); eod_Swap.SwapTradeId = td.id; eod_Swap.SwapTradeNo = td.TradeNumber; eod_Swap.ClientId = td.ClientId; @@ -1972,9 +1972,9 @@ namespace YLErp.Modules.SwapModule var eodSwapPositions = DbContext.eod_swap_position.Where(x => x.SwapTradeId == td.id && x.ValueDate == settleDate && !x.Invalid).ToList(); var interestPositions = eodSwapPositions.Where(x => string.IsNullOrEmpty(x.UnderlyingCode)).ToList();//利息腿 var positions = eodSwapPositions.Where(x => !string.IsNullOrEmpty(x.UnderlyingCode)).ToList();//持仓腿 - eod_Swap.NotionalValue = Convert.ToDecimal(td.StockEqvNotional); + eod_Swap.NotionalValue = Convert.ToDecimal(td.OriginalStockEqvNotional ?? td.StockEqvNotional); eod_Swap.NotionalValueLong = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue); - eod_Swap.NotionalValueShort = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue); + eod_Swap.NotionalValueShort = -Math.Abs(positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue)); 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); @@ -2164,13 +2164,23 @@ namespace YLErp.Modules.SwapModule var retListResult = query.ToSearchList(req); var tradeIds = retListResult.rows.Select(x => x.position.SwapTradeId).Distinct().ToList(); var valueDates = retListResult.rows.Select(x => x.position.ValueDate).Distinct().ToList(); + var tradeNotionals = DbContext.trade + .Where(x => tradeIds.Contains(x.id)) + .Select(x => new { x.id, x.OriginalStockEqvNotional, x.StockEqvNotional }) + .ToDictionary(x => x.id); var eodPositionDetails = DbContext.eod_swap_position .Where(x => tradeIds.Contains(x.SwapTradeId) && valueDates.Contains(x.ValueDate) && !x.Invalid) .ToList(); + var tradeExtends = DbContext.trade_extend.Where(x => tradeIds.Contains(x.TradeId)).ToList(); var underlyingDataSource = DataCacheProvider.GetUnderlyingDataSource(); var varietyDataSource = DataCacheProvider.GetVarietyDataSource(); foreach (var item in retListResult.rows) { + item.position.NotionalValueShort = -Math.Abs(item.position.NotionalValueShort); + if (tradeNotionals.TryGetValue(item.position.SwapTradeId, out var tradeNotional)) + { + item.position.NotionalValue = Convert.ToDecimal(tradeNotional.OriginalStockEqvNotional ?? tradeNotional.StockEqvNotional); + } var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId); item.SwapTradeTypeStr = client?.SwapTradeTypeStr; var details = eodPositionDetails @@ -2178,6 +2188,8 @@ namespace YLErp.Modules.SwapModule .ToList(); var floatingLegs = details.Where(x => !string.IsNullOrEmpty(x.UnderlyingCode)).ToList(); var marginLegs = details.Where(x => marginTypes.Contains(x.InterestMode)).ToList(); + var tradeExtend = tradeExtends.FirstOrDefault(x => x.TradeId == item.position.SwapTradeId); + var dividendPayDate = tradeExtend?.ExtendObj?.DividendPayDate ?? 1; item.UnderlyingType = string.Join(",", floatingLegs .Select(x => @@ -2189,7 +2201,17 @@ namespace YLErp.Modules.SwapModule }) .Where(x => !string.IsNullOrWhiteSpace(x)) .Distinct()); - item.PeriodAmount = floatingLegs.Sum(x => x.PosiDividendSum); // 分红 - 为实现 + item.PeriodAmount = floatingLegs.Sum(x => x.RealizedDividend + x.PosiDividendSum); + item.FloatingUnrealizedPnl = floatingLegs.Sum(x => x.PosiMtmPnL); + item.InterestPaymentMethod = dividendPayDate == 0 ? "到期轧差" : "派息日支付"; + if (dividendPayDate == 0) + { + item.MaturityNettingValuation = item.FloatingUnrealizedPnl + item.position.InterestPnL + item.PeriodAmount; + } + else + { + item.PeriodPaymentValuation = item.FloatingUnrealizedPnl + item.position.InterestPnL; + } item.MarginInterestGain = marginLegs .Where(x => x.InterestDirection == (int)SwapDirectionEnum.收取) .Sum(x => Math.Abs(x.InterestIncomeSum)); @@ -2340,6 +2362,10 @@ namespace YLErp.Modules.SwapModule { predicate = predicate.And(x => x.ClientId == req.ClientId); } + if (req.BookId > 0) + { + tradePredicate = tradePredicate.And(x => x.AssetId == req.BookId.Value); + } if (req.ValueDateFrom != null) { predicate = predicate.And(x => x.ValueDate >= req.ValueDateFrom); @@ -2373,8 +2399,13 @@ namespace YLErp.Modules.SwapModule } var retListResult = query.ToSearchList(req); var tradeIds = retListResult.rows.Select(s => s.position.SwapTradeId).ToList(); + if (!tradeIds.Any()) + { + return retListResult; + } interestPredicate = interestPredicate.And(x => tradeIds.Contains(x.SwapTradeId)); var valueDates = retListResult.rows.Select(s => s.position.ValueDate).Distinct().ToList(); + interestPredicate = interestPredicate.And(x => valueDates.Contains(x.ValueDate)); var eodPositions = DbContext.eod_swap_position.Where(interestPredicate).ToList(); var positions = DbContext.swap_position.Where(x => tradeIds.Contains(x.SwapTradeId) && x.InterestMode == (int)InterestModeEnum.初始预付金 && x.IsInitial && !x.Invalid).ToList(); var tradeExtends = DbContext.trade_extend.Where(x => tradeIds.Contains(x.TradeId)).ToList(); @@ -2386,6 +2417,14 @@ namespace YLErp.Modules.SwapModule if (tradeExtend != null) { eventDate = QdpCalendarHelper.GetNonHoliday(eventDate.AddDays(tradeExtend.ExtendObj.SettlementRules)); + if (item.position.PosiMatuirityDate.HasValue) + { + item.MaturitySettlementDate = QdpCalendarHelper.GetNonHoliday(item.position.PosiMatuirityDate.Value.AddDays(tradeExtend.ExtendObj.SettlementRules)); + } + } + else + { + item.MaturitySettlementDate = item.position.PosiMatuirityDate; } item.DayCount = Math.Max(0, (eventDate - item.position.PosiStartDate).Days + 1); //item.position.PosiProfitSum += item.position.VTradingFee-item.position.PosiFeePending; @@ -2393,23 +2432,41 @@ namespace YLErp.Modules.SwapModule //item.position.PosiProfitSum += item.TradingFee; var posiProfitSum = item.position.PosiProfitSum; //item.position.PosiProfitSum 不需要加交易费用 - item.position.PosiProfitSum = item.position.PosiProfitSum - item.position.PosiFeePending - item.position.PosiDividendSum; - item.NetSettmentAmount = item.position.PosiProfitSum + item.position.PosiDividendSum + item.position.PosiFeePending; - item.PeriodAmount = item.position.PosiDividendSum; + var pendingDividend = item.position.PosiDividendSum; + item.position.PosiProfitSum = item.position.PosiProfitSum - item.position.PosiFeePending - pendingDividend; + if (ConsGlobal.InstrumentType.IsBond(item.position.UnderlyingInstrumentType)) + { + item.PeriodAmount = pendingDividend; + item.DividendAmount = 0; + } + else + { + item.PeriodAmount = 0; + item.DividendAmount = pendingDividend; + } + item.NetSettmentAmount = item.position.PosiProfitSum + item.PeriodAmount + item.DividendAmount + item.position.PosiFeePending; var margins = positions.Where(x => x.SwapTradeId == item.position.SwapTradeId); var interests = eodPositions.Where(x => x.SwapTradeId == item.position.SwapTradeId && x.ValueDate == item.position.ValueDate); var eodMargins = interests.Where(x => marginTypes.Contains(x.InterestMode)); var eodInterests = interests.Where(x => !marginTypes.Contains(x.InterestMode)); + var initialMargins = eodMargins.Where(x => x.InterestMode == (int)InterestModeEnum.初始预付金); + var additionalMargins = eodMargins.Where(x => x.InterestMode == (int)InterestModeEnum.追加预付金); var floatRateInterest = eodInterests.Where(x => !string.IsNullOrEmpty(x.FloatRateUnderlyingCode)).FirstOrDefault(); item.position.FloatRateUnderlyingCode = floatRateInterest?.FloatRateUnderlyingCode; item.position.FloatRate = floatRateInterest?.FloatRate ?? 0; - item.OpenMarginAmount = margins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); - item.OpenMarginRate = margins.Sum(s => s.InterestRateDefault * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); + item.OpenMarginAmount = initialMargins.Any() + ? initialMargins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)) + : margins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); + item.OpenMarginRate = initialMargins.Any() + ? initialMargins.Sum(s => s.InterestRateDefault * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)) + : margins.Sum(s => s.InterestRateDefault * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); + item.AdditionalMarginAmount = additionalMargins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); item.MarginInterestAmount = eodMargins.Sum(s => s.InterestIncomeSum * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); item.InterestAmount = eodInterests.Sum(s => s.InterestIncomeSum * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? -1 : 1)); item.InterestRate = eodInterests.Sum(s => s.InterestRateDefault); - item.NetSettmentAmount += item.InterestAmount + item.MarginInterestAmount + eodMargins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); + item.NetSettmentAmount += item.InterestAmount + item.MarginInterestAmount; item.NetSettmentAmount = Math.Round(item.NetSettmentAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + item.TrsValue = Math.Round(item.NetSettmentAmount + item.OpenMarginAmount + item.AdditionalMarginAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); if (item.position.PosiNotionalValue != 0 && item.position.PosiNetPrice != 0) { item.FloatRateAbs = item.position.PosiNotionalValue == 0 ? 0 : item.InterestAmount / item.position.PosiNotionalValue; diff --git a/YLErpWeb/Views/SwapTrade2/TradeMarketReport_EodPosition.cshtml b/YLErpWeb/Views/SwapTrade2/TradeMarketReport_EodPosition.cshtml index 1429aaec..8cfa8006 100644 --- a/YLErpWeb/Views/SwapTrade2/TradeMarketReport_EodPosition.cshtml +++ b/YLErpWeb/Views/SwapTrade2/TradeMarketReport_EodPosition.cshtml @@ -39,6 +39,7 @@ } @section JS{ +