using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos; using Qdp.Pricing.Base.Implementations; using Qdp.Pricing.Library.Common.Interfaces; using Qdp.Pricing.Library.Options.Products.Asian; using Qdp.Pricing.Library.Options.Products.Barrier; using Qdp.Pricing.Library.Options.Products.Binary; using YLErp.Commons; using YLErp.DBModels.Helpers; using YLErp.Modules; using YLErp.Modules.CalculationModule; using YLErp.Modules.TradeModule.ExoticOptionModule; namespace YLErp.BLL.EodSettlement { /// /// 结算通用类 /// public class SettlementCalcCommons { /// /// 计算行权收益 /// public static void SetPossibleExec(trade_cash tc, trade trade, double price, bool isRefreshFinalPrice = false , DateTime? finalPriceSettleDate = null, double? strike = null) { string fixings = null; tradeBLL.SetFieldsByTradeType(trade); //var isBinaryOption = trade.TradeType == "二元期权"; var isAsianOption = trade.TradeType == "亚式期权"; if (isAsianOption && trade.trade_asian_option == null) { throw new ServiceException("缺少亚式期权交易信息"); } //亚式期权浮动行权价有行权价传入的情况处理 if (isAsianOption) { var startDate = trade.trade_asian_option.AveragingPeriodStartDate ?? trade.TradeDate.Value; var settleDate = finalPriceSettleDate ?? valuedateBLL.ValueDate; //亚式浮动行权价并且行权价有输入值的情况下 if (strike.HasValue && trade.trade_asian_option.StrikeType == "Floating") { //均价起算日大于结算日的情况下取计值日 if (startDate > settleDate) { startDate = settleDate; } fixings = $"{startDate:yyyy-MM-dd},{strike}"; } else { //均价起算日大于结算日的情况下取不到fixing则直接赋值 if (startDate > settleDate) { fixings = $"{settleDate:yyyy-MM-dd},{price}"; } else { fixings = AsianOptionFixingService.GetFixingString(settleDate, trade); if (string.IsNullOrEmpty(fixings)) { //取不到fixing则直接赋值 fixings = $"{settleDate:yyyy-MM-dd},{price}"; } } } } if (trade.TradeType == "Risky期权") { var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); if (underlying == null) { throw new Exception($"找不到标的资产{trade.UnderlyingCode}的信息"); } var QdpTrades = GetToQdpOptionRisk(trade, underlying, finalPriceSettleDate, fixings); tc.IsPossibleExec = true; tc.UnwindPrice = tc.UnwindPrice ?? 0; foreach (var item in QdpTrades) { if (item != null && item.Instrument != null && item.Instrument is IOption optitem) { Cashflow[] cashFlows; cashFlows = optitem.GetPayoff(new double[] { price }); if (!(cashFlows != null && (cashFlows[0].PaymentAmount == 0 || double.IsNaN(cashFlows[0].PaymentAmount)))) { //cashFlows[0].PaymentAmount包含了买卖方向的处理了 tc.UnwindPrice += cashFlows[0].PaymentAmount / trade.Notional; tc.Amount += OtcFormatHelper.FormatValue(cashFlows[0].PaymentAmount, 2); tc.InitialAmount += OtcFormatHelper.FormatValue(cashFlows[0].PaymentAmount, 2); } } } //risky保底是一个总的值 var amount = TradeHelper.GetAmountByPaymentAmount(0, trade.PrincipalSum(), trade.BuySell); tc.Amount += OtcFormatHelper.FormatValue(amount, 2); tc.InitialAmount += OtcFormatHelper.FormatValue(amount, 2); } else if (trade.TradeType == "雪球期权" && trade.trade_snowball.PrepaymentUsed) { var obResult = new SpecialSnowballObservationHelper(trade, trade.trade_snowball) .GetObservationResultForTraderSide(finalPriceSettleDate ?? valuedateBLL.ValueDate, price, trade.Notional); var amount = TradeHelper.GetAmountByPaymentAmount(obResult.PaymentAmount, trade.PrincipalSum(), trade.BuySell); tc.IsPossibleExec = true; tc.UnwindPrice = obResult.PaymentAmount / trade.Notional; tc.Amount = OtcFormatHelper.FormatValue(amount, 2); tc.InitialAmount = OtcFormatHelper.FormatValue(amount, 2); } else { var QdpTrade = TradeCalcHelper.GetQdpTrade(trade, finalPriceSettleDate, fixings); if (QdpTrade != null && QdpTrade.Instrument != null && QdpTrade.Instrument is IOption opt) { if (isAsianOption) { var asianOpt = opt as AsianOption; tc.StrikeType = trade.trade_asian_option.StrikeType; if (trade.trade_asian_option.StrikeType == "Floating") { tc.Strike = asianOpt.ActualStrike; } else { tc.FinalPrice = asianOpt.FinalPrice(); //isRefreshFinalPrice为false代表非默认标的价格,则根据行权页面的标的价格计算行权收益 if (isRefreshFinalPrice) { //分段式亚式期权,行权时的默认标的价格需要通过QDP计算得出,而不是标的现价 //再根据该价格算出行权收益 price = asianOpt.FinalPrice(); if (finalPriceSettleDate != null) { price = asianOpt.FinalPrice(finalPriceSettleDate); } price = Convert.ToDouble(price.OtcFormatUmPrice()); } } } Cashflow[] cashFlows; if (QdpTrade.Instrument is BinaryOption) { var option = QdpTrade.Instrument as BinaryOption; var valueDate = finalPriceSettleDate ?? valuedateBLL.ValueDate; cashFlows = option.GetPayoff(new double[] { price }, valueDate); } else if (QdpTrade.Instrument is BarrierOption) { var option = QdpTrade.Instrument as BarrierOption; var valueDate = finalPriceSettleDate ?? valuedateBLL.ValueDate; cashFlows = option.GetPayoff(new double[] { price }, valueDate); } else { cashFlows = opt.GetPayoff(new double[] { price }); } if (cashFlows != null && (cashFlows[0].PaymentAmount == 0 || double.IsNaN(cashFlows[0].PaymentAmount))) { var amount = TradeHelper.GetAmountByPaymentAmount(0, trade.PrincipalSum(), trade.BuySell); tc.IsPossibleExec = true; tc.UnwindPrice = 0; tc.Amount = OtcFormatHelper.FormatValue(amount, 2); tc.InitialAmount = OtcFormatHelper.FormatValue(amount, 2); } else { //cashFlows[0].PaymentAmount包含了买卖方向的处理了 var paymentAmount = trade.TradeType == "累计期权" ? cashFlows[0].PaymentAmount * trade.Notional / (trade.CountRatio ?? 1) : cashFlows[0].PaymentAmount; var amount = TradeHelper.GetAmountByPaymentAmount(paymentAmount, trade.PrincipalSum(), trade.BuySell); tc.IsPossibleExec = true; tc.UnwindPrice = paymentAmount / trade.Notional; tc.Amount = OtcFormatHelper.FormatValue(amount, 2); tc.InitialAmount = OtcFormatHelper.FormatValue(amount, 2); } } } } public static List GetToQdpOptionRisk(trade trade, underlying_manager underlying, DateTime? finalPriceSettleDate, string fixings) { var tradeclone = trade.Clone(); tradeclone.TradeAmount = tradeclone.TradeAmount = TradeCalcHelper.GetTradeAmountV(trade, trade.TradeAmount, 1); tradeclone.Notional = tradeclone.Notional = TradeCalcHelper.GetTradeAmountV(trade, trade.Notional, underlying.CountRatio); var options = new List(); var td1 = tradeclone.Clone(); td1.Strike = trade.trade_risky_option.Strike1; td1.ParticipationRate = trade.trade_risky_option.ParticipationRate1; td1.TradeAmount = TradeCalcHelper.GetTradeAmount(td1, td1.TradeAmount, 1); td1.Notional = TradeCalcHelper.GetTradeAmount(td1, td1.Notional, underlying.CountRatio); td1.OptionType = "看跌"; td1.BuySell = trade.BuySell == "买入" ? "卖出" : "买入"; var option1 = TradeCalcHelper.GetQdpTrade(td1, finalPriceSettleDate, fixings); if (option1 != null) { options.Add(option1); } var td2 = tradeclone.Clone(); td2.Strike = trade.trade_risky_option.Strike2; td2.ParticipationRate = trade.trade_risky_option.ParticipationRate2; td2.TradeAmount = TradeCalcHelper.GetTradeAmount(td2, td2.TradeAmount, 1); td2.Notional = TradeCalcHelper.GetTradeAmount(td2, td2.Notional, underlying.CountRatio); var option2 = TradeCalcHelper.GetQdpTrade(td2, finalPriceSettleDate, fixings); if (option2 != null) { options.Add(option2); } var td3 = tradeclone.Clone(); td3.Strike = trade.trade_risky_option.Strike3; //decimal 为了解决精度问题: 0.2-0.3=0.0999999999 var participationRate3 = (decimal)trade.trade_risky_option.ParticipationRate2 - (decimal)trade.trade_risky_option.ParticipationRate3; td3.ParticipationRate = (double?)Math.Abs(participationRate3); td3.TradeAmount = TradeCalcHelper.GetTradeAmount(td3, td3.TradeAmount, 1); td3.Notional = TradeCalcHelper.GetTradeAmount(td3, td3.Notional, underlying.CountRatio); if (participationRate3 < 0) { td3.BuySell = trade.BuySell == "买入" ? "卖出" : "买入"; } var option3 = TradeCalcHelper.GetQdpTrade(td3, finalPriceSettleDate, fixings); if (option3 != null) { options.Add(option3); } return options; } /// /// 获取根据当前价格行权的行权价 /// public static double GetOTCTradeExerciseProfit(trade trade, double price) { //实值pv计算 var ActualPv = 0.0; tradeBLL.SetFieldsByTradeType(trade); var QdpTrade = TradeCalcHelper.GetQdpTrade(trade); if (QdpTrade != null && QdpTrade.Instrument != null) { var opt = QdpTrade.Instrument as IOption; if (opt != null) { try { var cashFlows = opt.GetPayoff(new double[] { price }); if (cashFlows != null && cashFlows[0].PaymentAmount == 0) { return ActualPv; } else { ActualPv = OtcFormatHelper.FormatValue(cashFlows[0].PaymentAmount, 2); } } catch (Exception) { } } } return ActualPv; } } }