using BaseOUDAL; using DocumentFormat.OpenXml.Bibliography; using DocumentFormat.OpenXml.Spreadsheet; using MathNet.Numerics; using NPOI.SS.UserModel; using YLErp.BLL.Eod; using YLErp.DBModels; using YLErp.DBModels.Enums; using YLErp.Helpers; using YLErp.Model; using YLErp.Models; using YLErp.Modules; using YLErp.Modules.ClientModule; namespace YLErp.BLL.EodSettlement { /// /// 客户结算信息工具类 /// public class ClientBalanceUtility { /// /// 获取startDate至endDate 所有客户结算信息统计 /// public static IEnumerable GetAllClientBanlances(DateTime startDate, DateTime endDate, bool IsGetOuterMarginGap = false , Abstract.IDataSource clientDataSource = null) { using var db = DbContextFactory.GetClientDbContext(null); var clientIds = db.client.Where(s => s.ProcessStatus != "未提交").Select(n => n.id).ToList(); return GetClientBanlances( clientIdList: clientIds, startDate: startDate, endDate: endDate, IsGetOuterMarginGap: IsGetOuterMarginGap, clientDataSource: clientDataSource); } /// /// 获取startDate至endDate 客户结算信息统计 /// public static IEnumerable GetClientBanlances(List clientIdList , DateTime startDate, DateTime endDate, bool IsClientBalanceGap = false, bool IsGetOuterMarginGap = false, bool ParentFlag = false , Abstract.IDataSource clientDataSource = null) { if (startDate > endDate) { throw new ArgumentException("startDate不能大于endDate"); } if (null == clientIdList || !clientIdList.Any()) { return Enumerable.Empty(); } var returnClientId = clientIdList[0]; if (ParentFlag) { clientIdList = GetSubclientId(clientIdList[0]); } //一些客户在下面没有关联的数据,在这里直接赋值 var dic = clientIdList.ToHashSet().ToDictionary(n => n, m => new ClientSettleBalance { ClientId = m, ValueDate = endDate, }); foreach (var clientId in clientIdList) { var balance = dic[clientId]; var client = DataCacheProvider.GetClientDataSource().GetData(clientId); balance.DesirableRate = client?.DesirableRate ?? 0; balance.CreditCanApplySwap = client?.creditCanApplySwap ?? false; balance.ClientType = client?.SwapTradeType ?? 0; } if (PS.Config.Is广期资本) { Dictionary samePeerDic = null; using (var clientDb = DbContextFactory.GetClientDbContext(null)) { samePeerDic = clientDb.client.AsNoTracking().Where(p => clientIdList.Contains(p.id)).ToDictionary(p => p.id, p => p.SamePeer); } samePeerDic ??= new Dictionary(); foreach (var kv in dic) { kv.Value.SamePeer = samePeerDic.ContainsKey(kv.Key) ? samePeerDic[kv.Key] ?? 0 : 0; } } if (PS.Config.Is宏源) { Dictionary ratio1Dic = null; using (var clientDb = DbContextFactory.GetClientDbContext(null)) { ratio1Dic = (from c in clientDb.client join cl in clientDb.clientlevel on c.LevelId equals cl.id into t_cl from temp in t_cl.DefaultIfEmpty() where clientIdList.Contains(c.id) select new { Id = c.id, Ratio1 = temp == null ? null : temp.Ratio1 }).ToDictionary(p => p.Id, p => p.Ratio1); } ratio1Dic ??= new Dictionary(); foreach (var kv in dic) { kv.Value.Ratio1 = ratio1Dic.ContainsKey(kv.Key) ? ratio1Dic[kv.Key] ?? 1.0 : 1.0; } } var clientIdS = new List(); clientIdS.AddRange(clientIdList); using (var db = new YLContext()) { //系统交易日 var valuedate = valuedateBLL.ValueDate; var lastpushLog = db.push_log.Where(x => x.data_type == (int)SwapPushDataEnum.日终估值获取 && x.data_state == (int)SwapPushDataStateEnum.接收处理成功 && x.create_time > valuedate).OrderByDescending(o => o.create_time).FirstOrDefault(); //获取根据系统时间 var lastBalanceDate = EodOperationBase.GetLastSettlementDate(valuedate); var lastDate = lastBalanceDate; //查询历史记录 if (startDate <= lastBalanceDate) { if (endDate < lastBalanceDate) { lastDate = db.ClientBalanceDaily.Where(n => n.BalanceDate <= endDate) .Max(n => n.BalanceDate) ?? DateTime.MinValue; } var sumQuery = from t in db.ClientBalanceDaily where t.BalanceDate == lastDate && clientIdS.Contains(t.ClientId) select new ClientSettleBalance { ClientId = t.ClientId, NetFund = t.NetFundSum ?? 0, InFund = t.InFundSum ?? 0, OutFund = t.OutFundSum ?? 0, OtherFund = t.OtherFundSum ?? 0, OptionPremium = t.OptionPremiumSum ?? 0, OptionPremiumSwap = t.OptionPremiumSwapSum ?? 0, SettlementBalance = t.SettlementBalanceSum ?? 0, UnwindBalance = t.UnwindBalanceSum ?? 0, SwapBalance = t.SwapBalanceSum ?? 0, Coupon = t.CouponSum ?? 0, ExerciseBalance = t.ExerciseBalanceSum ?? 0, CashInCashOutProductChange = t.CashInCashOutProductChangeSum ?? 0, WinLoss = t.WinLossSum ?? 0, EndPremiumSum = t.EndPremiumSum ?? 0, FundJson = t.FundJson, PFE = t.PFE, EAD = t.EAD, LastSettlemetTime = t.OptDate, TradeFee = t.trade_fee_sum ?? 0, InterestPnl = t.interest_pnl_sum ?? 0 }; var sumDatas = sumQuery.ToArray(); //获取结束日期那一天的Sum总值 //例如2018-08-08到2019-08-08:区间段sum值 = sum(2019-08-08) - sum(2018-08-08) //此处取的是sum(2019-08-08) foreach (var data in sumDatas) { var balance = dic[data.ClientId]; balance.NetFund = data.NetFund; balance.InFund = data.InFund; balance.OutFund = data.OutFund; balance.OtherFund = data.OtherFund; balance.OptionPremium = data.OptionPremium; balance.OptionPremiumSwap = data.OptionPremiumSwap; balance.OptionPremiumAndSwapSum = data.OptionPremium + data.OptionPremiumSwap; balance.EndPremiumSum = data.EndPremiumSum; balance.SettlementBalance = data.SettlementBalance; balance.UnwindBalance = data.UnwindBalance; balance.ExerciseBalance = data.ExerciseBalance; balance.SwapBalance = data.SwapBalance; balance.Coupon = data.Coupon; balance.CashInCashOutProductChange = data.CashInCashOutProductChange; balance.WinLoss = data.WinLoss; balance.TradeFee = data.TradeFee; balance.InterestPnl = data.InterestPnl; //起始时间 有值 和 WinLoss 区分 -- 国投不含当天 balance.WinLossSum = data.WinLoss; balance.FundJson = data.FundJson; balance.PFE = data.PFE; balance.EAD = data.EAD; balance.LastSettlemetTime = endDate <= lastDate ? data.LastSettlemetTime : null; balance.LastHTSettlemetTime = lastpushLog == null ? "未同步" : lastpushLog.update_time.ToString("yyyy-MM-dd HH:mm:ss"); } } //-------------------------------------------- // 期末资金信息(取最新结算日当日信息) //-------------------------------------------- //当日客户资金 if (valuedate > lastBalanceDate && lastBalanceDate < endDate) { var todayClientBalance = new RealTimeClientBanlanceService(OptUserInfo.SystemUser) .GetBanlances(clientIdS, startDate > lastBalanceDate ? startDate : lastBalanceDate.AddDays(1), endDate); foreach (var data in todayClientBalance) { data.TdWinLoss = data.WinLoss; //当日实现盈亏 if (dic.TryGetValue(data.ClientId, out var balance)) { data.NetFund += balance.NetFund; data.InFund += balance.InFund; data.OutFund += balance.OutFund; data.OtherFund += balance.OtherFund; data.OptionPremium += balance.OptionPremium; data.OptionPremiumSwap += balance.OptionPremiumSwap; data.OptionPremiumAndSwapSum += balance.OptionPremium + balance.OptionPremiumSwap; data.EndPremiumSum += balance.EndPremiumSum; data.SettlementBalance += balance.SettlementBalance; data.UnwindBalance += balance.UnwindBalance; data.ExerciseBalance += balance.ExerciseBalance; data.SwapBalance += balance.SwapBalance; data.Coupon += balance.Coupon; data.CashInCashOutProductChange += balance.CashInCashOutProductChange; data.WinLoss += balance.WinLoss; data.TradeFee += balance.TradeFee; data.InterestPnl += balance.InterestPnl; //data.AvailableStockEqvNotional = balance.AvailableStockEqvNotional; data.LastSettlemetTime = balance.LastSettlemetTime; data.LastHTSettlemetTime = balance.LastHTSettlemetTime; } dic[data.ClientId] = data; data.UpdateDate = DateTime.Now; data.IsLatestDate = true; } } else { var endQuery = from t in db.ClientBalanceDaily join cs in db.client_span.Where(eod_cs => eod_cs.SpanType == ClientSpan.SpanType_Eod) on new { t.ClientId, ValueDate = t.BalanceDate } equals new { cs.ClientId, cs.ValueDate } into eodClientSpan from cs in eodClientSpan.DefaultIfEmpty() where t.BalanceDate == lastDate && clientIdS.Contains(t.ClientId) select new { ClientId = t.ClientId, FreezePremium = t.FrozenPremium ?? 0.0, ReceivablesPremium = 0.0, AmountFund = t.ToDayRemainFund ?? 0.0, GuaranteesTotalAmount = t.TodayRemianFundProduct ?? 0.0, //仅用于广期资本可用资金计算 //可用资金1 = 净入金 + 已实现盈亏 + 浮动盈亏 - 次日最大亏损; //可用资金2 = 净入金 + 已实现盈亏 - 持仓期初净支付权利金; //可用资金 = min(可用资金1,可用资金2); AvailableAmount1 = (t.NetFundSum ?? 0) + (t.WinLossSum ?? 0) + (t.PositionPnl ?? 0) + (cs.WorstCastClientPayable ?? 0), AvailableAmount2 = (t.NetFundSum ?? 0) + (t.WinLossSum ?? 0) - (t.OptionPremiumSum ?? 0) - (t.OptionPremiumSwapSum ?? 0), AvailableAmount = (t.MarginBalance ?? 0.0) + (t.PayableMargin ?? 0.0) - (t.FrozenMarginMoney ?? 0.0) - (t.TodayRemianFundProduct ?? 0.0),//t.FrozenMarginMoney是通道业务显示所用到的 TotalCredit = t.Credit ?? 0.0, PayableMargin = t.PayableMargin ?? 0.0, DeltaMargin = t.DeltaMargin ?? 0d, SwapPayableMargin = t.SwapPayableMargin ?? 0.0, SwapUnPayableMargin = t.SwapUnPayableMargin ?? 0.0, TwoSideMargin = t.TwoSideMargin ?? 0.0, OtherSideMargin = t.OtherSideMargin ?? 0.0, MySideMargin = t.MySideMargin ?? 0.0, MaintenanceMargin = cs.VariationMargin ?? 0.0, IsPayableMarginManual = t.IsPayableMarginManual, IsPayableMarginLock = cs == null ? false : cs.ModifiedFlag, FrozenMarginMoney = t.FrozenMarginMoney ?? 0.0, FrozenOutFund = t.FrozenOutFund ?? 0.0, MarginBalance = t.MarginBalance ?? 0.0, Coupon = t.Coupon ?? 0.0, SwapBalance = t.SwapBalance ?? 0.0, Margin = t.Margin ?? 0.0, //IsTradeCredit = t.IsTradeCredit ?? c.IsTradeCredit == 1, TodayNewMargin = 0, PositionPv = t.Pv ?? 0, RoundedPositionPv = t.RoundedPv ?? 0, SellPv = t.SellPv ?? 0, PrepaymentAmount = t.PrepaymentAmount ?? 0.0, DaliyPnl = t.DailyPnl ?? 0, PositionPnl = t.PositionPnl ?? 0, RoundedPositionPnl = t.RoundedPositionPnl ?? 0, ClientSellPositionPnl = t.ClientSellPositionPnl ?? 0, PositionPremiumNetCash = t.PositionPremiumNetCash ?? 0, LastDayPositionPremiumNetCash = t.LastDayPositionPremiumNetCash ?? 0, SellTradePrice = t.SellTradePrice, AvailableStockEqvNotional = t.AvailableStockEqvNotional ?? 0, FrozenBalance = t.FrozenBalance ?? 0, TdWinLoss = t.WinLoss, MarginJson = cs.PVJsons, MaintenanceLine = t.MaintenanceLine, TotalNominal = t.TotalNominal, InFundSum = t.InFundSum, OutFundSum = t.OutFundSum, VmInFundSum = t.vm_in_fund_sum, VmOutFundSum = t.vm_out_fund_sum, }; var endDatas = endQuery.ToArray(); foreach (var data in endDatas) { if (dic.TryGetValue(data.ClientId, out var balance)) { var client = DataCacheProvider.GetClientDataSource().GetData(data.ClientId); var lasttoDay = EodOperationBase.GetLastSettlementDate(lastDate, true); var lastClientBalanceDaily = db.ClientBalanceDaily.Where(a => a.BalanceDate == lasttoDay && a.ClientId == data.ClientId).FirstOrDefault(); balance.FrozenBalance = data.FrozenBalance; balance.FreezePremium = data.FreezePremium; balance.ReceivablesPremium = data.ReceivablesPremium; balance.AmountFund = data.AmountFund; balance.TotalCredit = data.TotalCredit; balance.PayableMargin = data.PayableMargin; balance.GuaranteesTotalAmount = data.GuaranteesTotalAmount; balance.FrozenMarginMoney = data.FrozenMarginMoney; balance.DaliyPnl = data.DaliyPnl; balance.RoundedDaliyPnl = data.RoundedPositionPnl - (lastClientBalanceDaily?.RoundedPositionPnl ?? 0); balance.PositionPnl = data.PositionPnl; balance.RoundedPositionPnl = data.RoundedPositionPnl; balance.DeltaMargin = data.DeltaMargin; balance.SwapPayableMargin = data.SwapPayableMargin; balance.SwapUnMargin = data.SwapUnPayableMargin; balance.TwoSideMargin = data.TwoSideMargin; balance.OtherSideMargin = data.OtherSideMargin; balance.MySideMargin = data.MySideMargin; balance.MaintenanceMargin = data.MaintenanceMargin; balance.IsPayableMarginManual = data.IsPayableMarginManual; balance.IsPayableMarginLock = data.IsPayableMarginLock; balance.FrozenMarginMoney = data.FrozenMarginMoney; balance.FrozenOutFund = data.FrozenOutFund; balance.MarginBalance = data.MarginBalance; balance.Margin = data.Margin; balance.UpdateDate = DateTime.Now; balance.IsTradeCredit = client?.IsTradeCredit == 1; balance.TodayNewMargin = data.TodayNewMargin; balance.PositionPv = data.PositionPv; balance.RoundedPositionPv = data.RoundedPositionPv; balance.SellPv = data.SellPv; balance.PrepaymentAmount = data.PrepaymentAmount; balance.ClientSellPositionPnl = data.ClientSellPositionPnl; balance.PositionPremiumNetCash = data.PositionPremiumNetCash; balance.SellTradePrice = data.SellTradePrice ?? 0; balance.LastDayPositionPremiumNetCash = data.LastDayPositionPremiumNetCash; balance.MarginOptionType = client?.MarginOptionType ?? 0; balance.IsLatestDate = true; balance.IsEodData = true; balance.TdWinLoss = data.TdWinLoss ?? 0; balance.AvailableStockEqvNotional = data.AvailableStockEqvNotional; balance.MarginJson = data.MarginJson; balance.ClientType = client.SwapTradeType ?? 0; balance.ClientName = client.Name; balance.MaintenanceLine = data.MaintenanceLine ?? 0; balance.PositionNotionalPrincipal = data.TotalNominal ?? 0; balance.OutFundSum = data.OutFundSum ?? 0; balance.InFundSum = data.InFundSum ?? 0; balance.VmInFundSum = data.VmInFundSum ?? 0; balance.VmOutFundSum = data.VmOutFundSum ?? 0; //预付金金额=期末结存-初始预付金金额 balance.MarginBalance = balance.AmountFund - balance.MySideMargin; // 可用资金 = 期末结存 - 追保账户余额 - 初始保证金 balance.AvailableAmount = balance.MarginBalance - (balance.VmInFundSum - balance.VmOutFundSum); // 是否追保=盯市金额小于维持保证金额 balance.NeedAddMargin = balance.SwapMarketAmount < balance.MaintenanceMargin; // 追保金额=初始保证金金额-盯市金额 balance.MarginByPayableMarginTotal = balance.NeedAddMargin ? (balance.MySideMargin - balance.SwapMarketAmount) : 0; // 可取资金=Math.Max(期末结存-min(持仓盈亏,0)-初始保证金,0) balance.DesirableFund = Math.Max(balance.MarginBalance + Math.Min(balance.RoundedPositionPnl, 0), 0); } } } //-------------------------------------------- //对出入金,权利金,结算收支,实现盈亏,抵押品变化区间段sum处理 //例如2018-08-08到2019-08-08:区间段sum值 = sum(2019-08-08) - sum(2018-08-07) //-------------------------------------------- if (startDate <= lastBalanceDate) { //默认期初结存为0 foreach (var balance1 in dic.Values) { balance1.LastDayRemainFund = 0; balance1.LastDayRemainFundWithProduct = 0; balance1.LastGuaranteesTotalAmount = 0; balance1.LastDayPositionPremiumNetCash = 0; } //该判断代表起始时间是选择了的,而不是空,需要区间逻辑处理 if (startDate.Year > 2008) { var query = from t in db.ClientBalanceDaily where t.BalanceDate >= startDate && t.BalanceDate <= endDate && clientIdS.Contains(t.ClientId) group t by t.ClientId into g select new { ClientId = g.Key, BalanceDate = g.Min(n => n.BalanceDate) }; var startQuery = from t in db.ClientBalanceDaily join t2 in query on new { t.ClientId, t.BalanceDate } equals new { t2.ClientId, t2.BalanceDate } select new { ClientId = t.ClientId, LastDayRemainFund = t.LastDayRemainFund ?? 0, TodayRemianFundProduct = t.TodayRemianFundProduct ?? 0, CashInCashOutProductChange = t.CashInCashOutProductChange ?? 0, LastDayPositionPremiumNetCash = t.LastDayPositionPremiumNetCash ?? 0, //此处取上一日的sum,例如sum(2018-08-07) NetFundSum = (t.NetFundSum ?? 0) - (t.NetFund ?? 0), InFundSum = (t.InFundSum ?? 0) - (t.InFund ?? 0), OutFundSum = (t.OutFundSum ?? 0) - (t.OutFund ?? 0), OtherFundSum = (t.OtherFundSum ?? 0) - (t.OtherFund ?? 0), OptionPremiumSum = (t.OptionPremiumSum ?? 0) - (t.OptionPremium ?? 0), OptionPremiumSwapSum = (t.OptionPremiumSwapSum ?? 0) - (t.OptionPremiumSwap ?? 0), SettlementBalanceSum = (t.SettlementBalanceSum ?? 0) - (t.SettlementBalance ?? 0), UnwindBalanceSum = (t.UnwindBalanceSum ?? 0) - (t.UnwindBalance ?? 0), ExerciseBalanceSum = (t.ExerciseBalanceSum ?? 0) - (t.ExerciseBalance ?? 0), SwapBalanceSum = (t.SwapBalanceSum ?? 0) - (t.SwapBalance ?? 0), CouponSum = (t.CouponSum ?? 0) - (t.Coupon ?? 0), WinLossSum = (t.WinLossSum ?? 0) - (t.WinLoss ?? 0), CashInCashOutProductChangeSum = (t.CashInCashOutProductChange ?? 0) - (t.CashInCashOutProductChange ?? 0), }; var startDatas = startQuery.ToArray(); foreach (var data in startDatas) { if (dic.TryGetValue(data.ClientId, out var balance)) { balance.LastDayRemainFund = data.LastDayRemainFund; balance.LastDayRemainFundWithProduct = data.LastDayRemainFund + data.TodayRemianFundProduct - data.CashInCashOutProductChange; balance.LastGuaranteesTotalAmount = data.TodayRemianFundProduct - data.CashInCashOutProductChange; balance.LastDayPositionPremiumNetCash = data.LastDayPositionPremiumNetCash; //例如2018-08-08到2019-08-08:区间段sum值 = sum(2019-08-08) - sum(2018-08-07) balance.NetFund -= data.NetFundSum; balance.InFund -= data.InFundSum; balance.OutFund -= data.OutFundSum; balance.OtherFund -= data.OtherFundSum; balance.OptionPremium -= data.OptionPremiumSum; balance.OptionPremiumSwap -= data.OptionPremiumSwapSum; balance.OptionPremiumAndSwapSum -= data.OptionPremiumSum + data.OptionPremiumSwapSum; balance.SettlementBalance -= data.SettlementBalanceSum; balance.UnwindBalance -= data.UnwindBalanceSum; balance.ExerciseBalance -= data.ExerciseBalanceSum; balance.SwapBalance -= data.SwapBalanceSum; balance.Coupon -= data.CouponSum; balance.CashInCashOutProductChange -= data.CashInCashOutProductChangeSum; balance.WinLoss -= data.WinLossSum; balance.WinLossSum -= balance.WinLoss; } } } } var gapList = db.ClientBalanceGap.Where(c => clientIdS.Contains(c.ClientId) && c.ValueDate == endDate).ToList(); gapList ??= new List(); if (IsClientBalanceGap || IsGetOuterMarginGap) { var ClientBalanceGap = new ClientBalanceGap(); foreach (var item in dic.Values) { if (IsClientBalanceGap) { ClientBalanceGap = gapList.FirstOrDefault(c => c.ClientId == item.ClientId && c.ValueDate == endDate && !c.IsImportOuterMargin); } if (IsGetOuterMarginGap) { ClientBalanceGap = gapList.FirstOrDefault(c => c.ClientId == item.ClientId && c.ValueDate == endDate && c.IsImportOuterMargin); } if (ClientBalanceGap != null) { if (IsClientBalanceGap) { item.ClientBalanceGap = ClientBalanceGap; item.IsGap = true; item.AmountFund += ClientBalanceGap.ToDayRemainFund ?? 0; item.AvailableAmount += (ClientBalanceGap.ToDayRemainFund ?? 0) - (ClientBalanceGap.PayableMargin ?? 0); item.NetFund += ClientBalanceGap.NetFund ?? 0; item.OptionPremium += ClientBalanceGap.OptionPremium ?? 0; item.OptionPremiumSwap += ClientBalanceGap.OptionPremiumSwap ?? 0; item.OptionPremiumAndSwapSum += ClientBalanceGap.OptionPremium ?? 0; item.OptionPremiumAndSwapSum += ClientBalanceGap.OptionPremiumSwap ?? 0; item.SettlementBalance += ClientBalanceGap.SettlementBalance ?? 0; item.Coupon += ClientBalanceGap.Coupon ?? 0; item.SwapBalance += ClientBalanceGap.SwapBalance ?? 0; item.OtherFund += ClientBalanceGap.OtherFund ?? 0; item.TotalCredit += ClientBalanceGap.Credit ?? 0; //if (ClientBalanceGap.PayableFund != null && ClientBalanceGap.PayableFund != 0) //{ // item.PayableFund += ClientBalanceGap.PayableFund ?? 0; //} //else //{ // item.MarginByPayableMargin += ClientBalanceGap.MarginByPayableMargin ?? 0; //} item.WinLoss += ClientBalanceGap.WinLoss ?? 0; item.PositionPnl += ClientBalanceGap.PositionPnl ?? 0; item.RoundedPositionPnl += ClientBalanceGap.PositionPnl ?? 0; item.PositionPv += ClientBalanceGap.PositionPv ?? 0; item.RoundedPositionPv += ClientBalanceGap.PositionPv ?? 0; } if (IsGetOuterMarginGap) { item.ClientBalanceGap = ClientBalanceGap; //(ClientBalanceGap.PayableMargin ?? 0)正数代表客户应付预付金 //item.PayableMargin负数代表客户应付预付金 //(ClientBalanceGap.PayableMargin ?? 0) + item.PayableMargin代表客户支付预付金的差额 item.AvailableAmount += (ClientBalanceGap.ToDayRemainFund ?? 0) - ((ClientBalanceGap.PayableMargin ?? 0) + item.PayableMargin); item.IsGap = true; } } } } //return dic.Values; } using (var clientDB = new ClientDBContext()) { var balance1 = dic[returnClientId]; if (!clientDB.client_Axis_Fundthresholds.Where(x => x.ClientId == returnClientId).Any() || endDate == DateTime.Today) { balance1.FundThreshold = clientDB.client.Where(n => n.id == returnClientId).Select(n => n.FundThreshold).FirstOrDefault(); } else { balance1.FundThreshold = clientDB.client_Axis_Fundthresholds.Where(x => x.ValueDate <= endDate && x.ClientId == returnClientId).OrderByDescending(x => x.ValueDate)?.FirstOrDefault()?.FundThreshold; } } if (clientDataSource != null) { foreach (var item in dic.Values) { var client = clientDataSource.GetData(item.ClientId); item.ClientNumber = client?.Number; item.ClientName = client?.Name; } } else { foreach (var item in dic.Values) { var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId); item.ClientNumber = client?.Number; item.ClientName = client?.Name; } } if (dic.Values != null && dic.Values.Count > 0) { if (PS.Config.Is宏源 || PS.Config.Company == Configuration.CompanyEnum.广发商贸) { //宏源 二次计算预付金占用及相关数据 //var clientIds = new List(); //foreach (var item in dic.Values) //{ // clientIds.Add(item.ClientId); //} var marginFactorDict = new ClientMarginTemplateService(OptUserInfo.SystemUser).GetMarginFactorDict(endDate, clientIdList, true); dic.Values.ToList().ForEach(p => p.ReCaculatePayableMargin(p.ClientId, marginFactorDict)); } } //当是单一客户的时候,或者包含子级 执行新的字段返回,其他来源使用原来字段 if (ParentFlag || clientIdList.Count() == 1) { var DicTotal = dic[returnClientId]; #region 循环统计所有客户 foreach (var dc in dic) { #region 所有客户数据进行累加 if (dc.Key == returnClientId) { DicTotal.OptionPremiumAndUnwindBalanceTotal = DicTotal.OptionPremiumAndUnwindBalance; DicTotal.MinusPayableMarginTotal = DicTotal.MinusPayableMargin; DicTotal.TotalMarginTotal = DicTotal.TotalMargin; DicTotal.RoundedTotalAmountTotal = DicTotal.RoundedTotalAmount; DicTotal.TotalAmountTotal = DicTotal.TotalAmount; DicTotal.MarginByPayableMarginTotal = DicTotal.MarginByPayableMarginTotal; //if (PS.Config.Is广期资本) //{ // DicTotal.MarginByPayableMarginTotal = Math.Max(-DicTotal.AvailableAmount, 0); //} DicTotal.ClosedTradePayableFundTotal = DicTotal.ClosedTradePayableFund; DicTotal.PositionTradePayableFundTotal = DicTotal.PositionTradePayableFund; DicTotal.PayableFundTotal = DicTotal.PayableFund; DicTotal.DesirableFundTotal = DicTotal.DesirableFund; DicTotal.TotalNetSettlementTotal = DicTotal.TotalNetSettlement; DicTotal.IsLatestDate = true; continue; } DicTotal.SettlementBalance += dc.Value.SettlementBalance; DicTotal.LastDayRemainFund += dc.Value.LastDayRemainFund; DicTotal.NetFund += dc.Value.NetFund; DicTotal.InFund += dc.Value.InFund; DicTotal.OutFund += dc.Value.OutFund; DicTotal.OptionPremium += dc.Value.OptionPremium; DicTotal.OptionPremiumSwap += dc.Value.OptionPremiumSwap; DicTotal.OptionPremiumAndSwapSum += dc.Value.OptionPremiumAndSwapSum; DicTotal.OtherFund += dc.Value.OtherFund; DicTotal.Coupon += dc.Value.Coupon; DicTotal.SwapBalance += dc.Value.SwapBalance; DicTotal.OptionPremiumAndUnwindBalanceTotal += dc.Value.OptionPremiumAndUnwindBalance; DicTotal.ExerciseBalance += dc.Value.ExerciseBalance; DicTotal.AmountFund += dc.Value.AmountFund; DicTotal.GuaranteesTotalAmount += dc.Value.GuaranteesTotalAmount; DicTotal.MinusPayableMarginTotal += dc.Value.MinusPayableMargin; DicTotal.AvailableAmount += dc.Value.AvailableAmount; DicTotal.TotalMarginTotal += dc.Value.TotalMargin; DicTotal.TotalCredit += dc.Value.TotalCredit; DicTotal.WinLoss += dc.Value.WinLoss; DicTotal.TdWinLoss += dc.Value.TdWinLoss; DicTotal.PositionPremiumNetCash += dc.Value.PositionPremiumNetCash; DicTotal.RoundedPositionPv += dc.Value.RoundedPositionPv; DicTotal.PositionPv += dc.Value.PositionPv; DicTotal.RoundedPositionPnl += dc.Value.RoundedPositionPnl; DicTotal.PositionPnl += dc.Value.PositionPnl; DicTotal.RoundedTotalAmountTotal += dc.Value.RoundedTotalAmount; DicTotal.TotalAmountTotal += dc.Value.TotalAmount; DicTotal.MarginByPayableMarginTotal += dc.Value.MarginByPayableMarginTotal; DicTotal.ClosedTradePayableFundTotal += dc.Value.ClosedTradePayableFund; DicTotal.PositionTradePayableFundTotal += dc.Value.PositionTradePayableFund; DicTotal.PayableFundTotal += dc.Value.PayableFund; DicTotal.DesirableFundTotal += dc.Value.DesirableFund; DicTotal.SellTradePrice += dc.Value.SellTradePrice; DicTotal.ClientSellPositionPnl += dc.Value.ClientSellPositionPnl; DicTotal.TotalNetSettlementTotal += dc.Value.TotalNetSettlement; DicTotal.MarginBalance += dc.Value.MarginBalance; DicTotal.FrozenMarginMoney += dc.Value.FrozenMarginMoney; DicTotal.FrozenRedeemFunds += dc.Value.FrozenRedeemFunds; //DicTotal.FundThreshold += dc.Value.FundThreshold; #endregion } #endregion } return dic.Values; } /// /// 获取历史交易中追保金额不为0的客户ids(排除对系统日实时的数据的筛选) /// /// /// public static List GetHaveMarginAmount(DateTime searchDate, string MarginShownType = "default") { //获取根据系统时间 var lastDate = searchDate;// EodOperationBase.GetLastSettlementDate(DateTime.Now.Date); var clientlist = new List(); var baseQuery = new List(); using var db = new YLContext(); switch (MarginShownType) { case "default": baseQuery = (from t in db.ClientBalanceDaily where t.BalanceDate == lastDate select new Pairs { tdaily = t, tgap = null }).ToList(); break; case "ClientBalanceGap": baseQuery = (from t in db.ClientBalanceDaily where t.BalanceDate == lastDate join tgap in db.ClientBalanceGap.Where(o => !o.IsImportOuterMargin && o.ValueDate == lastDate) on new { t.ClientId, date = t.BalanceDate ?? DateTime.MinValue } equals new { tgap.ClientId, date = tgap.ValueDate } into tempTgap from tgap in tempTgap.DefaultIfEmpty() select new Pairs { tdaily = t, tgap = tgap }).ToList(); break; case "GetOuterMargin": baseQuery = (from t in db.ClientBalanceDaily where t.BalanceDate == lastDate join tgap in db.ClientBalanceGap.Where(o => o.IsImportOuterMargin && o.ValueDate == lastDate) on new { t.ClientId, date = t.BalanceDate ?? DateTime.MinValue } equals new { tgap.ClientId, date = tgap.ValueDate } into tempTgap from tgap in tempTgap.DefaultIfEmpty() select new Pairs { tdaily = t, tgap = tgap }).ToList(); break; } if (PS.Config.Is广期资本) { //同业客户:期末结存+持仓盈亏-冻结+授信+质押市值<0,追保 //非同业客户:期末结存 + 持仓盈亏 - 预付金占用 - 冻结 + 授信 + 质押市值 < 0,追保 if (baseQuery == null || baseQuery.Count == 0) { return clientlist; } var clientIds = baseQuery.Select(p => p.tdaily.ClientId).Distinct().ToList(); //List samePeerList = null; Dictionary samePeerDic = null; using (var clientDb = DbContextFactory.GetClientDbContext(null)) { samePeerDic = clientDb.client.AsNoTracking().Where(p => clientIds.Contains(p.id)).ToDictionary(p => p.id, p => p.SamePeer); } samePeerDic ??= new Dictionary(); foreach (var t in baseQuery) { var clientId = t.tdaily.ClientId; var clientSettleBalance = new ClientSettleBalance { AmountFund = t.tdaily.ToDayRemainFund ?? 0.0, GuaranteesTotalAmount = t.tdaily.TodayRemianFundProduct ?? 0.0, PositionPnl = t.tdaily.PositionPnl ?? 0.0, FreezePremium = t.tdaily.FrozenPremium ?? 0.0, FrozenOutFund = t.tdaily.FrozenOutFund ?? 0.0, FrozenRedeemFunds = t.tdaily.FrozenRedeemFunds ?? 0.0, FrozenMarginMoney = t.tdaily.FrozenMarginMoney ?? 0.0, TotalCredit = t.tdaily.Credit ?? 0.0, PayableMargin = t.tdaily.PayableMargin ?? 0.0, PositionPremiumNetCash = t.tdaily.PositionPremiumNetCash ?? 0.0, }; if (t.tgap != null) { clientSettleBalance.ClientBalanceGap = t.tgap; clientSettleBalance.IsGap = true; } clientSettleBalance.SamePeer = samePeerDic.ContainsKey(clientId) ? samePeerDic[clientId] ?? 0 : 0; if (clientSettleBalance.OtherMarginByPayableMargin < 0) { clientlist.Add(clientId); } } } else { //-PayableMargin - Math.Max(AmountFund + ClosedTradePayableFund + PositionTradePayableFund, 0) - GuaranteesTotalAmount - TotalCredit //ClosedTradePayableFund: -1 * Math.Min(AmountFund + PositionPremiumNetCash, 0) //PositionTradePayableFund: Math.Max(PositionPremiumNetCash - Math.Max(AmountFund + PositionPremiumNetCash, 0), 0) foreach (var t in baseQuery) { var clientId = t.tdaily.ClientId; double MarginPayableMargin = 0; if (t.tgap != null) { if (t.tgap.MarginByPayableMargin != null && t.tgap.MarginByPayableMargin != 0) { MarginPayableMargin = -(t.tdaily.PayableMargin ?? 0.0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) - Math.Min((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0), 0) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0), 0), 0), 0) - (t.tdaily.TodayRemianFundProduct ?? 0.0) - (t.tdaily.Credit ?? 0.0) + (t.tgap.MarginByPayableMargin ?? 0); } else { MarginPayableMargin = -((t.tdaily.PayableMargin ?? 0.0) - (t.tgap.PayableMargin ?? 0)) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0) - Math.Min((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0), 0) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0), 0), 0), 0) - ((t.tdaily.TodayRemianFundProduct ?? 0.0) + (t.tgap.ToDayRemainFund ?? 0)) - ((t.tdaily.Credit ?? 0.0) + (t.tgap.Credit ?? 0)); } } else { MarginPayableMargin = -(t.tdaily.PayableMargin ?? 0.0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) - Math.Min((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0), 0) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0), 0), 0), 0) - (t.tdaily.TodayRemianFundProduct ?? 0.0) - (t.tdaily.Credit ?? 0.0); } if (MarginPayableMargin > 1e-3) { clientlist.Add(clientId); } } } return clientlist; } /// /// 获取当前客户中总资产小于1的客户ids(排除对系统日实时的数据的筛选) /// public static List GetTotalAssetClientIds(DateTime value) { List result = null; using (var db = new YLContext()) { var tempList = db.ClientBalanceDaily.Where(O => O.BalanceDate == value).AsEnumerable(); if (PS.Config.IsPVRounded) { result = tempList.Where(O => (O.RoundedTotalAmount ?? 0) > 1).Select(O => O.ClientId).ToList(); } else { result = tempList.Where(O => (O.TotalAmount ?? 0) > 1).Select(O => O.ClientId).ToList(); } } return result; } /// /// 获取历史交易中应付资金总额不为0的客户ids(排除对系统日实时的数据的筛选) /// public static List GetHavePayableFund(DateTime searchDate, string MarginShownType = "default") { //获取根据系统时间 var lastDate = searchDate;// EodOperationBase.GetLastSettlementDate(DateTime.Now.Date); using var db = new YLContext(); var clientlist = new List(); var baseQuery = new List(); switch (MarginShownType) { case "default": baseQuery = (from t in db.ClientBalanceDaily where t.BalanceDate == lastDate select new Pairs { tdaily = t, tgap = null }).ToList(); break; case "ClientBalanceGap": baseQuery = (from t in db.ClientBalanceDaily where t.BalanceDate == lastDate join tgap in db.ClientBalanceGap.Where(o => !o.IsImportOuterMargin && o.ValueDate == lastDate) on new { t.ClientId, date = t.BalanceDate ?? DateTime.MinValue } equals new { tgap.ClientId, date = tgap.ValueDate } into tempTgap from tgap in tempTgap.DefaultIfEmpty() select new Pairs { tdaily = t, tgap = tgap }).ToList(); break; case "GetOuterMargin": baseQuery = (from t in db.ClientBalanceDaily where t.BalanceDate == lastDate join tgap in db.ClientBalanceGap.Where(o => o.IsImportOuterMargin && o.ValueDate == lastDate) on new { t.ClientId, date = t.BalanceDate ?? DateTime.MinValue } equals new { tgap.ClientId, date = tgap.ValueDate } into tempTgap from tgap in tempTgap.DefaultIfEmpty() select new Pairs { tdaily = t, tgap = tgap }).ToList(); break; } foreach (var t in baseQuery) { var ClientId = t.tdaily.ClientId; double PayableFund = 0; if (t.tgap != null) { if (t.tgap.PayableFund != null && t.tgap.PayableFund != 0) { PayableFund = Math.Max( (-Math.Min((t.tdaily.ToDayRemainFund + t.tdaily.PositionPremiumNetCash) ?? 0, 0)) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) , 0) + Math.Max(-(t.tdaily.PayableMargin ?? 0.0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) - Math.Min((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) , 0) , 0) - (t.tdaily.TodayRemianFundProduct ?? 0.0) - (t.tdaily.Credit ?? 0.0), 0) , 0) + (t.tgap == null ? 0 : t.tgap.PayableFund ?? 0); } else { PayableFund = Math.Max( (-Math.Min(((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0) + t.tdaily.PositionPremiumNetCash) ?? 0, 0)) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) , 0) + Math.Max(-((t.tdaily.PayableMargin ?? 0.0) - (t.tgap.PayableMargin ?? 0)) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0) - Math.Min((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0 + (t.tgap.ToDayRemainFund ?? 0)) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) , 0) , 0) - (t.tdaily.TodayRemianFundProduct ?? 0.0) - ((t.tdaily.Credit ?? 0.0) + (t.tgap.Credit ?? 0)), 0) , 0); } } else { PayableFund = Math.Max( (-Math.Min((t.tdaily.ToDayRemainFund + t.tdaily.PositionPremiumNetCash) ?? 0, 0)) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) , 0) + Math.Max(-(t.tdaily.PayableMargin ?? 0.0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) - Math.Min((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) + Math.Max((t.tdaily.PositionPremiumNetCash ?? 0) - Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tdaily.PositionPremiumNetCash ?? 0) , 0) , 0) , 0) - (t.tdaily.TodayRemianFundProduct ?? 0.0) - (t.tdaily.Credit ?? 0.0), 0) , 0); } if (PayableFund > 1) { clientlist.Add(ClientId); } } return clientlist; } /// /// 对传入的客户进行指定日期有持仓记录的筛选(排除对系统日实时的数据的筛选) /// public static List GetHavePositionClientIds(DateTime searchDate) { using var db = new YLContext(); var query = from eodpos in db.eod_trade_position where eodpos.ValueDate == searchDate && eodpos.ClientId > 0 && eodpos.TradeId > 0 select eodpos.ClientId; return query.Distinct().ToList(); } /// /// 进行指定日期应付了结交易款是否大于1元的筛选(排除对系统日实时的数据的筛选) /// public static List GetClosePayableFundClientIds(DateTime searchDate, string MarginShownType = "default") { using var db = new YLContext(); var clientlist = new List(); var baseQuery = (from t in db.ClientBalanceDaily where t.BalanceDate == searchDate select t.ClientId).Distinct().ToList(); var IsGap = false; var IsOuter = false; if (MarginShownType == "ClientBalanceGap") { IsGap = true; } if (MarginShownType == "GetOuterMargin") { IsOuter = true; } var balances = GetClientBanlances(baseQuery, searchDate, searchDate, IsGap, IsOuter); foreach (var item in balances) { if (item.ClosedTradePayableFund >= 1) { clientlist.Add(item.ClientId); } } return clientlist; } /// /// /// public static IEnumerable GetClientRiskMonitor(List clientIdList, DateTime searchDate, string marginShownType) { if (null == clientIdList || !clientIdList.Any()) { return null; } //获取根据系统时间 var lastBalanceDate = EodOperationBase.GetLastSettlementDate(DateTime.Now.Date); //系统交易日 var valuedate = valuedateBLL.ValueDate; using var db = new YLContext(); var IsGap = false; var IsOuter = false; if (marginShownType == "ClientBalanceGap") { IsGap = true; } if (marginShownType == "GetOuterMargin") { IsOuter = true; } //db.SetDebugLog(); var lastClientBalances = GetClientBanlances(clientIdList, DateTime.MinValue, searchDate, IsGap, IsOuter); //历史查询,部分交易信息重新计算 if (valuedate <= lastBalanceDate || valuedate > searchDate) { //---------------------------------------- // 所有交易合计 //---------------------------------------- var allTradeQuery = from t in db.trade where t.TradeDate <= searchDate && t.ValidState != "InValid" && (t.TradeType != "结构化交易" || t.IsGroup == 1) && t.IsGroup != 2 && clientIdList.Contains(t.ClientId) && ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus) select new { t.ClientId, OriginalStockEqvNotional = t.OriginalStockEqvNotional > 0 ? t.OriginalStockEqvNotional.Value : (t.SpotPrice ?? 0.0) * (t.OriginalNotional ?? 0), BuyCount = t.BuySell == "买入" ? 0 : 1,//从客户角度看 SellCount = t.BuySell == "卖出" ? 0 : 1,//从客户角度看 TodayCount = t.TradeDate == searchDate ? 1 : 0 }; var allTradeQuerySum = from t in allTradeQuery group t by t.ClientId into g select new { ClientId = g.Key, SellNotionalPrincipal = g.Sum(a => a.SellCount * a.OriginalStockEqvNotional), BuyNotionalPrincipal = g.Sum(a => a.BuyCount * a.OriginalStockEqvNotional), BuyCount = g.Sum(n => n.BuyCount), SellCount = g.Sum(n => n.SellCount), TodayCount = g.Sum(n => n.TodayCount), TodayNotionalPrincipal = g.Sum(n => n.TodayCount * n.OriginalStockEqvNotional) }; var tradeSumDic = allTradeQuerySum.ToDictionary(n => n.ClientId); //---------------------------------------- // 交易结算预付金统计 //---------------------------------------- //组合交易和结构化交易获取的是父亲交易(不包含子交易) var tradeOriginQuery = from x in db.trade where x.ParentTradeId == 0 && x.ValidState != ConsGlobal.InValid select x; var eodTradePositionQuery = from eodTradePosition in db.eod_trade_position where eodTradePosition.ValueDate == searchDate && clientIdList.Contains(eodTradePosition.ClientId) select eodTradePosition; //组合交易和结构化交易获取的是父亲交易(不包含子交易) var eodTradeQuery = from eodTrade in db.eod_trade join tradeOrigin in tradeOriginQuery on eodTrade.TradeId equals tradeOrigin.id where eodTrade.ValueDate == searchDate && clientIdList.Contains(eodTrade.ClientId) && ConsTrade.NeedMarginTradeStatusList.Contains(eodTrade.TradeStatus) select new { eodTrade.TradeId, et = new xodTradeBase() { TradeJson = eodTrade.TradeJson } }; var positionQuery = from eodTradePosition in eodTradePositionQuery join eodTrade in db.eod_trade on eodTradePosition.TradeId equals eodTrade.TradeId where eodTrade.ValueDate == searchDate && clientIdList.Contains(eodTrade.ClientId) && ConsTrade.NeedMarginTradeStatusList.Contains(eodTrade.TradeStatus) select new { eodTrade.TradeId, ClientId = eodTrade.ClientId, et = new xodTradeBase() { TradeJson = eodTrade.TradeJson }, underlyprice = eodTradePosition.UnderlyingPrice, }; var positionQuerySum = from eodTradePosition in eodTradePositionQuery group eodTradePosition by eodTradePosition.ClientId into g select new { ClientId = g.Key, //Margin = g.Sum(n => (n.BuySell == "买入" ? -1 : 0) * n.Margin), //增加收益互换只计算主交易主交易限制,收益互换暂不考虑买卖反向 Margin = g.Sum(n => (((n.BuySell == "买入" && n.TradeType != "收益互换") || (n.TradeType == "收益互换" && n.ParentTradeId == 0)) ? -1 : 0) * n.Margin), // 收益互换预付金 SwapMargin = g.Sum(n => ((n.TradeType == "收益互换" && n.ParentTradeId == 0) ? -1 : 0) * n.Margin), // 收益互换预付金容忍金额 SwapUnMargin = g.Sum(n => ((n.TradeType == "收益互换" && n.ParentTradeId == 0) ? -1 : 0) * n.SwapUnMargin), }; var eodTrades = eodTradeQuery.ToList().Select(o => new { o.et.trade.ClientId, o.et.trade }); var positionSumDic = positionQuerySum.ToDictionary(n => n.ClientId); var positionDic = positionQuery.ToList(); //---------------------------------------- // 新交易统计 //---------------------------------------- var newTradeQuery = from t in db.trade where t.TradeDate == searchDate && t.ValidState != "InValid" && (t.TradeType != "结构化交易" || t.IsGroup == 1) && t.IsGroup != 2 && clientIdList.Contains(t.ClientId) && ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus) select new { t.id, notionalPrincipal = t.OriginalStockEqvNotional > 0 ? ((t.OriginalStockEqvNotional * t.Notional / t.OriginalNotional) ?? 0) : (t.SpotPrice ?? 0.0) * t.Notional }; var todayPostionQuery = from eodTradePosition in eodTradePositionQuery join trad in newTradeQuery on eodTradePosition.TradeId equals trad.id select new ClientBalanceEx { ClientId = eodTradePosition.ClientId, UnderlyingCode = eodTradePosition.UnderlyingCode }; var todayPostionList = todayPostionQuery.ToArray(); var todayPostionSumQuery = from t in todayPostionList group t by t.ClientId into g select new ClientBalanceEx { ClientId = g.Key }; var todayPostionSumDic = todayPostionSumQuery.ToDictionary(n => n.ClientId); var tradePostionMarginQuery = from eodTradePosition in eodTradePositionQuery select new ClientBalanceEx { ClientId = eodTradePosition.ClientId, BuyerPositionMargin = eodTradePosition.Margin * (eodTradePosition.BuySell == "买入" ? 1 : 0), }; var tradePostionMarginSumQuery = from t in tradePostionMarginQuery group t by t.ClientId into g select new ClientBalanceEx { ClientId = g.Key, BuyerPositionMargin = g.Sum(n => n.BuyerPositionMargin), }; var tradePostionMarginSumDic = tradePostionMarginSumQuery.ToDictionary(n => n.ClientId); //---------------------------------------- // //---------------------------------------- foreach (var balance in lastClientBalances) { if (tradeSumDic.TryGetValue(balance.ClientId, out var dicItem)) { balance.SellNotionalPrincipal = dicItem.SellNotionalPrincipal; balance.BuyNotionalPrincipal = dicItem.BuyNotionalPrincipal; balance.BuyCount = dicItem.BuyCount; balance.SellCount = dicItem.SellCount; balance.TradeCount = dicItem.TodayCount; balance.TodayNotionalPrincipal = dicItem.TodayNotionalPrincipal; balance.TotalNotionalPrincipal = balance.SellNotionalPrincipal + balance.BuyNotionalPrincipal; balance.TotalTradeCount = balance.BuyCount + balance.SellCount; } if (positionSumDic.TryGetValue(balance.ClientId, out var dicItem2)) { balance.TodayNewMargin = dicItem2.Margin; } balance.PositionCount = eodTrades.Where(x => x.ClientId == balance.ClientId).Count(); balance.SellerPositionPremium = eodTrades.Where(o => o.ClientId == balance.ClientId).Sum(o => (o.trade.TradePrice ?? 0) * (o.trade.BuySell == "买入" ? 0 : 1)); balance.PositionNotionalPrincipal = eodTrades.Where(o => o.ClientId == balance.ClientId).Sum(o => o.trade.StockEqvNotional); if (tradePostionMarginSumDic.TryGetValue(balance.ClientId, out var dicItem4)) { balance.BuyerPositionMargin = dicItem4.BuyerPositionMargin; } if (IsOuter) { balance.MySideMargin = balance.PayableMargin; } } } if (searchDate > lastBalanceDate) { //get nowTime SellerPositionPremium BuyerPositionMargin //get postion trade var suspensionUnderlyingIdList = DataCacheProvider.GetUnderlyingDataSource().AsQueryable() .Where(t => t.UnderlyingStatus == underlying_manager.Status_Suspension).Select(t => t.id).ToList(); var predicate = PredicateBuilder.Create(t => t.ClientId > 0 && ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus) && (t.TradeType != "结构化交易" && t.IsGroup != 1 || t.IsGroup == 1 && t.TradeType == "结构化交易") && (t.IsGroup != 2 || t.IsGroup == 2 && t.TradeType == "收益互换") && t.ValidState != ConsGlobal.InValid && (t.ExerciseDate >= searchDate || suspensionUnderlyingIdList.Contains(t.UnderlyingId))); if (clientIdList != null && clientIdList.Count() > 0) { predicate = predicate.And(t => clientIdList.Contains(t.ClientId)); } var positionTradeQuery = from t in db.trade.Where(predicate) join i in db.intraday_trade_position on t.id equals i.TradeId join risk in db.realtime_trade_risk.Where(tr => tr.ValueDate == searchDate && tr.VolType == "持仓") on t.id equals risk.TradeId into risks from risk in risks.DefaultIfEmpty() select new ClientBalanceEx { ClientId = t.ClientId, SellerPositionPremium = (t.TradePrice ?? 0) * (t.BuySell == "买入" ? 0 : 1), BuyerPositionMargin = i.Margin * (t.BuySell == "买入" ? 1 : 0), PositionNotionalPrincipal = t.StockEqvNotional, }; var positionTradeSumQuery = from t in positionTradeQuery group t by t.ClientId into g select new ClientBalanceEx { ClientId = g.Key, SellerPositionPremium = g.Sum(n => n.SellerPositionPremium), BuyerPositionMargin = g.Sum(n => n.BuyerPositionMargin), PositionNotionalPrincipal = g.Sum(n => n.PositionNotionalPrincipal), }; var tradePostionMarginSumDic = positionTradeSumQuery.ToDictionary(n => n.ClientId); foreach (var balance in lastClientBalances) { if (tradePostionMarginSumDic.TryGetValue(balance.ClientId, out var dicItem1)) { balance.SellerPositionPremium = dicItem1.SellerPositionPremium; balance.BuyerPositionMargin = dicItem1.BuyerPositionMargin; balance.PositionNotionalPrincipal = dicItem1.PositionNotionalPrincipal; } } // } return lastClientBalances; } /// /// 为山西固收而写,因为GetClientBanlances已经拿了历史跟最新,不需要再判断是历史还是最新 /// /// /// /// /// public static IEnumerable GetClientRiskMonitorForShanXiGuShou(List clientIdList, DateTime searchDate, string marginShownType) { if (null == clientIdList || !clientIdList.Any()) { return null; } //获取根据系统时间 var lastBalanceDate = EodOperationBase.GetLastSettlementDate(DateTime.Now.Date); //系统交易日 var valuedate = valuedateBLL.ValueDate; using var db = new YLContext(); var IsGap = false; var IsOuter = false; if (marginShownType == "ClientBalanceGap") { IsGap = true; } if (marginShownType == "GetOuterMargin") { IsOuter = true; } var lastClientBalances = GetClientBanlances(clientIdList, DateTime.MinValue, searchDate, IsGap, IsOuter); if (valuedate <= lastBalanceDate || valuedate > searchDate) { //---------------------------------------- // 所有交易合计 //---------------------------------------- var allTradeQuery = from t in db.trade where t.TradeDate <= searchDate && t.ValidState != "InValid" && t.TradeType == "收益互换" && clientIdList.Contains(t.ClientId) && ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus) select new { t.id, t.ClientId, OriginalStockEqvNotional = t.OriginalStockEqvNotional > 0 ? t.OriginalStockEqvNotional.Value : (t.SpotPrice ?? 0.0) * (t.OriginalNotional ?? 0), BuyCount = t.BuySell == "买入" ? 0 : 1,//从客户角度看 SellCount = t.BuySell == "卖出" ? 0 : 1,//从客户角度看 TodayCount = t.TradeDate == searchDate ? 1 : 0 }; var allTradeQuerySum = from t in allTradeQuery group t by t.ClientId into g select new { ClientId = g.Key, SellNotionalPrincipal = g.Sum(a => a.SellCount * a.OriginalStockEqvNotional), BuyNotionalPrincipal = g.Sum(a => a.BuyCount * a.OriginalStockEqvNotional), BuyCount = g.Sum(n => n.BuyCount), SellCount = g.Sum(n => n.SellCount), TodayCount = g.Sum(n => n.TodayCount), TodayNotionalPrincipal = g.Sum(n => n.TodayCount * n.OriginalStockEqvNotional) }; var tradeSumDic = allTradeQuerySum.ToDictionary(n => n.ClientId); var tradePosiQuery = from t in allTradeQuery join p in db.eod_swap_position on t.id equals p.SwapTradeId where !p.Invalid select new { t.id, t.ClientId, p }; foreach (var balance in lastClientBalances) { if (tradeSumDic.TryGetValue(balance.ClientId, out var dicItem)) { balance.SellNotionalPrincipal = dicItem.SellNotionalPrincipal; balance.BuyNotionalPrincipal = dicItem.BuyNotionalPrincipal; balance.BuyCount = dicItem.BuyCount; balance.SellCount = dicItem.SellCount; balance.TradeCount = dicItem.TodayCount; balance.TodayNotionalPrincipal = dicItem.TodayNotionalPrincipal; balance.TotalNotionalPrincipal = balance.SellNotionalPrincipal + balance.BuyNotionalPrincipal; balance.TotalTradeCount = balance.BuyCount + balance.SellCount; } var clientTradePosiQuery = tradePosiQuery.Where(x => x.ClientId == balance.ClientId && x.p.PosiQuantity > 0 && x.p.ValueDate == searchDate); balance.PositionCount = clientTradePosiQuery.Select(s => s.id).Distinct().Count(); var PosiNotionalValue = clientTradePosiQuery.Sum(o => o.p.PosiNotionalValue); balance.PositionNotionalPrincipal = Convert.ToDouble(PosiNotionalValue); } } return lastClientBalances; } public static void FillClientBalanceHisTradeFee() { List marginTypes = new List() { (int)InterestModeEnum.追加预付金, (int)InterestModeEnum.初始预付金 }; var clients = DataCacheProvider.GetClientDataSource().AsQueryable().Where(x => x.ProcessStatus == "已开户").ToList(); using var db = new YLContext(); var firstEodStatusDate = db.eodStatus.OrderBy(o => o.ValueDate).FirstOrDefault(); if (firstEodStatusDate != null) { var firstDate = firstEodStatusDate.ValueDate; var preBalanceDate = valuedateBLL.GetNonHolidayDefore(valuedateBLL.ValueDate.AddDays(-1)); while (firstDate < valuedateBLL.ValueDate) { foreach (var client in clients) { var interestPnl = 0d; var tradeFee = 0d; var clientBalance = db.ClientBalanceDaily.FirstOrDefault(x => x.ClientId == client.id && x.BalanceDate == firstDate); var clientBalancePre = db.ClientBalanceDaily.FirstOrDefault(x => x.ClientId == client.id && x.BalanceDate == preBalanceDate); if (clientBalance != null) { // 互换平仓信息 var clientEventFlowQuery = from eod in db.swap_flow_event.Where(x => x.EventDate <= firstDate && x.EventDate > preBalanceDate && x.ClientId == client.id && x.DataState == (int)SwapFlowDateStateEnum.完成 && x.EventType == (int)SwapFlowEventTypeEnum.平仓) join t in db.trade.Where(x => x.TradeType == "收益互换" && x.ValidState != ConsGlobal.InValid) on eod.SwapTradeId equals t.id select eod; var clientEodSwaps = clientEventFlowQuery.ToList(); foreach (var item in clientEodSwaps.GroupBy(x => x.SwapTradeId)) { var eventPosis = item.Where(t => t.PayDirection > 0).ToList(); var eventInterests = item.Where(t => t.PayDirection == 0).ToList(); interestPnl += Convert.ToDouble(eventInterests.Sum(s => s.InterestClosePnL)) * (-1); tradeFee += Convert.ToDouble(eventPosis.Sum(s => s.TradingFee + s.TradingFeePending)) * (-1); } clientBalance.trade_fee = tradeFee; clientBalance.interest_pnl = interestPnl; clientBalance.trade_fee_sum = clientBalance.trade_fee; clientBalance.interest_pnl_sum = clientBalance.interest_pnl; if (clientBalancePre != null) { clientBalance.trade_fee_sum += clientBalancePre.trade_fee_sum; clientBalance.interest_pnl_sum += clientBalancePre.interest_pnl_sum; } db.SaveChanges(); } } preBalanceDate = firstDate; firstDate = valuedateBLL.GetNonHoliday(firstDate.AddDays(1)); } } } /// /// 获取预付金率设置 /// /// /// /// private static client_marginrate GetClientMarginRate(int clientId, List clientMarginTemplates) { var marinRate = clientMarginTemplates.Where(x => x.ClientId == clientId).FirstOrDefault(); if (marinRate == null) { marinRate = clientMarginTemplates.Where(x => x.ClientId == 0).FirstOrDefault(); } if (marinRate == null) { marinRate = new client_marginrate { InitMarginRate = 1, MaintenanceRate = 1, }; } return marinRate; } class ClientBalanceEx : ClientSettleBalance { public string UnderlyingCode { get; set; } } class Pairs { public ClientBalanceDaily tdaily { get; set; } public ClientBalanceGap tgap { get; set; } } /// /// 获取所有子客户id /// public static List GetSubclientId(int id) { return InnerGetSubclientId(id, new HashSet()); } private static List InnerGetSubclientId(int id, HashSet checkSet) { checkSet ??= new HashSet(); if (!checkSet.Add(id)) { checkSet.Clear(); var pid = id; var list = new List(); for (var i = 0; i < 100; i++) { if (pid <= 0 || !checkSet.Add(pid)) break; var client = DataCacheProvider.GetClientDataSource().GetData(pid); if (client == null) { break; } else { list.Add(client.Name); pid = client.ParentId; } } if (list.Count > 0) { list.Add(list[0]); } throw new ServiceFaultException("客户父子关系产生了循环依赖:" + string.Join("->", list)); } var result = new List() { id }; var clientIdList = DataCacheProvider.GetClientDataSource().AsQueryable(O => O.ParentId == id).Select(O => O.id).ToList(); foreach (var c in clientIdList) { result.AddRange(InnerGetSubclientId(c, checkSet)); } return result; } public static List queryClientRiskMonitor(ClientRiskMonitorReq req) { if (!req.SearchDate.HasValue) { req.SearchDate = valuedateBLL.ValueDate; } if (string.IsNullOrWhiteSpace(req.marginShownType)) { req.marginShownType = "default"; } if (req.ClientIds == null || req.ClientIds.Count <= 0) { var clientService = new ClientQueryService(OptUserInfo.SystemUser); var predicate = clientService.CreatePredicate(new ClientReq() { ValueDate = req.SearchDate }); req.ClientIds = clientService.GetClientListByWhere(predicate).Select(o => o.id).Distinct().ToList(); } var result = ClientBalanceUtility.GetClientRiskMonitorForShanXiGuShou(req.ClientIds, req.SearchDate.Value, req.marginShownType); if (result == null) { return new List(); } var roundFunc = new Func(O => Math.Round(O, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero)); //精简字段 var resultList = result.Select(item => new ClientBalanceView { ValueDate = req.SearchDate.Value, Number = item.ClientNumber ?? "", Name = item.ClientName ?? "", TotalTradeCount = item.TotalTradeCount, TotalNotionalPrincipal = roundFunc(item.TotalNotionalPrincipal), TransactionPenNumber = item.TradeCount, TodayNotionalPrincipal = roundFunc(item.TodayNotionalPrincipal), PositionNotionalPrincipal = roundFunc(item.PositionNotionalPrincipal), CurrentHoldingPenNumber = item.PositionCount, WinLoss = roundFunc(item.WinLoss), PositionPnl = roundFunc(item.PositionPnl), RoundedPositionPnl = roundFunc(item.RoundedPositionPnl), LastDayRemainFund = roundFunc(item.LastDayRemainFund), NetFundAll = roundFunc(item.NetFundAll), NetFund = roundFunc(item.NetFund), VmFundSum = roundFunc(item.VmFundSum), OtherFund = roundFunc(item.OtherFund), AmountFund = roundFunc(item.AmountFund), MySideMargin = roundFunc(item.MySideMargin), MaintenanceMargin = roundFunc(item.MaintenanceMargin), SwapMarketAmount = roundFunc(item.SwapMarketAmount), SwapMarketAmountPercent = item.SwapMarketAmountPercent, AvailableAmount = roundFunc(item.AvailableAmount), InsuredAmount = roundFunc(item.MarginByPayableMarginTotal), DesirableFund = roundFunc(item.DesirableFund), TradeFee = roundFunc(item.TradeFee), InterestPnl = roundFunc(item.InterestPnl), Updatetime = DateTime.Now }).ToList(); return resultList; } /// /// 保存客户资金监控结果, 用于浙商数据采集 /// /// public static void saveClientRiskMonitor(DateTime valueDate) { LogFactory.GetLogger("saveClientRiskMonitor").Info($"开始执行 {valueDate:yyyy-MM-dd} 数据落库操作"); var req = new ClientRiskMonitorReq { SearchDate = valueDate }; var list = queryClientRiskMonitor(req); if (list.Count == 0) { LogFactory.GetLogger("saveClientRiskMonitor").Info($"{valueDate:yyyy-MM-dd} 记录数为0,跳过落库"); } using (var db = new YLContext()) { db.BulkDelete($"ValueDate='{valueDate:yyyy-MM-dd}'"); db.clientBalanceView.AddRange(list); db.SaveChanges(); } LogFactory.GetLogger("saveClientRiskMonitor").Info($"{valueDate:yyyy-MM-dd} 记录数为{list.Count},落库完成"); } public class ClientRiskMonitorReq { public List ClientIds { get; set; } public DateTime? SearchDate { get; set; } public string marginShownType { get; set; } } } }