using CsvHelper; using Qdp.Foundation.Implementations; using Qdp.Pricing.Library.Options.Products.Autocall.Snowball; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using YLErp.Abstract; using YLErp.BLL; using YLErp.DBModels; using YLErp.DBModels.Helpers; using YLErp.Modules.CalculationModule; using YLErp.Modules.TradeModule.ExoticOptionModule; using YLErp.Modules.TradeModule.KnockOutModule.Dto; namespace YLErp.Modules.TradeModule.KnockOutModule { /// /// 雪球期权敲出计算服务 /// public class SnowBallTradeKnockOutService : ITradeKnockOutService { public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate, ITradeExtendDataProvider _tradeExtendDataProvider) { var snowBallOption = _tradeExtendDataProvider.GetTrade_Snowball_Option(td.id); if (snowBallOption == null) { return new GetKnockOutPayoffResult { IsKnockOut = false }; } td.trade_snowball = snowBallOption; return GetKnockOutPayoff(td, underlyingPrice, _valueDate); } public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate) { GetKnockOutPayoffResult result = new GetKnockOutPayoffResult { IsKnockOut = false }; var snowBallOption = td.trade_snowball; if (snowBallOption == null) { return result; } if (snowBallOption.PrepaymentUsed) { var specialSnowBallResult = new SpecialSnowballObservationHelper(td, snowBallOption).GetObservationResultForTraderSide(_valueDate, underlyingPrice, td.Notional); if (specialSnowBallResult != null && specialSnowBallResult.ResultType == SnowballObservationResultType.KoPayoff) { result.IsKnockOut = true; result.Payoff = specialSnowBallResult.PaymentAmount; } return result; } var request = new OptionTradeParamRequest(valuedateBLL.SysRiskFreeRate()) { ParamOverride = p => p.notional = td.Notional }; var optionTrade = QdpTradeBuilder.GetSnowballOptionTrade(td, snowBallOption, request); var snowball = (SimpleSnowball)optionTrade.Instrument; var isCall = ConsGlobal.CallPut.IsCall(td.CallPut); if (snowball.KOObsDates.Select(x => x.DateTime).Contains(_valueDate)) { (var koSettleDate, var koBarrier) = GetSnowBallKoSettleInfo(_valueDate, td, snowBallOption, snowball); // 发生敲出事件(看涨 - 向上敲出支付票息,看跌 - 向下敲出支付票息) if (isCall ? underlyingPrice >= koBarrier : underlyingPrice <= koBarrier) { result.IsKnockOut = true; if (snowball.UseOptionPayoffAtKO) { double paymentAmount = 0; var koOptionCashflows = snowball.GetKOPayoff(new Date(_valueDate), underlyingPrice); paymentAmount = TradeHelper.GetAmountByPaymentAmount(koOptionCashflows[0].PaymentAmount, td.PrincipalSum(), td.BuySell); result.Payoff = paymentAmount; } else { var CouponPayment = snowball.CouponPayment(_valueDate, includeStartDate: snowBallOption.CouponIncludeStartDate == true && snowBallOption.CouponDayCount != "Monthly"); var couponPayment = TradeHelper.GetAmountByPaymentAmount(CouponPayment, td.PrincipalSum(), td.BuySell); if (snowBallOption.AnnualizedPremiumRate.HasValue && snowBallOption.AnnualizedPremiumRate != 0) { var tradePrice = (td.StockEqvNotional * td.ParticipationRate * snowBallOption.AnnualizedPremiumRate * snowball.CouponDayCount.CalcDayCountFraction(snowball.StartDate, new Date(_valueDate))) ?? 0; if (tradePrice != 0) { couponPayment += (td.BuySell == "买入" ? -1 : 1) * tradePrice; } } result.Payoff = couponPayment; } } } return result; } //获取雪球期权敲出时要准备的信息 public (DateTime koSettleDate, double koBarrier) GetSnowBallKoSettleInfo(DateTime valueDate, OtcTradeBase otcTrade, trade_snowball tradeSnowball, SimpleSnowball snowball) { double koBarrier; var koSettleDate = valueDate; var datesStr = tradeSnowball.KOObservationSettleDates; var KOObsSettleDates = string.IsNullOrWhiteSpace(datesStr) ? null : datesStr.Split(new char[] { ',', ';', ',', ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => DateTime.Parse(x)).ToArray(); if (snowball.CustomizedKOBarriers != null && snowball.CustomizedKOBarriers.Length > 0) { var index = snowball.KOObsDates.Select(x => x.DateTime).ToList().IndexOf(valueDate); koBarrier = snowball.CustomizedKOBarriers[index]; if (KOObsSettleDates != null && KOObsSettleDates.Length > index) { koSettleDate = KOObsSettleDates[index]; } } else { koBarrier = tradeSnowball.KOBarrier; if (KOObsSettleDates != null && KOObsSettleDates.Any()) { koSettleDate = KOObsSettleDates[0]; } } if (tradeSnowball.KORebateType == RebateTypeEnum.AtEnd) { koSettleDate = otcTrade.ExerciseDate.Value; } else if (koSettleDate < valueDate) { koSettleDate = valueDate; } if (otcTrade.IsMoneynessOptionData) { koBarrier *= otcTrade.SpotPrice ?? 1.0; } return (koSettleDate, koBarrier); } } }