using YLErp.BLL.Calculation; using YLErp.Enums; using YLErp.Modules.MarginModule; using YLErp.Modules.VolatilityModule; using YLErp.QdpModule; namespace YLErp.BLL.MarginCalculation { public class MaoChuanMarginCalculation : MarginCalculationBase { // 定义一个静态变量来保存类的实例(单例模式) public static readonly MaoChuanMarginCalculation Instance; static MaoChuanMarginCalculation() { Instance = new MaoChuanMarginCalculation(); } // 定义私有构造函数,使外界不能创建该类实例 private MaoChuanMarginCalculation() { } /// /// 计算香草期权和亚式期权预付金 /// private List CalculationNormalOptionMargin(RunMarginCalculationReq req) { var resultMap = new Dictionary(); var codes = req.tradeList.Select(O => O.UnderlyingCode).ToHashSet(); var mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate) .Initialize(codes, MarginParamTypeEnum.MarginRate); //客户要求用AskVol计算预付金,所以先把所有交易方向改为卖出并把VolType赋值为 BidAskVol; //Dictionary buySellDict = tradeList.ToDictionary(K => K.id, V => V.BuySell); //tradeList.ForEach(t => t.BuySell = "卖出"); var vols = new Dictionary(); foreach (var t in req.tradeList) { var vType = t.VolType; t.VolType = "报价Ask"; var um = _underlyingDataProvider.GetUnderlying(t.UnderlyingCode); if (um == null) { throw new MarginCalcException($"[预付金计算]找不到标的数据(交易编号:{t.TradeNumber},标的代码:{t.UnderlyingCode})"); } var vol = SingleVolService.GetSingleVol(new SingleVolReq(t, um), req.userId, isEodCalc: req.CalcMarginType == CalcMarginTypeEnum.EodMargin); vols[t.id] = vol; t.VolType = vType; } var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( valueDate: req.settleDate, tradeList: req.tradeList, calcScenario: CalcScenarioEnum.EodSettlement, priceProvider: req.PriceProvider, pricingRequest: QdpPricingRequest.BASIC_PRICING, addVolRateDic: null, volType: null, overrideVolsForTrade: vols, isUseTradeVol: PS.Config.IsTradeVol, preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); //tradeList.ForEach(t => t.BuySell = buySellDict[t.id]); foreach (var r in tradeRiskResult.Results) { if (!mpProvider.TryGetMarginRate(r.Trade.UnderlyingCode, out var marginRate)) { throw new MarginCalcException($"{r.Trade.UnderlyingCode} 预付金比率不存在"); } var trade = req.tradeList.FirstOrDefault(t => t.id == r.Trade.id); if (!req.PriceProvider.TryGetPrice(r.Trade.UnderlyingCode, out var price)) { price = r.Trade.SpotPrice ?? 0; } logger.Info($"茂川标准预付金计算:[{r.Trade.TradeType}_{r.Trade.BuySell}_{r.Trade.OptionType}_{r.Trade.Strike}] => Vol:{r.ValueResult.Vol};Delta:{r.ValueResult.Delta}"); //预付金= Delta*标的期货预付金比率*标的期货价格*持仓规模 (qdp计算出的Delta已经乘过数量了,所以这里不用再乘了); var value = Math.Abs(r.ValueResult.Delta) * marginRate * price;// * r.Trade.Notional; if (r.Trade.BuySell == "买入") { value = Math.Abs(value); } else { value = 0 - Math.Abs(value); } var tempTradeSpan = new trade_span { TradeId = r.Trade.id, ClientId = trade.ClientId, ValueDate = req.settleDate, UnderlyingId = trade.UnderlyingId, UnderlyingCode = trade.UnderlyingCode, OptId = req.userId, OptName = req.userName, OptDate = DateTime.Now, Spv1 = value, Spv2 = value, Spv3 = value, Spv4 = value, WorstCastClientPayable = value }; resultMap[r.Trade.id] = tempTradeSpan; } return resultMap.Values.ToList(); } /// /// 计算其他期权预付金 /// private List CalculationOtherOptionMargin(RunMarginCalculationReq req) { var resultMap = new Dictionary(); var tempTradeList = new List(); var vols = new Dictionary(); foreach (var t in req.tradeList) { var vType = t.VolType; t.VolType = "报价Ask"; var um = _underlyingDataProvider.GetUnderlying(t.UnderlyingCode); var vol = SingleVolService.GetSingleVol(new SingleVolReq(t, um), req.userId, req.CalcMarginType == CalcMarginTypeEnum.EodMargin); vols[t.id] = vol; t.VolType = vType; tempTradeList.Add(t.Clone()); } var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( valueDate: req.settleDate, tradeList: tempTradeList, calcScenario: CalcScenarioEnum.EodSettlement, priceProvider: req.PriceProvider, pricingRequest: QdpPricingRequest.BASIC_PRICING, addVolRateDic: null, volType: null, overrideVolsForTrade: vols, isUseTradeVol: PS.Config.IsTradeVol, preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); //if (priceDict == null) //{ // priceDict = new Dictionary(); // Dictionary rateDict = base.GetUpDownLimitRate(req.tradeList.Select(O => O.UnderlyingId).ToArray()); // tempTradeList.ForEach(t => // { // double[] arr = base.GetUpDownLimitPrice(rateDict[t.id], (t.SpotPrice ?? 0), double.Parse(rateDict[t.id][2])); // priceDict[t.UnderlyingId] = t.OptionType == "看涨" ? arr[1] : arr[0]; // }); //} //else //{ // Dictionary dict = base.GetUpDownLimitPrice(priceDict); // tempTradeList.ForEach(t => // priceDict[t.UnderlyingId] = t.OptionType == "看涨" ? dict[t.id][1] : dict[t.id][0]); //} var newTradeRiskResult = CalculatorHelper.CalculateRisksForTrades( valueDate: req.settleDate, tradeList: tempTradeList, calcScenario: CalcScenarioEnum.EodSettlement, priceProvider: req.PriceProvider, pricingRequest: QdpPricingRequest.BASIC_PRICING, addVolRateDic: null, volType: null, overrideVolsForTrade: vols, isUseTradeVol: PS.Config.IsTradeVol, preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); foreach (var t in tempTradeList) { var cPv = tradeRiskResult.Results.FirstOrDefault(O => O.ValueResult.TradeId == t.id).ValueResult.Pv; var nPv = newTradeRiskResult.Results.FirstOrDefault(O => O.ValueResult.TradeId == t.id).ValueResult.Pv; //预付金= 次日最大亏损; var value = t.OptionType == "看涨" ? cPv - nPv : cPv + nPv; logger.Info($"茂川奇异预付金计算:[{t.TradeType}_{t.BuySell}_{t.OptionType}_{t.Strike}] => 当日Pv:{cPv};次日Pv:{nPv}"); var tempTradeSpan = new trade_span { TradeId = t.id, ClientId = t.ClientId, ValueDate = req.settleDate, UnderlyingId = t.UnderlyingId, UnderlyingCode = t.UnderlyingCode, OptId = req.userId, OptName = req.userName, OptDate = DateTime.Now, Spv1 = value, Spv2 = value, Spv3 = value, Spv4 = value, WorstCastClientPayable = value }; resultMap[t.id] = tempTradeSpan; } return resultMap.Values.ToList(); } private List CalculationStructureOptionMargin(RunMarginCalculationReq req) { var resultMap = new List(); foreach (var td in req.tradeList) { var tempId = int.MaxValue; td.SubTrades.ToList().ForEach(t => t.id = tempId--); var childrenSpans = RunMarginCalculation(req.Clone(td.SubTrades.ToList())); double margin = 0; switch (td.StructureType) { case "牛市价差": case "熊市价差": case "亚式熊市价差": case "三领口组合": for (var j = 0; j < childrenSpans.Count; j++) { margin += childrenSpans[j].WorstCastClientPayable ?? 0; } break; case "跨式组合": case "宽跨式组合": for (var j = 0; j < childrenSpans.Count; j++) { var absMargin = Math.Abs(childrenSpans[j].WorstCastClientPayable ?? 0); if (margin < absMargin) { margin = absMargin; } } break; case "复制标的资产": case "蝶式组合": case "飞鹰式组合": case "比例价差": case "日历价差": case "箱式价差": case "风险逆转": default: break; } var tempTradeSpan = new trade_span { TradeId = td.id, ClientId = td.ClientId, ValueDate = req.settleDate, UnderlyingId = td.UnderlyingId, UnderlyingCode = td.UnderlyingCode, OptId = req.userId, OptName = req.userName, OptDate = DateTime.Now, Spv1 = margin, Spv2 = margin, Spv3 = margin, Spv4 = margin, WorstCastClientPayable = margin }; resultMap.Add(tempTradeSpan); } return resultMap; } public override List RunMarginCalculation(RunMarginCalculationReq req) { var resultMap = new List(); if (req.tradeList == null || !req.tradeList.Any()) { return resultMap; } if (req.forOtherSide) { return RunMarginCalculationOtherSide(req); } var tList = req.tradeList.Where(O => O.TradeType == "结构化交易").ToList(); if (tList.Count > 0) { resultMap.AddRange(CalculationStructureOptionMargin(req.Clone(tList))); } tList = req.tradeList.Where(O => O.TradeType == "香草期权" || O.TradeType == "亚式期权").ToList(); if (tList.Count > 0) { resultMap.AddRange(CalculationNormalOptionMargin(req.Clone(tList))); } tList = req.tradeList.Where(O => O.TradeType != "结构化交易" && O.TradeType != "香草期权" && O.TradeType != "亚式期权").ToList(); if (tList.Count > 0) { resultMap.AddRange(CalculationOtherOptionMargin(req.Clone(tList))); } return resultMap; } public override double GetTradeMargin(GetTradeMarginReq req) { var trade = req.trade; if (trade.TradeType == "结构化交易" && (trade.SubTrades == null || trade.SubTrades.Count() == 0)) { using (var db = new YLContext()) { trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); } } var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); if (null != tradeMargin) { return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; } return 0.0; } } }