using Qdp.Pricing.Base.Implementations; using YLErp.BLL.Calculation; using YLErp.Enums; using YLErp.Helpers; using YLErp.Model.Enum; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.Modules.MarginModule; namespace YLErp.BLL.MarginCalculation { public class GDGZMarginCalculation : MarginCalculationBase { // 定义一个静态变量来保存类的实例(单例模式) public static readonly GDGZMarginCalculation Instance; static GDGZMarginCalculation() { Instance = new GDGZMarginCalculation(); } // 定义私有构造函数,使外界不能创建该类实例 private GDGZMarginCalculation() { } public override List RunMarginCalculation(RunMarginCalculationReq req) { if (req.tradeList == null || !req.tradeList.Any()) { return new List(0); } return new InnerRunMarginCalculation(req, _underlyingDataProvider).CalcMargin(); } public override List CalcClientMargin(CalcClientMarginReq req) { var clientSpanNews = new List(); using (var db = new YLContext()) { if (req.tradeSpans != null && req.tradeSpans.Count > 0) { var clientGroups = req.tradeSpans.GroupBy(t => t.ClientId); foreach (var clientGroup in clientGroups) { var clientSpan = new ClientSpan { ClientId = clientGroup.Key ?? 0, ValueDate = req.settleDate, //负数代表客户应缴预付金,正数代表客户应收预付金 WorstCastClientPayable = -clientGroup.Sum(g => g.WorstCastClientPayable), 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 }; 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; } /// /// 内部计算交易预付金类 /// class InnerRunMarginCalculation { readonly RunMarginCalculationReq _req; readonly List _tradeSpans; readonly bool _isInitialMargin; readonly RunMarginCalculationHelper _helper; MarginParamProvider _mpProvider; public InnerRunMarginCalculation(RunMarginCalculationReq req, UnderlyingDataProvider underlyingDataProvider) { _req = req; _tradeSpans = new List(); _isInitialMargin = req.CalcMarginType == CalcMarginTypeEnum.InitialMargin; _helper = new RunMarginCalculationHelper(_req, underlyingDataProvider); } public List CalcMargin() { _tradeSpans.Clear(); if (_req.tradeList == null || !_req.tradeList.Any()) { return _tradeSpans; } //设置详细信息 _helper.SetFieldsByTradeType(); //计算一组数据的交易风险指标 var calcReq = _helper.GetCalculateRisksForTradesReq( priceProvider: _req.PriceProvider, addVolRateDic: null, overrideVols: null, pricingRequest: PricingRequest.Pv | PricingRequest.Delta | PricingRequest.Gamma); var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); if (tradeRiskResult.Results.Count < 1) { return _tradeSpans; } //跨式组合 var tradeStraddleList = new List(); //结构化交易组合 var tradeStructureList = new List(); //这个循环只处理最简单的情况 foreach (var item in tradeRiskResult.Results) { if (item.Trade.StructureType == "跨式组合" || item.Trade.StructureType == "宽跨式组合") { tradeStraddleList.Add(item); } else if (item.Trade.StructureType == "结构化交易") { tradeStructureList.Add(item); } else { ProcessSingleTrade(item); } } //处理跨式交易 var groups = tradeStraddleList.GroupBy(n => n.Trade.ParentTradeId); foreach (var grp in groups) { ProcessStraddleTrades(grp.ToArray()); } //处理结构化组合交易 groups = tradeStructureList.GroupBy(n => n.Trade.ParentTradeId); foreach (var grp in groups) { ProcessStructureTrades(grp.ToArray()); } return _tradeSpans; } /// /// 处理单个交易 /// private void ProcessSingleTrade(TradeRiskResultRecord item) { var margin = GetUpDownEffectValue(item.ValueResult, out var updownLimit); if (!_isInitialMargin) { margin += item.ValueResult.Pv; margin = GetRealMargin(margin, item.Trade.BuySell, item.Trade.ClientId, out _); } else if (item.Trade.BuySell == "卖出") { margin = -margin; } var tradeSpan = _helper.CreateTradeSpan(item.Trade).SetAllSpvAndWorst(margin); tradeSpan.Comment = GetComment(item.ValueResult, updownLimit); _tradeSpans.Add(tradeSpan); } /// /// 处理跨式交易 /// private void ProcessStraddleTrades(TradeRiskResultRecord[] items) { var firstItem = items[0]; //组内只有一条交易 if (items.Length == 1) { ProcessSingleTrade(firstItem); return; } //初始预付金:两腿初始预付金平分 //跨式组合的两腿交易方向是一致的 if (_isInitialMargin) { var spans1 = items.Select(n => { var tradeSpan = _helper.CreateTradeSpan(n.Trade); tradeSpan.WorstCastClientPayable = n.ValueResult.Pv + GetUpDownEffectValue(n.ValueResult, out var updownLimit); tradeSpan.Comment = GetComment(n.ValueResult, updownLimit); return tradeSpan; }).ToArray(); var margin = spans1.Average(n => n.WorstCastClientPayable ?? 0); if (firstItem.Trade.BuySell == "卖出") { margin = -margin; } foreach (var span in spans1) { span.SetAllSpvAndWorst(margin); } _tradeSpans.AddRange(spans1); return; } //持仓预付金 //一腿预付金为期末结算收支 //另一腿预付金为期末结算收支+两腿标的涨跌停造成期权价值变化孰大者 var maxEffectVal = 0d; var lastItem = items.Last(); InnerClient client = null; var spans2 = items.Select(n => { var effectVal = GetUpDownEffectValue(n.ValueResult, out var updownLimit); maxEffectVal = Math.Max(maxEffectVal, effectVal); var tradeSpan = _helper.CreateTradeSpan(n.Trade); tradeSpan.Comment = GetComment(n.ValueResult, updownLimit); var margin = n == lastItem ? n.ValueResult.Pv + maxEffectVal : n.ValueResult.Pv; if (client != null && client.ClientId == n.Trade.ClientId) { margin = GetRealMargin(margin, n.Trade.BuySell, (MarginOptionEnum)client.MarginOptionType); } else { margin = GetRealMargin(margin, n.Trade.BuySell, n.Trade.ClientId, out client); } //设置预付金 tradeSpan.SetAllSpvAndWorst(margin); return tradeSpan; }); _tradeSpans.AddRange(spans2); } /// /// 处理结构化组合交易 /// private void ProcessStructureTrades(TradeRiskResultRecord[] items) { var firstItem = items[0]; InnerClient client = null; client = _helper.GetClient(firstItem.Trade.ClientId); double margin = 0d, updownLimit = 0; //远期:光子买的腿,初始预付金为期初权利金*2,持仓预付金计算公式与香草一致 if (firstItem.Trade.TradeNumber.Contains("FWD")) { foreach (var item in items) { if (_isInitialMargin) { if (item.Trade.BuySell == "买入") { updownLimit = 0; margin = item.ValueResult.Pv * 2; } else { margin = -GetUpDownEffectValue(item.ValueResult, out updownLimit); } } else { margin = item.ValueResult.Pv + GetUpDownEffectValue(item.ValueResult, out updownLimit); if (client != null && client.ClientId == item.Trade.ClientId) { margin = GetRealMargin(margin, item.Trade.BuySell, (MarginOptionEnum)client.MarginOptionType); } else { margin = GetRealMargin(margin, item.Trade.BuySell, item.Trade.ClientId, out client); } } var tradeSpan = _helper.CreateTradeSpan(item.Trade).SetAllSpvAndWorst(margin); tradeSpan.Comment = GetComment(item.ValueResult, updownLimit); _tradeSpans.Add(tradeSpan); } return; } //价差 if (firstItem.Trade.TradeNumber.Contains("SPD")) { //行权价 K1=4000,K2=4500,Notional=10: //单向追保: //1.交易员买入,预付金5000 //2.交易员卖出,预付金0 //双向追保: //1.交易员买入,预付金5000 //2.交易员卖出,预付金 - 5000 //对手方单向追保: //1.交易员买入,预付金0 //2.交易员卖出,预付金 - 5000 //双向追保 交易员买入 买入 + 卖出 0 // 卖出 买入 0 卖出 - var sumBuy = items.Sum(n => n.Trade.BuySell == "买入" ? (n.Trade.TradePrice ?? 0) : 0); var sumSell = items.Sum(n => n.Trade.BuySell == "买入" ? 0 : (n.Trade.TradePrice ?? 0)); //行权价之差的绝对值,因为取得时总和的绝对值所以在任何方向取负值都没问题 var strikeDiff = Math.Abs(items.Sum(n => (n.Trade.BuySell == "买入" ? -1 : 1) * (n.Trade.Strike ?? 0) * n.Trade.TradeAmount)); //交易员买入价差 if (sumBuy > sumSell) { if ((MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.对手方单向追保) { margin = 0; } else { margin = strikeDiff; } //最后一笔交易员买入 var lastItem = items.LastOrDefault(n => n.Trade.BuySell == "买入"); var spans = items.Select(n => { var tradeSpan = _helper.CreateTradeSpan(n.Trade); if (n == lastItem) { tradeSpan.SetAllSpvAndWorst(margin); tradeSpan.Comment = "客户卖出价差LAST"; } else { tradeSpan.Comment = "客户卖出价差"; } return tradeSpan; }).ToArray(); _tradeSpans.AddRange(spans); } else { //最后一笔客户卖出腿/交易员买入 var lastItem = items.LastOrDefault(n => n.Trade.BuySell == "买入"); if ((MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.单向追保) { margin = 0; } else { margin = -strikeDiff; } var spans = items.Select(n => { var tradeSpan = _helper.CreateTradeSpan(n.Trade); if ((n == lastItem && (MarginOptionEnum)client.MarginOptionType != MarginOptionEnum.双向追保) || (n != lastItem && (MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.双向追保)) { tradeSpan.SetAllSpvAndWorst(margin); tradeSpan.Comment = "客户卖出价差LAST"; } else { tradeSpan.Comment = "客户卖出价差"; } return tradeSpan; }).ToArray(); _tradeSpans.AddRange(spans); } } else { foreach (var item in items) { ProcessSingleTrade(item); } } } /// /// 获取涨跌停造成期权价值变化 /// private double GetUpDownEffectValue(TradeValueResult ValueResult, out double updownLimit) { if (_mpProvider == null) { _mpProvider = new MarginParamProvider(_req.UserInfo, _req.settleDate); } if (!_mpProvider.TryGetUpdownLimit(ValueResult.UnderlyingCode, out updownLimit, out _)) { return 0; } var spotPrice = ValueResult.SpotPrice ?? 0; var spotPriceLimit = spotPrice * updownLimit; return Math.Abs(ValueResult.Delta * spotPriceLimit) + Math.Abs(ValueResult.Gamma * spotPriceLimit * spotPriceLimit) / 2; } /// /// 根据买卖方向和客户追保方向获取预付金实际取值(只用于持仓预付金) /// private double GetRealMargin(double margin, string buysell, int clientId, out InnerClient client) { client = _helper.GetClient(clientId); if (client != null) { return GetRealMargin(margin, buysell, (MarginOptionEnum)client.MarginOptionType); } return margin; } /// /// 根据买卖方向和客户追保方向获取预付金实际取值(只用于持仓预付金) /// private static double GetRealMargin(double margin, string buysell, MarginOptionEnum marginOptionType) { if (marginOptionType == MarginOptionEnum.单向追保) { return buysell == "卖出" ? 0 : Math.Max(margin, 0); } if (marginOptionType == MarginOptionEnum.对手方单向追保) { return buysell == "卖出" ? Math.Min(margin, 0) : 0; } return margin; } /// /// 获取交易预付金备注 /// private static string GetComment(TradeValueResult ValueResult, double updownLimit) { return $"Delta:{ValueResult.Delta},closePrice:{ValueResult.SpotPrice},Gamma:{ValueResult.Gamma},updownLimit:{updownLimit:0.00%}"; } } } }