public static List<BDGainLoss> ComputeBdGainLoss(List<Position> positionsBegin, List<Position> positionsEnd, List<IncomeRealUnrealGain> realUnrealGain, List<IncomeEarnedIncome> earnedIncomes, List<IncomeFee> fees, List<IncomeDividend> dividends) { var positionsEndDict = positionsEnd.ToDictionary(p => p.Position_ID, p => p); var positionRealUnrealGain = realUnrealGain.ToDictionary(p => p.Position_ID, p => p); var positionFeeIncomes = fees .GroupBy(f => f.Position_ID) .ToDictionary(g => g.Key, g => new { AmortizedFee = g.Sum(f => f.AmortizedFeeRC ?? 0), TranIncomeAmount = g.Sum(f => f.TranIncome_AmountRC) }); var positionDividendIncomes = dividends .GroupBy(d => d.Position_ID) .ToDictionary(g => g.Key, g => new { Dividend_Amount = g.Sum(d => d.TranAll_AmountRC ?? 0) }); var positionEarnedIncomes = earnedIncomes.ToDictionary( ei => ei.Position_ID, ei => new { EarnedInterestRC = ei.EarnedInterestRC ?? 0, EarnedFeesRC = ei.EarnedFeesRC ?? 0 }); const double threshold = 0.5; return positionsBegin.Select(positionBegin => { var positionEnd = positionsEndDict.GetValueOrDefault(positionBegin.Position_ID, new Position()); var positionDividendIncome = positionDividendIncomes.GetValueOrDefault(positionBegin.Position_ID, new { Dividend_Amount = 0d }); var positionFeeIncome = positionFeeIncomes.GetValueOrDefault(positionBegin.Position_ID, new { AmortizedFee = 0d, TranIncomeAmount = 0d }); var positionEarnedIncome = positionEarnedIncomes.GetValueOrDefault(positionBegin.Position_ID, new { EarnedInterestRC = 0d, EarnedFeesRC = 0d }); const int liabilityPortfolioTypeId = 3; var (beginAccruedIncome, endAccruedIncome, earnedIncome) = positionBegin.Portfolio_PortfolioType_ID switch { liabilityPortfolioTypeId => ( -positionBegin.AccruedIncomeRC, -positionEnd.AccruedIncomeRC, -positionEarnedIncome.EarnedInterestRC + positionEarnedIncome.EarnedFeesRC ), _ => ( positionBegin.AccruedIncomeRC, positionEnd.AccruedIncomeRC, positionEarnedIncome.EarnedInterestRC + positionEarnedIncome.EarnedFeesRC ), }; var positionRealizedUnrealizedGain = positionRealUnrealGain.GetValueOrDefault(positionBegin.Position_ID, new IncomeRealUnrealGain()); var marketValueAccruedIncomeBegin = positionBegin.MarketValueRC + beginAccruedIncome; var marketValueAccruedIncomeEnd = positionEnd.MarketValueRC + endAccruedIncome; var gainLoss = positionRealizedUnrealizedGain.RealGainsMVInPeriodRC + positionRealizedUnrealizedGain.UnrealGainsMVInPeriodRC; var interest = earnedIncome + positionFeeIncome.AmortizedFee + positionFeeIncome.TranIncomeAmount + positionDividendIncome.Dividend_Amount; var totalGain = gainLoss + interest; return new BDGainLoss { Position_ID = positionBegin.Position_ID, StartDate = positionBegin.AsOfDate, EndDate = positionEnd.AsOfDate, Begin_AmountRC = positionRealizedUnrealizedGain.AmountBeginRC, End_AmountRC = positionRealizedUnrealizedGain.AmountEndRC, Begin_Quantity = positionRealizedUnrealizedGain.QuantityBegin, End_Quantity = positionRealizedUnrealizedGain.QuantityEnd, WeightedAverageMVPrice = positionRealizedUnrealizedGain.WeightedAverageMVPrice, WeightedAvgFXRate = positionRealizedUnrealizedGain.WeightedAvgFXRate, MarkEndPrice = positionRealizedUnrealizedGain.MarkEndPrice, FXEndRate = positionRealizedUnrealizedGain.FXEndRate, FXStartRate = positionRealizedUnrealizedGain.FXStartRate, RealGainsMVInPeriodRC = positionRealizedUnrealizedGain.RealGainsMVInPeriodRC, UnrealGainsMVInPeriodRC = positionRealizedUnrealizedGain.UnrealGainsMVInPeriodRC, UnrealGainsMVInPeriodFXFluctRC = positionRealizedUnrealizedGain.UnrealGainsMVInPeriodFXFluctRC, UnrealGainsMVInPeriodMVFluctRC = positionRealizedUnrealizedGain.UnrealGainsMVInPeriodMVFluctRC, RealGainsInPeriodFXFluctRC = positionRealizedUnrealizedGain.RealGainsInPeriodFXFluctRC, RealGainsInPeriodMVFluctRC = positionRealizedUnrealizedGain.RealGainsInPeriodMVFluctRC, DispositionInPeriod = positionRealizedUnrealizedGain.DispositionInPeriod, DateType = positionRealizedUnrealizedGain.DateType, AssetTypes = positionRealizedUnrealizedGain.AssetTypes, MarkBy = positionRealizedUnrealizedGain.MarkBy, MarkType = positionRealizedUnrealizedGain.MarkType, MarkLevel = positionRealizedUnrealizedGain.MarkLevel, CostMethod = positionRealizedUnrealizedGain.CostMethod, AmortizationMethod = positionRealizedUnrealizedGain.AmortizationMethod, EarnSales = positionRealizedUnrealizedGain.EarnSales, CapitalizedCost = positionRealizedUnrealizedGain.CapitalizedCost, ExcludeSpecificLotAllocations = positionRealizedUnrealizedGain.ExcludeSpecificLotAllocations, BaseCurrency = positionRealizedUnrealizedGain.BaseCurrency, DateRecordCreated = DateTime.Now, Begin_MarketValueRC = positionBegin.MarketValueRC, End_MarketValueRC = positionEnd.MarketValueRC, Begin_AccruedIncomeRC = beginAccruedIncome, End_AccruedIncomeRC = endAccruedIncome, Portfolio_PortfolioType_ID = positionBegin.Portfolio_PortfolioType_ID, Portfolio_AbbrevName = positionBegin.Portfolio_AbbrevName, Issuer_Name = positionBegin.Issuer_Name, Asset_SecurityID = positionBegin.Asset_SecurityID, Asset_Name = positionBegin.Asset_Name, Asset_AssetType_Name = positionBegin.Asset_AssetType_Name, Asset_PriceFactor = positionBegin.Asset_PriceFactor, EarnedInterestRC = positionEarnedIncome.EarnedInterestRC, EarnedFeesRC = positionEarnedIncome.EarnedFeesRC, AmortizedFee = positionFeeIncome.AmortizedFee, Dividend_Amount = positionDividendIncome.Dividend_Amount, Portfolio_ID = positionBegin.Portfolio_ID, Issuer_ID = positionBegin.Issuer_ID, Asset_ID = positionBegin.Asset_ID, EarnedIncome = earnedIncome, Begin_MarketValueAccruedIncome = marketValueAccruedIncomeBegin, End_MarketValueAccruedIncome = marketValueAccruedIncomeEnd, GainLoss = gainLoss, Interest = interest, TotalGain = totalGain, MarkPrice_MarkPrice = positionBegin.MarkPrice_MarkPrice, MarkPrice_AskPrice = positionBegin.MarkPrice_AskPrice, MarkPrice_MarkDate = positionBegin.MarkPrice_MarkDate, MarkPrice_BidPrice = positionBegin.MarkPrice_BidPrice, MarkPrice_MarkSource = positionBegin.MarkPrice_MarkSource, OutstandingRC = positionBegin.OutstandingRC, BookValueRC = positionBegin.BookValueRC, BVPrice = positionBegin.BVPrice, Portfolio_UDF2 = positionBegin.Portfolio_UDF2, Portfolio_UDF1 = positionBegin.Portfolio_UDF1, Position_SubPortfolioLvl3 = positionBegin.Position_SubPortfolioLvl3, Position_PortfolioType = positionBegin.Position_PortfolioType, Position_AssetStrategy = positionBegin.Position_AssetStrategy, TranIncome_Amount = positionFeeIncome.TranIncomeAmount }; }).ToList();