using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using YLErp.BLL.Eod; using YLErp.BLL; using YLErp.BLL.EodSettlement; using YLErp.Model; using YLErp.QdpModule; using YLErp.DBModels; using YLErp.Modules.CalculationModule; using static iTextSharp.text.pdf.AcroFields; using NPOI.SS.Formula.Functions; using YLErp.DBModels.Helpers; using YLErp.Modules.TradeDalModule; using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos; using Microsoft.Office.Interop.Word; namespace YLErp.Modules.ReportModule { public class FinancialSummaryReportZLService : YLBaseService { public FinancialSummaryReportZLService(OptUserInfo userInfo) : base(userInfo) { } /// /// 获取场外期权账单数据 /// /// /// public FinancialSummaryOptionExportModel GetReportData(FinancialSummaryModelReq req) { FinancialSummaryOptionExportModel reportModel = new FinancialSummaryOptionExportModel() { StartDate = req.CurrentPeriodDateStart, EndDate = req.CurrentPeriodDateEnd }; var allClientList = new List(); using (var db = DbContextFactory.GetClientDbContext(null)) { allClientList = db.client.Where(s => s.ProcessStatus != "未提交").ToList(); } var currentDate = QdpCalendarHelper.GetNonHolidayDefore(req.CurrentPeriodDateEnd); //系统交易日 var valuedate = valuedateBLL.ValueDate; //获取根据系统时间 var lastBalanceDate = EodOperationBase.GetLastSettlementDate(valuedate); if (currentDate < lastBalanceDate) { lastBalanceDate = currentDate; } var startDate = QdpCalendarHelper.GetNonHolidayDefore(req.CurrentPeriodDateStart); if (startDate > lastBalanceDate) { startDate = lastBalanceDate; } var beforeMouthLastDay = DbContext.ClientBalanceDaily.Where(n => n.BalanceDate < req.CurrentPeriodDateStart) .Max(n => n.BalanceDate) ?? DateTime.MinValue; ; //获取上个月最后一天日期 var lastNonHoliday = QdpCalendarHelper.GetNonHoliday(beforeMouthLastDay); var eodPositionQuery = DbContext.eod_trade_position.Where(x => x.ValueDate == lastBalanceDate && x.TradeId > 0);//取区间最后一天所有场外期权有效的交易 var lastMonthEodPositionQuery = DbContext.eod_trade_position.Where(x => x.ValueDate == lastNonHoliday && x.TradeId > 0);//取区间上个月末最后一天所有场外期权有效的交易 var eodTradeQuery = DbContext.eod_trade.Where(x => x.ValueDate <= lastBalanceDate && x.ValueDate >= req.CurrentPeriodDateStart).ToLookup(x => x.TradeId); var lastEodTradeQuery = DbContext.eod_trade.Where(x => x.ValueDate == lastNonHoliday).ToList(); List trades = new List(); List lastMonthTrades = lastEodTradeQuery.Select(s => s.trade).ToList(); foreach (var eodTrade in eodTradeQuery) { var lastEodTrade = eodTrade.OrderByDescending(o => o.ValueDate).First(); trades.Add(lastEodTrade.trade); } var clientbalanceDailys = DbContext.ClientBalanceDailyBS.Where(x => x.BalanceDate <= lastBalanceDate && x.BalanceDate >= startDate).ToList(); var lastMonthClientbalanceDailys = DbContext.ClientBalanceDailyBS.Where(x => x.BalanceDate == lastNonHoliday).ToList();//上个月末数据 var cashActions = new List() { ClientCashInCashOut.系统操作_期权费, ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_平仓费, ClientCashInCashOut.系统操作_票息, ClientCashInCashOut.系统操作_互换, ClientCashInCashOut.人工操作_其他 }; var entryexitPredicate = PredicateBuilder.Create(t => t.ClientId != null && t.ValidState != "InValid" && t.HappenDate >= req.CurrentPeriodDateStart && t.HappenDate < lastBalanceDate.AddDays(1) && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && cashActions.Contains(t.Action)); var entryexits = (from cash in DbContext.ClientCashInCashOut.Where(entryexitPredicate) join trade in DbContext.trade on cash.TradeId equals trade.id select cash).ToLookup(n => n.ClientId.Value); var tradeCashs = DbContext.trade_cash.Where(x => x.ValidState != "InValid" && !x.IsDeleted && x.ValueDate >= req.CurrentPeriodDateStart && x.ValueDate <= lastBalanceDate); CalculateClientTradeData(reportModel, entryexits, trades, tradeCashs, eodPositionQuery); var lastMonthReportModel = new FinancialSummaryOptionExportModel(); CalculateClientPosition(lastMonthReportModel, lastMonthTrades, lastMonthEodPositionQuery); CalculateClientSummary(reportModel, lastMonthReportModel, clientbalanceDailys, lastMonthClientbalanceDailys, allClientList, lastBalanceDate); return reportModel; } /// /// 客户买卖权数据计算 /// /// /// /// /// /// private void CalculateClientTradeData(FinancialSummaryOptionExportModel reportModel, ILookup entryexits, List tradeQuerys, IQueryable tradeCashs, IQueryable eodPositions) { var dealCouponRateCashInOutDic = new Dictionary();//已处理的票息 foreach (var groupEntryExits in entryexits) { var entryexitList = groupEntryExits.ToList(); foreach (var item in entryexitList) { var trade = tradeQuerys.FirstOrDefault(x => x.id == item.TradeId); if (dealCouponRateCashInOutDic.ContainsKey(item.id) || trade == null) { continue; } var tradeCash = tradeCashs.FirstOrDefault(x => x.id == item.TradeCashId); var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); if (ClientCashInCashOut.系统操作_期权费.Equals(item.Action)) { CalculateClientOpen(reportModel, trade, underlying, item.Money ?? 0); } else { CalculateClientUnwind(reportModel, trade, underlying, item, tradeCash); } } } CalculateClientPosition(reportModel, tradeQuerys, eodPositions); } /// /// 计算客户开仓情况 /// /// /// /// /// /// private void CalculateClientOpen(FinancialSummaryOptionExportModel reportModel, trade trade, underlying_manager underlying, double money) { bool isBuy = trade.BuySell == "卖出"; ClientOptionOpen clientOptionOpen = new ClientOptionOpen() { ClientId = trade.ClientId, ClientName = trade.ClientName, TradeType = trade.TradeMultipleType, TradeNumber = trade.TradeNumber, UnderlyingCode = trade.UnderlyingCode, UnderlyingName = trade.UnderlyingName, OpenPrice = Math.Round(trade.TradeSinglePrice ?? 0, 2), Qty = Math.Round(trade.OriginalNotional ?? 0 / underlying.CountRatio, 2), StockEqvNotional = Math.Round(trade.StockEqvNotional, 2), OpentAmount = Math.Round(trade.TradePrice ?? 0, 2), OptionAmount = money }; if (isBuy) { reportModel.BuyClientOptionOpens.Add(clientOptionOpen); } else { reportModel.SellClientOptionOpens.Add(clientOptionOpen); } } /// /// 计算客户平仓情况 /// /// /// /// /// /// /// /// /// private void CalculateClientUnwind(FinancialSummaryOptionExportModel reportModel , trade trade , underlying_manager underlying , ClientCashInCashOut item , trade_cash tradeCash) { bool isBuy = trade.BuySell == "卖出"; var money = Math.Round(tradeCash?.Amount ?? 0, 2); var couponRate = 0d; //结算收益 var unWindProfit = money; var cost = 0d; if (trade.TradeType != "远期") { cost = TradeCalcHelper.GetSign(trade.BuySell) * (trade.TradePrice ?? 0) * (tradeCash?.UnwindPercentRate ?? 0); } else { cost = -(trade.TradePrice ?? 0) * (tradeCash?.UnwindPercentRate ?? 0);//远期开仓总费用占比 } unWindProfit = cost - money; var unwindPrice = Math.Round(tradeCash?.UnwindPrice ?? 0, 2); if (tradeCash.Action == ClientCashInCashOut.系统操作_票息)//最后一笔操作,去取票息 { unWindProfit = 0; couponRate = money; } ClientOptionUnwind clientOptionUnwind = new ClientOptionUnwind() { ClientId = trade.ClientId, ClientName = trade.ClientName, TradeType = trade.TradeMultipleType, TradeNumber = trade.TradeNumber, UnderlyingCode = trade.UnderlyingCode, UnderlyingName = trade.UnderlyingName, OpenPrice = Math.Round(trade.TradeSinglePrice ?? 0, 2), Qty = Math.Round((tradeCash?.UnwindNotional ?? 0) / underlying.CountRatio, 2), OpentAmount = Math.Round((tradeCash?.UnwindNotional * trade.TradeSinglePrice) ?? 0, 2), UnwindPrice = unwindPrice, UnwindPnl = Math.Round(unWindProfit, 2), CouponRate = Math.Round(couponRate, 2), }; if (isBuy) { reportModel.BuyClientOptionUnwinds.Add(clientOptionUnwind); } else { reportModel.SellClientOptionUnwinds.Add(clientOptionUnwind); } } /// /// 计算客户持仓情况 /// /// /// /// private void CalculateClientPosition(FinancialSummaryOptionExportModel reportModel, List tradeQuerys, IQueryable eodPositions) { foreach (var item in eodPositions) { var trade = tradeQuerys.FirstOrDefault(x => x.id == item.TradeId); if (trade==null) { continue; } bool isBuy = trade.BuySell == "卖出"; var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); if (ConsTrade.TradeCompleteStatus.Contains(trade.TradeStatus)) { continue; } var currentPrice = TradeHelper.GetTradeSinglePriceByTradePrice(YLErp.PS.Config.IsPVRounded ? item.RoundedPv * -1 : item.Pv * -1, trade.Notional, PS.Config.ErpElement.IsPVIncludePrincipal ? trade.PrincipalSum() : 0, trade.BuySell, trade.TradeType, false); ClientOptionPosition clientOptionPosition = new ClientOptionPosition() { ClientId = trade.ClientId, ClientName = trade.ClientName, TradeType = trade.TradeMultipleType, TradeNumber = trade.TradeNumber, UnderlyingCode = trade.UnderlyingCode, UnderlyingName = trade.UnderlyingName, OpenPrice = Math.Round(trade.TradeSinglePrice ?? 0, 2), Qty = Math.Round(trade.Notional / underlying.CountRatio, 2), SettlePrice = Math.Round(currentPrice, 2), StockEqvNotional = Math.Round(trade.StockEqvNotional, 2), OpentAmount = Math.Round((trade.TradeSinglePrice ?? 0) * trade.Notional, 2), PosiPnl = Math.Round(item.PositionPnL * -1, 2), CouponRate = Math.Round(item.PositionRelizedAmount, 2) }; if (isBuy) { reportModel.BuyClientOptionPositions.Add(clientOptionPosition); } else { reportModel.SellClientOptionPositions.Add(clientOptionPosition); } } } /// /// 客户买卖权合计 /// /// /// /// private void CalculateClientSummary(FinancialSummaryOptionExportModel reportModel, FinancialSummaryOptionExportModel lastMonthReportModel, List clientbalanceDailys, List lastMonthClientbalanceDailys, List allClientList, DateTime lastBalanceDate) { foreach (var client in allClientList) { var clientbalanceB = clientbalanceDailys.FirstOrDefault(x => x.ClientId == client.id && x.IsBuy && x.BalanceDate == lastBalanceDate); var clientbalanceS = clientbalanceDailys.FirstOrDefault(x => x.ClientId == client.id && !x.IsBuy && x.BalanceDate == lastBalanceDate); var clientbalanceListB = clientbalanceDailys.Where(x => x.ClientId == client.id && x.IsBuy); var clientbalanceListS = clientbalanceDailys.Where(x => x.ClientId == client.id && !x.IsBuy); var lastMothClientbalanceB = lastMonthClientbalanceDailys.FirstOrDefault(x => x.ClientId == client.id && x.IsBuy); var lastMothClientbalanceS = lastMonthClientbalanceDailys.FirstOrDefault(x => x.ClientId == client.id && !x.IsBuy); var lastMonthClientBuyPositions = lastMonthReportModel.BuyClientOptionPositions.Where(x => x.ClientId == client.id); var lastMonthClientSellPositions = lastMonthReportModel.SellClientOptionPositions.Where(x => x.ClientId == client.id); var clientBuyPositions = reportModel.BuyClientOptionPositions.Where(x => x.ClientId == client.id); var clientSellPositions = reportModel.SellClientOptionPositions.Where(x => x.ClientId == client.id); double eodAmountS = 0;//卖权期末结存 if (clientbalanceS != null) { ClientSummaryOption sellClientSummaryOption = new ClientSummaryOption() { ClientName = client.Name, }; double lastMonthToDayRemainFund = lastMothClientbalanceS?.ToDayRemainFund ?? 0; double lastMonthPosiTradePrice = lastMonthClientSellPositions.Sum(s => s.OpentAmount); sellClientSummaryOption.LastMonthRemainFund = lastMonthToDayRemainFund - lastMonthPosiTradePrice; sellClientSummaryOption.TradePrice = clientbalanceListS.Sum(s => s.OptionPremium); sellClientSummaryOption.UnwindPnl = clientbalanceListS.Sum(s => s.WinLoss); sellClientSummaryOption.PosiPnl = clientbalanceS.PositionPnl; sellClientSummaryOption.CouponRate = clientbalanceListS.Sum(s => s.Coupon); sellClientSummaryOption.PosiTradePrice = clientSellPositions.Sum(s => s.OpentAmount); sellClientSummaryOption.LastRemainFund = sellClientSummaryOption.LastMonthRemainFund + sellClientSummaryOption.UnwindPnl + sellClientSummaryOption.PosiPnl + sellClientSummaryOption.CouponRate; sellClientSummaryOption.LastRemainFundEXPosiPnl = sellClientSummaryOption.LastRemainFund - sellClientSummaryOption.PosiPnl; sellClientSummaryOption.SellEodBalance = sellClientSummaryOption.LastRemainFundEXPosiPnl + sellClientSummaryOption.PosiTradePrice; eodAmountS = sellClientSummaryOption.SellEodBalance; reportModel.SellClientSummaryOptions.Add(sellClientSummaryOption); } if (clientbalanceB != null) { ClientSummaryOption buyClientSummaryOption = new ClientSummaryOption() { ClientName = client.Name, }; var cash = Math.Abs(clientbalanceListB.Sum(s => s.InFund)) - Math.Abs(clientbalanceListB.Sum(s => s.OutFund)); if (cash > 0) { buyClientSummaryOption.CashIn = cash; } else { buyClientSummaryOption.CashOut = cash; } double lastMonthToDayRemainFund = lastMothClientbalanceB?.ToDayRemainFund ?? 0; double lastMonthPosiTradePrice = lastMonthClientBuyPositions.Sum(s => s.OpentAmount); buyClientSummaryOption.LastMonthRemainFund = lastMonthToDayRemainFund + lastMonthPosiTradePrice; buyClientSummaryOption.TradePrice = clientbalanceListB.Sum(s => s.OptionPremium); buyClientSummaryOption.TradePrice =Math.Abs( buyClientSummaryOption.TradePrice);//买方支付权利金显示为正 buyClientSummaryOption.UnwindPnl = clientbalanceListB.Sum(s => s.WinLoss); buyClientSummaryOption.PosiPnl = clientbalanceB.PositionPnl; buyClientSummaryOption.CouponRate = clientbalanceListB.Sum(s => s.Coupon); buyClientSummaryOption.PosiTradePrice = clientBuyPositions.Sum(s => s.OpentAmount); buyClientSummaryOption.LastRemainFund = buyClientSummaryOption.LastMonthRemainFund + buyClientSummaryOption.CashIn + buyClientSummaryOption.UnwindPnl + buyClientSummaryOption.PosiPnl + buyClientSummaryOption.CouponRate - buyClientSummaryOption.CashOut; buyClientSummaryOption.LastRemainFundEXPosiPnl = buyClientSummaryOption.LastRemainFund - buyClientSummaryOption.PosiPnl; buyClientSummaryOption.BuyEodBalance = buyClientSummaryOption.LastRemainFundEXPosiPnl - buyClientSummaryOption.PosiTradePrice; buyClientSummaryOption.SellEodBalance = eodAmountS; buyClientSummaryOption.EodBalance = buyClientSummaryOption.BuyEodBalance + eodAmountS; reportModel.BuyClientSummaryOptions.Add(buyClientSummaryOption); } } } } }