using Qdp.Pricing.Library.Base.Utilities; using System.Linq; using YLErp.Abstract.DataProviders; using YLErp.BLL.Calculation; using YLErp.Enums; using YLErp.Helpers; using YLErp.Model.Enum; using YLErp.Modules.ApiModule; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.QdpModule; namespace YLErp.BLL.MarginCalculation { /// /// 广期资本 /// public class GQMarginCalculation : MarginCalculationBase { // 定义一个静态变量来保存类的实例 public static readonly GQMarginCalculation Instance; static GQMarginCalculation() { Instance = new GQMarginCalculation(); } // 定义私有构造函数,使外界不能创建该类实例 protected GQMarginCalculation() { } public override List RunMarginCalculation(RunMarginCalculationReq req) { var resultMap = new List(); resultMap.AddRange(marginCalculation(req)); return resultMap; } /// /// 计算同一交易 /// /// /// private List marginCalculation(RunMarginCalculationReq req) { //结果集 var resultMap = new Dictionary(); var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); //var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); //为了算客户角度的一个预付金数值 helper.ReverseTradeSide(); helper.SetFieldsByTradeType(); //取出张跌停价格 helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); //up涨停价 //down跌停价 //normal期权价 var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) };//期初价格 foreach (var price in prices) { var key = $"{price.Item1}"; //计算交易风险指标 计算Pv var tradeRiskResult2 = CalculatorHelper.CalculateRisksForTrades( valueDate: req.settleDate, tradeList: req.tradeList, calcScenario: req.GetCalcScenario(),//日终持仓预付金 priceProvider: price.Item2,//计算接口期初价格 pricingRequest: QdpPricingRequest.PV_ONLY, addVolRateDic: null, volType: req.volType, isUseTradeVol: PS.Config.IsTradeVol, preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, isAddVolPercent: false); if (tradeRiskResult2.Results == null || tradeRiskResult2.Results.Count < 1) { continue; } foreach (var item in tradeRiskResult2.Results) { //var client= helper.GetClient(item.Trade.ClientId); //获取交易值和span var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); var value = item.ValueResult.Pv; if (!contains) { resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); } switch (key) { //算出三个pv case "up": tempTradeSpan.Spv1 = value; break; case "normal": tempTradeSpan.Spv2 = value; tempTradeSpan.Comment += " normal:" + item.ValueResult.Pv.ToString() + " ;"; break; case "down": tempTradeSpan.Spv3 = value; tempTradeSpan.Comment += " down:" + item.ValueResult.Pv.ToString() + " ;"; break; } // tempTradeSpan.Spv4 = item.Trade.TradePrice; double key_up = 0; double key_down = 0; //该笔交易涨跌停盈亏为卖出并且期初权利金为0 if (contains && item.Trade.BuySell == "卖出" && item.Trade.TradePrice != 0) { key_up = Math.Max((tempTradeSpan.Spv1 ?? 0) - (tempTradeSpan.Spv2 ?? 0), 0); logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 卖出并且期初权利金不为0涨盈亏为:{key_up} PV1-PV{tempTradeSpan.Spv1}-{tempTradeSpan.Spv2}"); } else { key_up = (tempTradeSpan.Spv1 ?? 0) - (tempTradeSpan.Spv2 ?? 0); logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 涨盈亏为:{key_up} PV1-PV{tempTradeSpan.Spv1}-{tempTradeSpan.Spv2}"); } //跌停盈亏 if (contains && item.Trade.BuySell == "卖出" && item.Trade.TradePrice != 0) { key_down = Math.Max((tempTradeSpan.Spv3 ?? 0) - (tempTradeSpan.Spv2 ?? 0), 0); logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 卖出并且期初权利金不为0跌盈亏为:{key_down} PV-PV2{tempTradeSpan.Spv2}-{tempTradeSpan.Spv3} "); } else { key_down = (tempTradeSpan.Spv3 ?? 0) - (tempTradeSpan.Spv2 ?? 0); logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 跌盈亏为:{key_down} PV-PV2{tempTradeSpan.Spv2}-{tempTradeSpan.Spv3} "); } tempTradeSpan.WorstCastClientPayable = Math.Max(key_up, key_down); LogFactory.GetLogger("涨跌盈亏最大").Info(tempTradeSpan.WorstCastClientPayable.ToString()); } } return resultMap.Values.ToList(); } /// /// 计算同一客户 /// /// /// public override List CalcClientMargin(CalcClientMarginReq req) { var clientSpanNews = new List(); using (var db = new YLContext()) { if (req.tradeSpans != null && req.tradeSpans.Count > 0) { var trades = req.tradeSpans; var clientGroups = req.tradeSpans.GroupBy(t => t.ClientId); foreach (var clientGroup in clientGroups) { var underlyingMarginDic = new Dictionary(); var vIds = clientGroup.Select(o => o.VarietyId).Distinct();//所有品种 //计算出所有标的pv foreach (var ts in clientGroup) { var td = trades.FirstOrDefault(o => o.id == ts.TradeId); var key = ts.UnderlyingCode + "_" + ts.VarietyId.ToString();// + "_" + td.BuySell;标的 ///VarietyId品种ID if (!underlyingMarginDic.ContainsKey(key)) { underlyingMarginDic.Add(key, new double?[3] { ts.Spv1, ts.Spv2, ts.Spv3 }); } else { var us = underlyingMarginDic[key]; us[0] += ts.Spv1; us[1] += ts.Spv2; us[2] += ts.Spv3; } } //标的层面的盈亏 var underlyingMargins = new Dictionary(); var VarietyMarginsByUpDown = new Dictionary(); var VarietyMargins = new Dictionary(); foreach (var item in underlyingMarginDic) { var uvCode = item.Key; var key_up = uvCode + "_up"; //uvCode.Split('_')[0] + "_" + uvCode.Split('_')[1] var key_down = uvCode + "_down"; if (!underlyingMargins.ContainsKey(key_up)) { //与0相比取最大 underlyingMargins.Add(key_up, Math.Max((item.Value[0] ?? 0) - (item.Value[1] ?? 0), 0)); LogFactory.GetLogger("标的合约下所有的盈利合计= pv1-pv").Info($"{underlyingMargins.Values.ToString()}={(item.Value[0] ?? 0)} -{(item.Value[1] ?? 0)},0)"); } if (!underlyingMargins.ContainsKey(key_down)) { //与0相比 underlyingMargins.Add(key_down, Math.Max((item.Value[2] ?? 0) - (item.Value[1] ?? 0), 0)); LogFactory.GetLogger("标的合约下所有的亏损合计= pv-pv2").Info($"{underlyingMargins.Values.ToString()}={(item.Value[1] ?? 0)} -{(item.Value[2] ?? 0)},0)"); } } //计算同一客户单品标的合约盈亏累计的和 A00_Id_up/down foreach (var item in underlyingMargins) { //品种 标的id盈亏 var uvCode = item.Key; var vId = uvCode.Split('_')[1]; var upDown = uvCode.Split('_')[2]; vId = vId + upDown; if (VarietyMarginsByUpDown.ContainsKey(vId)) { //所有盈亏累加 VarietyMarginsByUpDown[vId] += item.Value; LogFactory.GetLogger("计算同一客户单品盈亏总和累计").Info(VarietyMarginsByUpDown[vId].ToString()); } else { VarietyMarginsByUpDown.Add(vId, item.Value); LogFactory.GetLogger("1计算同一客户单品盈亏总和累计").Info(VarietyMarginsByUpDown[vId].ToString()); } } //根据客户涨跌停品种取出合计 foreach (var item in vIds) { var upCode = item.ToString() + "up"; var downCode = item.ToString() + "down"; try { var upMargin = VarietyMarginsByUpDown[upCode]; var downMargin = VarietyMarginsByUpDown[downCode]; if (!VarietyMargins.ContainsKey(item.ToString())) { //取最大 VarietyMargins.Add(item.ToString(), Math.Max(upMargin, downMargin)); LogFactory.GetLogger("客户涨跌停盈亏分别为:").Info($"{upMargin},{downMargin}"); LogFactory.GetLogger("根据客户涨跌停品种判断取出合计").Info(VarietyMargins.Values.ToString()); } } catch (Exception) { VarietyMargins.Add(item.ToString(), 0); } } foreach (var item in VarietyMargins) { if (int.TryParse(item.Key, out int varietyId)) { //根据品种 var varietyGroup = clientGroup.Where(o => o.VarietyId == varietyId); //var tradePricedic = trades.GroupBy(l => new { l.ClientId }).(tradePricedic.Where(t => t.kv == ts.VarietyId && t.kc == ts.ClientId).FirstOrDefault()?.v) ?item.Value : 0; //Select(s => new { kc = s.Key.ClientId, v = Math.Min(s.Sum(item.Key) ?? 0,0) }); var t = 0; foreach (var ts in varietyGroup) { //所有单客户品种所有标的期初取最小 //因为不与单客户收支比较因此取客户涨停盈亏合计 // var sh = Math.Max(varietyGroup.Sum(s => s.Spv4) ?? 0, 0); //单品种维持预付金 var aa = item.Value; //> sh ? item.Value : 0; var dbts = db.trade_span.FirstOrDefault(o => o.id == ts.id); if (dbts != null) { dbts.WorstCastClientPayable = t == 0 ? aa : 0;//将多笔交易放到一笔交易 logger.Info($"单客户涨跌停品种盈亏合计为{aa}"); } var dbts1 = req.tradeSpans.FirstOrDefault(o => o.id == ts.id); dbts1.WorstCastClientPayable = t == 0 ? aa : 0; t++; } } } //所有品种维持预付金加总 var clientSpan = new ClientSpan { ClientId = clientGroup.Key ?? 0, ValueDate = req.settleDate, //负数代表客户应缴预付金,正数代表客户应收预付金 WorstCastClientPayable = req.tradeSpans.Where(O => O.ClientId == (clientGroup.Key ?? 0)).Sum(O => O.WorstCastClientPayable ?? 0) * -1, OptId = req.userId, OptName = req.userName, OptDate = DateTime.Now, SpanType = req.SpanType, AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key ?? 0, out var dd) ? dd : 0 }; LogFactory.GetLogger("该客户当日维持预付金所有预付金总和:").Info(clientSpan.ToString()); LogFactory.GetLogger("该客户当日维持预付金所有预付金VarietyMargins总和:").Info(clientSpan.VariationMargin.ToString()); clientSpanNews.Add(clientSpan); } } //span类型为实时删除所有实时计算的交易的预付金信息 if (req.SpanType == ClientSpan.SpanType_RealTime) { if (req.RefreshClientIds != null) { db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); } else { db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); } } else { if (req.ClientIds != null) { var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; db.BulkDelete(sql, new { ids = req.ClientIds }); } else { var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; db.BulkDelete(sql); } var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag).ToList(); clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); } if (clientSpanNews.Count > 0) { db.client_span.AddRange(clientSpanNews); } db.SaveChanges(); return req.tradeSpans; } } public override double GetTradeMargin(GetTradeMarginReq req) { using (var db = new YLContext()) { if (req.trade.TradeType == "结构化交易") { req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); } } var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); if (null != tradeMargin) { return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; } return 0.0; } } }