using BaseOUDAL; using YLErp.BLL; using YLErp.BLL.Eod; using YLErp.BLL.EodSettlement; using YLErp.Commons; using YLErp.Configuration; using YLErp.DBModels.Consts; using YLErp.DBModels.Enums; using YLErp.Model; using YLErp.Model.Enum; using YLErp.Model.FinancialVoucherCreator; using YLErp.Models.Tag; using YLErp.Modules.EodModule; using YLErp.Modules.MarketRiskMoudule; using YLErp.Modules.MarketRiskMoudule.Dto; using YLErp.Modules.RiskExposure; using YLErp.Modules.RiskListModule; using YLErp.Modules.RiskModule; using YLErp.Modules.SuperviseReportModule.CFMMC2022.Service; using YLErp.Modules.TagModule; using YLErp.Modules.TradeModule; using YLErp.QdpModule; namespace YLErp.Modules.FinancialModule { /// /// 财务凭证服务 /// public class FinancialVoucherService : YLBaseService { public FinancialVoucherService(OptUserInfo userInfo) : base(userInfo) { } /// /// 获取财务凭证 /// public ReturnInfo> GetFinancialStatements(FinancialStatementReq req) { var resultList = new List(); Task ExecuteAsync(Func> func) { return Task.Run(func).ContinueWith(t => { if (t.Result?.Count > 0) { lock (resultList) { resultList.AddRange(t.Result); } } }); } var tasks = new Task[] { ExecuteAsync(GetDepositWithdraw), ExecuteAsync(GetAROrAPOptionFee), ExecuteAsync(GetMaturityInvestmentIncome), ExecuteAsync(GetTerminationInvestmentIncome), }; Task.WaitAll(tasks); if (req.IsSamePeer.HasValue) { var isSamePeer = req.IsSamePeer.Value == SamePeerEnum.IsSamePeer.GetHashCode(); resultList = resultList.Where(d => d.IsSamePeer == isSamePeer).ToList(); } if (req.AbstractList?.Count > 0) { resultList = resultList.Where(f => req.AbstractList.Contains(f.AbstractTye)).ToList(); } return Return.Success(resultList); } private bool IsSamePeer(int clientId) { using (var db = DbContextFactory.GetClientDbContext(OptUser)) { var client = db.client.Where(n => n.id == clientId) .Select(n => new { n.CustomerNature }).FirstOrDefault(); if (client == null) { return false; //throw new Exception($"id为{clientId}的客户不存在"); } if (!client.CustomerNature.HasValue) { return false; } switch ((CustomerNatureEnum)client.CustomerNature) { case CustomerNatureEnum.证券公司: case CustomerNatureEnum.期货风险管理子公司: return true; default: return false; } } } /// /// 获取出入金凭证 /// /// public List GetDepositWithdraw() { List cashInCashOutList; var resultList = new List(); using (var db = new YLContext()) { cashInCashOutList = db.ClientCashInCashOut .Where(c => c.HappenDate == valuedateBLL.ValueDate && (c.Direction == "出金" || c.Direction == "入金") && c.State == ClientCashInCashOut.已确认).ToList(); } if (cashInCashOutList.Count == 0) { return resultList; } foreach (var clientCashInCashOut in cashInCashOutList) { var financialStatement = DepositWithdrawGenerator.GetFinancialStatement(IsSamePeer(clientCashInCashOut.ClientId.Value), clientCashInCashOut.ClientName, clientCashInCashOut.Money ?? 0, clientCashInCashOut.Direction == "出金"); resultList.Add(financialStatement); } return resultList; } /// /// 获取应收应付期权费凭证 /// public List GetAROrAPOptionFee() { List tradeList; using (var db = new YLContext()) { var valueDate = valuedateBLL.ValueDate; var query = from trade in db.trade join tradecash in db.trade_cash on trade.id equals tradecash.TradeId join confirmDoc in db.trade_contract_r.Where(aa => aa.Type == ContractTypeEnum.Trade && aa.IsValid) on new { id = trade.ParentTradeId > 0 ? trade.ParentTradeId : trade.id } equals new { id = confirmDoc.TradeId } into confirmDocT from confirmDoc in confirmDocT.DefaultIfEmpty() where tradecash.ValueDate == valueDate && tradecash.Action == ClientCashInCashOut.系统操作_期权费 && tradecash.ValidState != ConsGlobal.InValid && !tradecash.IsDeleted && tradecash.Status == TradeCashStatusEnum.已执行 select new TradeExtends { Id = trade.id, ClientId = trade.ClientId, ClientName = trade.ClientName, BuySell = trade.BuySell, ContractCode = confirmDoc.ContractCode, OptionFee = tradecash.Amount }; tradeList = query.ToList(); } var resultList = new List(); foreach (var trade in tradeList) { var financilaStatement = AROrAPOptionFeeGenerator.GetFinancialStatement( IsSamePeer(trade.ClientId.Value), trade.ClientName, trade.BuySell == "买入", trade.ContractCode, trade.OptionFee ?? 0); resultList.Add(financilaStatement); } return resultList; } /// /// 获取到期投资收益凭证 /// public List GetMaturityInvestmentIncome() { List tradeList; var expiredStatus = ConsTrade.已到期; var exerciseStatus = ConsTrade.已执行; using (var db = new YLContext()) { var valueDate = valuedateBLL.ValueDate; var query = from trade in db.trade join tradecash in db.trade_cash on new { tradeId = trade.id, tradeDate = trade.PremiumPayDate ?? trade.TradeDate ?? DateTime.Now } equals new { tradeId = tradecash.TradeId, tradeDate = tradecash.ValueDate } into tradecashT from tradecash in tradecashT.DefaultIfEmpty() join tradecashStrike in db.trade_cash on trade.id equals tradecashStrike.TradeId into tradecashStrikeT from tradecashStrike in tradecashStrikeT.DefaultIfEmpty() join confirmDoc in db.trade_contract_r.Where(aa => aa.Type == ContractTypeEnum.Trade && aa.IsValid) on new { id = trade.ParentTradeId > 0 ? trade.ParentTradeId : trade.id } equals new { id = confirmDoc.TradeId } into confirmDocT from confirmDoc in confirmDocT.DefaultIfEmpty() where tradecashStrike.ValueDate == valueDate && tradecashStrike.Action == ClientCashInCashOut.系统操作_行权费 && tradecashStrike.ValidState != ConsGlobal.InValid && !tradecashStrike.IsDeleted && tradecashStrike.Status == TradeCashStatusEnum.已执行 && trade.TradeStatus == exerciseStatus && tradecash.Action == ClientCashInCashOut.系统操作_期权费 && tradecash.ValidState != ConsGlobal.InValid && !tradecash.IsDeleted && tradecash.Status == TradeCashStatusEnum.已执行 select new TradeExtends { Id = trade.id, ClientId = trade.ClientId, ClientName = trade.ClientName, BuySell = trade.BuySell, ContractCode = confirmDoc.ContractCode, OptionFee = tradecash.Amount, StrikeFee = tradecashStrike.Amount }; query = query.Union(from trade in db.trade join tradecash in db.trade_cash on new { tradeId = trade.id, tradeDate = trade.PremiumPayDate ?? trade.TradeDate ?? DateTime.Now } equals new { tradeId = tradecash.TradeId, tradeDate = tradecash.ValueDate } into tradecashT from tradecash in tradecashT.DefaultIfEmpty() join confirmDoc in db.trade_contract_r.Where(aa => aa.Type == ContractTypeEnum.Trade && aa.IsValid) on new { id = trade.ParentTradeId > 0 ? trade.ParentTradeId : trade.id } equals new { id = confirmDoc.TradeId } into confirmDocT from confirmDoc in confirmDocT.DefaultIfEmpty() where trade.TradeStatus == expiredStatus && trade.UnWindDate == valueDate && !tradecash.IsDeleted && tradecash.Action == ClientCashInCashOut.系统操作_期权费 && tradecash.ValidState != ConsGlobal.InValid && tradecash.Status == TradeCashStatusEnum.已执行 select new TradeExtends { Id = trade.id, ClientId = trade.ClientId, ClientName = trade.ClientName, BuySell = trade.BuySell, ContractCode = confirmDoc.ContractCode, OptionFee = tradecash.Amount, StrikeFee = 0 }); tradeList = query.ToList(); } var resultList = new List(); foreach (var trade in tradeList) { var financilaStatement = MaturityInvestmentIncomeGenerator.GetFinancialStatement( IsSamePeer(trade.ClientId.Value), trade.ClientName, trade.BuySell == "买入", trade.ContractCode, trade.StrikeFee.HasValue, trade.OptionFee ?? 0, trade.StrikeFee ?? 0); resultList.Add(financilaStatement); } return resultList; } /// /// 获取提前终止投资收益凭证 /// /// public List GetTerminationInvestmentIncome() { List tradeList; var unwindStatus = ConsTrade.已平仓; using (var db = new YLContext()) { var valueDate = valuedateBLL.ValueDate; var query = from trade in db.trade join tradecash in db.trade_cash on new { tradeId = trade.id, tradeDate = trade.PremiumPayDate ?? trade.TradeDate ?? DateTime.Now } equals new { tradeId = tradecash.TradeId, tradeDate = tradecash.ValueDate } into tradecashT from tradecash in tradecashT.DefaultIfEmpty() join tradecashUnwind in db.trade_cash on trade.id equals tradecashUnwind.TradeId into tradecashUnwindT from tradecashUnwind in tradecashUnwindT.DefaultIfEmpty() join confirmDoc in db.trade_contract_r.Where(aa => aa.Type == ContractTypeEnum.Trade && aa.IsValid) on new { id = trade.ParentTradeId > 0 ? trade.ParentTradeId : trade.id } equals new { id = confirmDoc.TradeId } into confirmDocT from confirmDoc in confirmDocT.DefaultIfEmpty() where tradecashUnwind.ValueDate == valueDate && tradecashUnwind.Action == ClientCashInCashOut.系统操作_平仓费 && tradecashUnwind.ValidState != ConsGlobal.InValid && !tradecashUnwind.IsDeleted && tradecashUnwind.Status == TradeCashStatusEnum.已执行 && tradecash.Action == ClientCashInCashOut.系统操作_期权费 && tradecash.ValidState != ConsGlobal.InValid && !tradecash.IsDeleted && tradecash.Status == TradeCashStatusEnum.已执行 && trade.TradeStatus == unwindStatus select new TradeExtends { Id = trade.id, ClientId = trade.ClientId, ClientName = trade.ClientName, BuySell = trade.BuySell, ContractCode = confirmDoc.ContractCode, OptionFee = tradecash.Amount, UnwindFee = tradecashUnwind.Amount }; tradeList = query.ToList(); } var resultList = new List(); foreach (var trade in tradeList) { var financilaStatement = TerminationInvestmentIncomeGenerator.GetFinancialStatement( IsSamePeer(trade.ClientId.Value), trade.ClientName, trade.BuySell == "买入", trade.ContractCode, trade.OptionFee ?? 0, trade.UnwindFee ?? 0); resultList.Add(financilaStatement); } return resultList; } /// /// 广发定制的财务汇总数据查询 /// /// /// public List FinancialSummary_Option_GF(FinancialSummaryModelReq req) { //默认值查询场外期权的交易 if (req.TradeTypeList == null || req.TradeTypeList.Count == 0) { switch (req.SummaryType) { case "远期/掉期": req.TradeTypeList = new List { "远期" }; break; case "互换": req.TradeTypeList = new List { "收益互换" }; break; case "场外期权": default: req.SummaryType = "场外期权"; req.TradeTypeList = ConsTrade.OptionTradeTypes; break; } } var contractBLL = new TradeDocumentService(UserInfo); var modelList = new List(); var searchTradeList = tradeBLL.SearchOptionTrade_GF(req); var tradeIds = searchTradeList.Select(O => O.TradeId).ToList(); var parentTradeIds = searchTradeList.Select(x => x.ParentTradeId).ToHashSet(); var parentTrades = DbContext.trade.Where(x => parentTradeIds.Contains(x.id)).ToDictionary(n => n.id); var lastDate = QdpCalendarHelper.GetNonHolidayDefore(req.CurrentPeriodDateStart.AddDays(-1)); var currentDate = QdpCalendarHelper.GetNonHolidayDefore(req.CurrentPeriodDateEnd); var positionReq = new EodTradePositionReq { ValueDateStart = lastDate, ValueDateEnd = currentDate, TraderIds = string.Join(",", tradeIds) }; List positions = null; positions = new EodTradePositionBLL().SearchList(positionReq)?.rows.Select(O => (EodTradePosition)O).ToList(); Dictionary> clientTagList = null; if (searchTradeList != null && searchTradeList.Any()) { using (var tagService = new TagService(OptUser)) { clientTagList = tagService.GetTagByClientIds(searchTradeList.Select(p => p.ClientId).Distinct().ToList()); } } if (clientTagList == null) { clientTagList = new Dictionary>(); } List position = new List(); Dictionary riskDict = new Dictionary(); var futureDict = position.GroupBy(O => O.UnderlyingCode).ToDictionary(K => K.Key, V => (double)V.ToList().Sum(O => O.PositionPnL)); var feeDict = position.GroupBy(O => O.UnderlyingCode).ToDictionary(K => K.Key, V => (double)V.ToList().Sum(O => O.Commission)); foreach (var item in searchTradeList) { if (parentTrades.TryGetValue(item.ParentTradeId, out var parentTrade)) { item.TradeNumber = parentTrade.TradeNumber; } double percent = 1; double? lastPv = positions.FindAll(O => O.TradeId == item.TradeId && O.ValueDate == lastDate).Sum(O => O.Amount == 0 ? 0 : Convert.ToDouble(O.Pv) / O.Amount); double? lastPnl = positions.FindAll(O => O.TradeId == item.TradeId && O.ValueDate == lastDate).Sum(O => O.Amount == 0 ? 0 : Convert.ToDouble(O.PositionPnL) / O.Amount); double? pv = positions.FindAll(O => O.TradeId == item.TradeId && O.ValueDate == currentDate).Sum(O => O.Amount == 0 ? 0 : Convert.ToDouble(O.Pv) / O.Amount); double? Pnl = positions.FindAll(O => O.TradeId == item.TradeId && O.ValueDate == currentDate).Sum(O => O.Amount == 0 ? 0 : Convert.ToDouble(O.PositionPnL) / O.Amount); item.LastPv = lastPv * item.Notional;//上期期末市值; item.LastTotalPnl = lastPnl * item.Notional;//上期末累计浮动盈亏; item.Pv = pv * item.Notional;//本期期末市值; item.TotalPnl = Pnl * item.Notional;//本期末累计浮动盈亏; if (item.TradeDate >= req.CurrentPeriodDateStart) { item.LastTotalPnl = 0; } if (item.UnderlyingCode != null) { item.FuturePnl = futureDict.ContainsKey(item.UnderlyingCode) ? futureDict[item.UnderlyingCode] * percent : 0;//期货盈亏(结算价); item.ServiceFee = feeDict.ContainsKey(item.UnderlyingCode) ? feeDict[item.UnderlyingCode] * percent : 0;//期货手续费; item.CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode).CountRatio; } else { item.FuturePnl = 0;//期货盈亏(结算价); item.ServiceFee = 0;//期货手续费; item.CountRatio = 1; } item.DailyPnL = positions.FindAll(O => O.TradeId == item.TradeId && O.ValueDate == currentDate).Sum(O => O.DailyPnL); item.FinancialEntry = null;//财务入账; var SpotPrice = DbContext.trade.Where(l => l.id == item.TradeId).FirstOrDefault()?.SpotPrice; item.SurvivingNominalPrincipal = item.PositionAmount * SpotPrice; //拼装标签值 if (clientTagList.ContainsKey(item.ClientId)) { item.Tags = clientTagList[item.ClientId]; item.OutputTags = TagService.GetOutputTagsStr(item.Tags); } } return searchTradeList; } /// /// 汇总客户数据 /// public List GatherClientData(FinancialSummaryModelReq req) { //反回表格数据(明细 小计 合计 ) List rowSummaryOptionModels = new List(); //明细数据 var financialSummaryOptionDetails = FinancialSummary_Option_GF(req); //小计数据 var reqSubTotle = new FinancialSummaryModelReq() { SummaryType = req.SummaryType, TradeTypeList = req.TradeTypeList, CurrentPeriodDateStart = req.CurrentPeriodDateStart, CurrentPeriodDateEnd = req.CurrentPeriodDateEnd, ClientIds = req.ClientIds }; var financialSummaryOptionSubtotal = FinancialSummary_Option_GF(reqSubTotle); if (financialSummaryOptionDetails != null && financialSummaryOptionDetails.Any()) { //小计【可用资金(财务)】= 【期末结存(财务)】-预付金占用 + 冻结资金 、【期末结存(财务)】 = 出入金净额 + 成交了结收支 var financialSummaryOptionModels = financialSummaryOptionDetails.GroupBy(l => new { l.ClientId, l.ClientFullName }).Select(l => l.Key).ToList(); var clientCashs = ClientBalanceUtility.GetClientBanlances(financialSummaryOptionModels.Select(l => l.ClientId).ToList(), req.CurrentPeriodDateEnd, req.CurrentPeriodDateEnd, false, true, false); List optionModelsSubtotal = new List(); var tcQuery = new YLContext().trade_cash.Where(O => !O.IsDeleted && O.ValidState != ConsGlobal.InValid); financialSummaryOptionModels.ForEach(l => { //查询明细是否有该客户数据,如果没有就不需要小计 var financialSummaryOptionDetailsByClient = financialSummaryOptionDetails.Where(x => x.ClientId == l.ClientId); if (financialSummaryOptionDetailsByClient != null && financialSummaryOptionDetailsByClient.Any()) { var financialSummaryOptionModelsByClient = financialSummaryOptionSubtotal.Where(r => r.ClientId == l.ClientId); FinancialSummaryOptionModel summaryOptionModel = CreateFinancialSummaryOptionClientModel(req, l.ClientId, " 小计:" + l.ClientFullName, "无状态", financialSummaryOptionModelsByClient.ToList(), tcQuery); var clientCashsByClientId = clientCashs.Where(c => c.ClientId == l.ClientId).FirstOrDefault(); if (clientCashsByClientId != null) { //可用资金(财务) clientCashsByClientId.AvailableCash summaryOptionModel.AvailableCash = clientCashsByClientId.AvailableAmount; //期末结存(财务) clientCashsByClientId.EndBalance; summaryOptionModel.EndBalance = clientCashsByClientId.AmountFund; } financialSummaryOptionDetailsByClient.ToList().ForEach(l => { l.StatusStr = l.Status ? "完结" : "未完结"; l.ConfirmTotlePnl = l.ConfirmPnl; l.GF_Pnl = l.Pnl; }); rowSummaryOptionModels.AddRange(financialSummaryOptionDetailsByClient); rowSummaryOptionModels.Add(summaryOptionModel); optionModelsSubtotal.Add(summaryOptionModel); } }); FinancialSummaryOptionModel summaryOptionModel = CreateFinancialSummaryOptionClientModel(req, 0, " 合计:", "无状态", financialSummaryOptionDetails, tcQuery); summaryOptionModel.AvailableCash = optionModelsSubtotal.Sum(f => f.AvailableCash); summaryOptionModel.EndBalance = optionModelsSubtotal.Sum(f => f.EndBalance); rowSummaryOptionModels.Add(summaryOptionModel); } return rowSummaryOptionModels; } /// /// 汇总簿记数据 /// public List GatherUnitData(FinancialSummaryModelReq req) { var startDate = QdpCalendarHelper.GetNonHolidayDefore(req.CurrentPeriodDateStart.AddDays(-1)); var TotalPnls = CaclTotalPnl(req.CurrentPeriodDateStart, req.CurrentPeriodDateEnd, out List t2); //场内 List financialSummaryExchanges = new List(); using (YLContext ylContext = new YLContext()) { var exchangList = (from eodtrade in ylContext.eod_trade_position_s join exchangeOption in ylContext.exchange_list_option on eodtrade.ExchangeOptionCode equals exchangeOption.ContractCode into exchangeOptionT from exchangeOption in exchangeOptionT.DefaultIfEmpty() where eodtrade.TradeId == 0 && !string.IsNullOrEmpty(eodtrade.HedgeUniqueCode) && (startDate <= eodtrade.ValueDate && req.CurrentPeriodDateEnd >= eodtrade.ValueDate) select new { eodtrade.HedgeUniqueCode, eodtrade.ExchangeOptionCode, eodtrade.ValueDate, eodtrade.BookId, eodtrade.UnderlyingCode, eodtrade.DailyPnL, eodtrade.Commission, eodtrade.PositionPnL, eodtrade.RealizedPnL, eodtrade.Pv, eodtrade.Amount, eodtrade.TotalPnL, //ContractSize = DataCacheProvider.GetUnderlyingDataSource().GetData(eodtrade.UnderlyingCode).ContractSize, Strike = eodtrade.TradeType == "场内期权" ? exchangeOption.Strike : 0, }).ToList(); if (req.UserAssets != null && req.UserClients != null) { exchangList = exchangList.Where(a => req.UserAssets.Contains(a.BookId)).ToList(); } if (req.BookIds != null && req.BookIds.Any()) { exchangList = exchangList.Where(a => req.BookIds.Contains(a.BookId)).ToList(); } if (!string.IsNullOrEmpty(req.VarietyCode)) { var reqUnderlyingCodes = ylContext.underlying_manager.AsNoTracking().Where(l => l.CommodityCode == req.VarietyCode).Select(l => l.UnderlyingCode).ToList(); exchangList = exchangList.Where(a => reqUnderlyingCodes.Contains(a.UnderlyingCode)).ToList(); } if (!string.IsNullOrEmpty(req.VarietyName)) { var reqUnderlyingCodes = ylContext.underlying_manager.AsNoTracking().Where(l => l.CommodityCode == req.VarietyName).Select(l => l.UnderlyingCode).ToList(); exchangList = exchangList.Where(a => reqUnderlyingCodes.Contains(a.UnderlyingCode)).ToList(); } var exchangListByHedgeUniqueCode = exchangList.GroupBy(l => new { l.ExchangeOptionCode, l.HedgeUniqueCode }).ToList(); foreach (var item in exchangListByHedgeUniqueCode) { var code = item.Key.ExchangeOptionCode; if (string.IsNullOrWhiteSpace(code)) { code = item.Key.HedgeUniqueCode; } else { if (financialSummaryExchanges.Where(l => l.ExchangeCode == code).Any()) { continue; } } var exchangListFirst = exchangList.Where(l => (l.ExchangeOptionCode == code || l.HedgeUniqueCode == code)).FirstOrDefault(); var exchangListEndDate = exchangList.Where(l => (l.ExchangeOptionCode == code || l.HedgeUniqueCode == code) && l.ValueDate == req.CurrentPeriodDateEnd); var exchangListStartDate = exchangList.Where(l => (l.ExchangeOptionCode == code || l.HedgeUniqueCode == code) && l.ValueDate == startDate); FinancialSummaryOptionModel financialSummaryOption = new FinancialSummaryOptionModel() { AssetId = exchangListFirst.BookId, ExchangeCode = string.IsNullOrWhiteSpace(exchangListFirst.ExchangeOptionCode) ? exchangListFirst.HedgeUniqueCode : exchangListFirst.ExchangeOptionCode, AssetBookName = DataCacheProvider.GetAssetUnitDataSource().GetData(exchangListFirst.BookId).Name, VarietyCode = DataCacheProvider.GetVariety(exchangListFirst.UnderlyingCode).VarietyCode, PositionAmount = exchangListEndDate.Any() ? Math.Abs(exchangListEndDate.Sum(l => l.Amount)) : 0, PositionLots = exchangListEndDate.Any() ? (Math.Abs(exchangListEndDate.Sum(l => l.Amount)) / DataCacheProvider.GetUnderlyingDataSource().GetData(exchangListEndDate.FirstOrDefault().UnderlyingCode).ContractSize) : 0, StockEqvNotional3 = exchangListEndDate.Any() ? (exchangListEndDate.Sum(l => Math.Abs(l.Strike * l.Amount))) : 0, ClearPrice = 0, ConfirmTotlePnl = exchangListEndDate.Any() ? exchangListEndDate.Sum(l => l.RealizedPnL) : 0, Pv = exchangListEndDate.Any() ? exchangListEndDate.Sum(l => l.Pv) : 0, LastPv = exchangListStartDate.Any() ? exchangListStartDate.Sum(l => l.Pv) : 0, TotalPnl = exchangListEndDate.Any() ? exchangListEndDate.Sum(l => l.PositionPnL) : 0, LastTotalPnl = exchangListStartDate.Any() ? exchangListStartDate.Sum(l => l.PositionPnL) : 0, GF_Pnl = (exchangListEndDate.Any() ? exchangListEndDate.Sum(l => l.PositionPnL) : 0) - (exchangListStartDate.Any() ? exchangListStartDate.Sum(l => l.PositionPnL) : 0), ServiceFee = exchangListEndDate.Any() ? exchangListEndDate.Sum(l => l.Commission) : 0, DailyPnL = exchangListEndDate.Any() ? exchangListEndDate.Sum(l => l.DailyPnL) : 0, NewTotalPnl = TotalPnls.Where(l => exchangList.Where(l => (l.ExchangeOptionCode == code || l.HedgeUniqueCode == code)).Select(l => l.HedgeUniqueCode).Contains(l.HedgeUniqueCode)).Sum(l => l.AccruedTotalPnL), }; financialSummaryExchanges.Add(financialSummaryOption); } } // financialSummaryOptions.GroupBy() //反回表格数据(明细 小计 合计 ) List rowSummaryOptionModels = new List(); //场外所有明细数据 req.TradeTypeList = new List() { "收益互换", "远期" }.Concat(ConsTrade.OptionTradeTypes).ToList(); var financialSummaryOptionDetails = FinancialSummary_Option_GF(req); //场外+场内 var financialSummaryOptionAll = financialSummaryOptionDetails.Concat(financialSummaryExchanges).ToList(); var tcQuery = new YLContext().trade_cash.Where(O => !O.IsDeleted && O.ValidState != ConsGlobal.InValid); //转换簿记维度 var financialSummaryOptionUnitDetails = CreateUnitDate(req, financialSummaryOptionAll, tcQuery, TotalPnls); //小计数据 //var reqSubTotle = new FinancialSummaryModelReq() { SummaryType = req.SummaryType, TradeTypeList = req.TradeTypeList, CurrentPeriodDateStart = req.CurrentPeriodDateStart, CurrentPeriodDateEnd = req.CurrentPeriodDateEnd, ClientIds = req.ClientIds }; //var financialSummaryOptionSubtotal = FinancialSummary_Option_GF(reqSubTotle); //转换簿记维度 //var financialSummaryOptionUnitSubtotal = CreateUnitDate(req, financialSummaryOptionSubtotal, tcQuery); if (financialSummaryOptionUnitDetails != null && financialSummaryOptionUnitDetails.Any()) { //小计【当日期货盈亏】、【累计总盈亏】 var financialSummaryOptionModels = financialSummaryOptionUnitDetails.GroupBy(l => new { l.AssetId }).Select(l => new { l.Key, AssetBookName = l.FirstOrDefault().AssetBookName, VarietyCode = l.FirstOrDefault().VarietyCode }).ToList(); List optionModelsSubtotal = new List(); financialSummaryOptionModels.ForEach(l => { //查询明细是否有该簿记数据,如果没有就不需要小计 var financialSummaryOptionDetailsByAsset = financialSummaryOptionUnitDetails.Where(x => x.AssetId == l.Key.AssetId); if (financialSummaryOptionDetailsByAsset != null && financialSummaryOptionDetailsByAsset.Any()) { FinancialSummaryOptionModel summaryOptionModel = CreateFinancialSummaryOptionUnitModel(l.Key.AssetId, " 小计:" + l.AssetBookName, l.VarietyCode, financialSummaryOptionDetailsByAsset.ToList(), tcQuery); rowSummaryOptionModels.AddRange(financialSummaryOptionDetailsByAsset); rowSummaryOptionModels.Add(summaryOptionModel); optionModelsSubtotal.Add(summaryOptionModel); } }); FinancialSummaryOptionModel summaryOptionModel = CreateFinancialSummaryOptionUnitModel(0, " 合计:", "", financialSummaryOptionUnitDetails, tcQuery); rowSummaryOptionModels.Add(summaryOptionModel); } return rowSummaryOptionModels; } private List CreateUnitDate(FinancialSummaryModelReq req, List financialSummaryOptionDetails, IQueryable tcQuery, List totalPnls) { var tradeTypes = new List { "雪球期权", "凤凰期权", "区间累积期权" }; //(trade.OriginalNotional ?? 0) / contractSize var parentIds = financialSummaryOptionDetails.Where(l => l.ParentTradeId > 0).GroupBy(l => l.ParentTradeId).Select(l => l.Key).ToList(); var FSOModelsGourpByClientByTradeId = financialSummaryOptionDetails.Where(l => !parentIds.Contains(l.TradeId)&& l.TradeId != 0).GroupBy(f => f.TradeId).Select(f => new FinancialSummaryOptionModel { TradeId = f.Key, AssetId = f.FirstOrDefault().AssetId, AssetBookName = f.FirstOrDefault().AssetBookName, VarietyCode = f.FirstOrDefault().VarietyCode, PositionAmount = f.Any(c => c.Status == false) ? f.Sum(c => c.PositionAmount) : 0, PositionLots = f.Any(c => c.Status == false) ? f.Sum(c => c.PositionAmount / c.ContractSize) : 0, StockEqvNotional3 = f.FirstOrDefault().StockEqvNotional3, TradePrice = f.Sum(v => v.TradePrice), ClearPrice = f.Any(c => c.Status == false) ? f.Sum(v => v.ClearPrice) : f.Sum(v => v.ClearPrice) + (f.Sum(v => tradeTypes.Contains(v.TradeType) ? tcQuery.Where(O => O.TradeId == f.Key && O.ValueDate >= req.CurrentPeriodDateStart && O.ValueDate <= req.CurrentPeriodDateEnd && O.Action == "系统操作-票息").Sum(O => (double?)O.Amount) : 0)), ConfirmTotlePnl = f.Sum(v => v.ConfirmPnl ?? 0), LastPv = f.Any(c => c.Status == false) ? f.Sum(f => f.LastPv) : 0, LastTotalPnl = f.Any(c => c.Status == false) ? f.Sum(f => (f.LastTotalPnl ?? 0)) : 0, Pv = f.Any(c => c.Status == false) ? f.Sum(f => f.Pv) : 0, TotalPnl = f.Any(c => c.Status == false) ? f.Sum(f => f.TotalPnl) : 0, GF_Pnl = f.Any(c => c.Status == false) ? f.Sum(f => f.Pnl) : 0, DailyPnL = f.FirstOrDefault().DailyPnL, ServiceFee = f.Sum(l => l.ServiceFee), NewTotalPnl = totalPnls.Where(c => c.TradeId == f.Key).FirstOrDefault()?.AccruedTotalPnL, }).Concat(financialSummaryOptionDetails.Where(l => l.TradeId == 0)); var FSOModelsGourpByClientByAsset = (FSOModelsGourpByClientByTradeId.GroupBy(l => new { l.AssetId, l.AssetBookName, l.VarietyCode }).Select( l => new FinancialSummaryOptionModel { AssetId = l.Key.AssetId, AssetBookName = l.Key.AssetBookName, VarietyCode = l.Key.VarietyCode, PositionAmount = l.Sum(v => v.PositionAmount), PositionLots = l.Sum(v => v.PositionLots), StockEqvNotional3 = l.FirstOrDefault().StockEqvNotional3, TradePrice = l.Sum(v => v.TradePrice), ClearPrice = l.Sum(v => v.ClearPrice), ConfirmTotlePnl = l.Sum(v => v.ConfirmTotlePnl??0), LastPv = l.Sum(f => f.LastPv), LastTotalPnl = l.Sum(f => f.LastTotalPnl), Pv = l.Sum(f => f.Pv), TotalPnl = l.Sum(f => f.TotalPnl), GF_Pnl = l.Sum(f => f.GF_Pnl), ServiceFee = l.Sum(f => f.ServiceFee), DailyPnL = l.Sum(f => f.DailyPnL), NewTotalPnl = l.Sum(f => f.NewTotalPnl), })).ToList(); return FSOModelsGourpByClientByAsset; } public FinancialSummaryOptionModel CreateFinancialSummaryOptionClientModel(FinancialSummaryModelReq req, int clientId, string ClientFullName, string StatusStr, List financialSummaryOptionModelsByClient, IQueryable trade_Cashes) { var tradeTypes = new List { "雪球期权", "凤凰期权", "区间累积期权" }; var parentIds = financialSummaryOptionModelsByClient.Where(l=>l.ParentTradeId>0).GroupBy(l => l.ParentTradeId).Select(l=>l.Key).ToList(); //场外期权每个客户,同交易id var FSOModelsGourpByClientByTradeId = financialSummaryOptionModelsByClient.Where(l=> !parentIds.Contains(l.TradeId)).GroupBy(f => f.TradeId).Select(f => new { f.Key, StockEqvNotional3 = f.FirstOrDefault().StockEqvNotional3, TradePrice = f.Sum(v => v.TradePrice), ClearPrice = f.Any(c => c.Status == false) ? f.Sum(v => v.ClearPrice) : f.Sum(v => v.ClearPrice) + (f.Sum(v => tradeTypes.Contains(v.TradeType) ? trade_Cashes.Where(O => O.TradeId == f.Key && O.ValueDate >= req.CurrentPeriodDateStart && O.ValueDate <= req.CurrentPeriodDateEnd && O.Action == "系统操作-票息").Sum(O => (double?)O.Amount) : 0)), ConfirmTotlePnl = f.Sum(v => v.ConfirmPnl ?? 0), LastPv = f.Any(c => c.Status == false) ? f.Sum(f => f.LastPv) : 0, LastTotalPnl = f.Any(c => c.Status == false) ? f.Sum(f => (f.LastTotalPnl ?? 0)) : 0, Pv = f.Any(c => c.Status == false) ? f.Sum(f => f.Pv) : 0, TotalPnl = f.Any(c => c.Status == false) ? f.Sum(f => f.TotalPnl) : 0, GF_Pnl = f.Sum(f => f.Pnl ?? 0), }); FinancialSummaryOptionModel summaryOptionModel = new FinancialSummaryOptionModel(); summaryOptionModel.ClientId = clientId; summaryOptionModel.ClientFullName = ClientFullName; summaryOptionModel.StatusStr = StatusStr; summaryOptionModel.OptionType = StatusStr; //名义本金 summaryOptionModel.StockEqvNotional3 = FSOModelsGourpByClientByTradeId.Sum(l => l.StockEqvNotional3).FormatValue(2); //期初权利金收支 summaryOptionModel.TradePrice = FSOModelsGourpByClientByTradeId.Sum(f => f.TradePrice).FormatValue(2); //清算金额 summaryOptionModel.ClearPrice = FSOModelsGourpByClientByTradeId.Sum(f => f.ClearPrice).FormatValue(2); //我方期权清算盈亏 summaryOptionModel.ConfirmTotlePnl = FSOModelsGourpByClientByTradeId.Sum(f => f.ConfirmTotlePnl).FormatValue(2); //上期期末市值 summaryOptionModel.LastPv = FSOModelsGourpByClientByTradeId.Sum(f => f.LastPv).FormatValue(2); //上期期末累计浮动盈亏 summaryOptionModel.LastTotalPnl = FSOModelsGourpByClientByTradeId.Sum(f => f.LastTotalPnl).FormatValue(2); //本期期末市值 summaryOptionModel.Pv = FSOModelsGourpByClientByTradeId.Sum(f => f.Pv).FormatValue(2); //本期期末累计浮动盈亏 summaryOptionModel.TotalPnl = FSOModelsGourpByClientByTradeId.Sum(f => f.TotalPnl).FormatValue(2); //本期浮动盈亏 summaryOptionModel.GF_Pnl = FSOModelsGourpByClientByTradeId.Sum(f => f.GF_Pnl).FormatValue(2); ////【累计总盈亏】 //summaryOptionModel.NewTotalPnl = financialSummaryOptionModelsByClient.GroupBy(x => x.TradeId).Sum(f => f.FirstOrDefault().NewTotalPnl); ////【当日期货盈亏】 //summaryOptionModel.TotalPnlAfterExpense = financialSummaryOptionModelsByClient.Sum(f => f.TotalPnlAfterExpense); return summaryOptionModel; } public FinancialSummaryOptionModel CreateFinancialSummaryOptionUnitModel(int AssetId, string AssetBookName, string VarietyCode, List financialSummaryOptionModelsByClient, IQueryable trade_Cashes) { FinancialSummaryOptionModel summaryOptionModel = new FinancialSummaryOptionModel(); summaryOptionModel.AssetId = AssetId; summaryOptionModel.AssetBookName = AssetBookName; summaryOptionModel.StatusStr = "无状态"; //StatusStr //summaryOptionModel.VarietyCode = VarietyCode; //名义本金 summaryOptionModel.StockEqvNotional3 = financialSummaryOptionModelsByClient.Sum(l => l.StockEqvNotional3).FormatValue(2); //期初权利金收支 summaryOptionModel.TradePrice = financialSummaryOptionModelsByClient.Sum(f => f.TradePrice).FormatValue(2); //清算金额 summaryOptionModel.ClearPrice = financialSummaryOptionModelsByClient.Sum(f => f.ClearPrice).FormatValue(2); //我方期权清算盈亏 summaryOptionModel.ConfirmTotlePnl = financialSummaryOptionModelsByClient.Sum(f => f.ConfirmTotlePnl).FormatValue(2); //上期期末市值 summaryOptionModel.LastPv = financialSummaryOptionModelsByClient.Sum(f => f.LastPv).FormatValue(2); //上期期末累计浮动盈亏 summaryOptionModel.LastTotalPnl = financialSummaryOptionModelsByClient.Sum(f => (f.LastTotalPnl??0)).FormatValue(2); //本期期末市值 summaryOptionModel.Pv = financialSummaryOptionModelsByClient.Sum(f => f.Pv).FormatValue(2); //本期期末累计浮动盈亏 summaryOptionModel.TotalPnl = financialSummaryOptionModelsByClient.Sum(f => f.TotalPnl).FormatValue(2); //本期浮动盈亏 summaryOptionModel.GF_Pnl = financialSummaryOptionModelsByClient.Sum(f => f.GF_Pnl).FormatValue(2); //【累计总盈亏】 summaryOptionModel.NewTotalPnl = financialSummaryOptionModelsByClient.Sum(f => f.NewTotalPnl).FormatValue(2); //【当日期货盈亏】 summaryOptionModel.DailyPnL = financialSummaryOptionModelsByClient.Sum(f => f.DailyPnL).FormatValue(2); summaryOptionModel.ServiceFee = financialSummaryOptionModelsByClient.Sum(f => f.ServiceFee).FormatValue(2); return summaryOptionModel; } public List CaclTotalPnl(DateTime? StartDate, DateTime EndDate, out List t2PositionDataDtos) { // 1、确定三点 T1 T1~T2 T2 var start = EodOperationBase.GetLastSettlementDate(StartDate?.AddDays(-1) ?? valuedateBLL.SystemDate.AccruedTotalPnlStartDate ?? DateTime.Today); var end = EndDate; //T1 var dateT1 = EodOperationBase.GetLastSettlementDate(start); // T2 var dateT2 = end; RiskRequestModel reqModel = new RiskRequestModel() { ValueDateStart = dateT1, ValueDateEnd = dateT2, EodSettlePriceMode = "收盘价" }; return new AccruedTotalPnlService(OptUserInfo.SystemUser).CalcuTotalPnl(out t2PositionDataDtos, dateT1, dateT2, reqModel); } } public class TradeExtends { public int Id { get; set; } public int? ClientId { get; set; } public string ClientName { get; set; } public string BuySell { get; set; } public string ContractCode { get; set; } public double? OptionFee { get; set; } public double? StrikeFee { get; set; } public double? UnwindFee { get; set; } } }