using Qdp.Foundation.Implementations; using Qdp.Pricing.Base.Implementations; using Qdp.Pricing.Base.Utilities; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using YLErp.Abstract; using YLErp.BLL.Eod; using YLErp.DBModels; using YLErp.Modules.TradeModule.KnockOutModule.Dto; using YLErp.QdpModule; namespace YLErp.Modules.TradeModule.KnockOutModule { /// /// 美式二元期权敲出服务 /// public class AmericanBinaryOptionTradeKnockOutService : ITradeKnockOutService { public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate, ITradeExtendDataProvider _tradeExtendDataProvider) { var binaryOption = _tradeExtendDataProvider.GetTrade_Binary_Option(td.id); if (binaryOption == null) { return new GetKnockOutPayoffResult { IsKnockOut = false }; } td.trade_binary_option = binaryOption; return GetKnockOutPayoff(td, underlyingPrice, _valueDate); } /// /// 获取敲出赔付 /// /// /// /// /// /// public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate) { var binaryOption = td.trade_binary_option; GetKnockOutPayoffResult result = new GetKnockOutPayoffResult { IsKnockOut = false }; if (binaryOption == null) { return result; } if (binaryOption.IsDiscreteMonitored) { var observationDates = QdpHelper.GetObservationDatesFromString(binaryOption.ObservationDates); if (observationDates != null && observationDates.Length > 0 && !observationDates.Contains(_valueDate)) { return result; //非观察日 不做敲出计算 } } var strike = td.IsMoneynessOptionData ? td.Strike * td.SpotPrice : td.Strike; var UpperBarrier = new Lazy(() => td.IsMoneynessOptionData ? binaryOption.UpperBarrier * td.SpotPrice : binaryOption.UpperBarrier); switch (binaryOption.PayoffType) { case "UpOneTouch": if (underlyingPrice >= strike) { //触碰,买方获得盈利,交易结束 result.IsKnockOut = true; result.Payoff = CalcAmericanBinaryOptionTradeKnockOutPayoff(td, binaryOption, useHighAmount: false, _valueDate); } else if (td.ExerciseDate <= _valueDate) { result.IsKnockOut = true; result.Payoff = 0; } break; case "DownOneTouch": if (underlyingPrice <= strike) { //触碰,买方获得盈利,交易结束 result.IsKnockOut = true; result.Payoff = CalcAmericanBinaryOptionTradeKnockOutPayoff(td, binaryOption, useHighAmount: false, _valueDate); } else if (td.ExerciseDate <= _valueDate) { result.IsKnockOut = true; result.Payoff = 0; } break; case "UpNoTouch": if (underlyingPrice >= strike) { //触碰,买方无盈利,交易结束 result.IsKnockOut = true; result.Payoff = 0; } break; case "DownNoTouch": if (underlyingPrice <= strike) { //触碰,买方无盈利,交易结束 result.IsKnockOut = true; result.Payoff = 0; } break; case "DoubleOneTouch": if (underlyingPrice >= UpperBarrier.Value || underlyingPrice <= strike) { var breachHighBarrier = underlyingPrice >= UpperBarrier.Value; result.IsKnockOut = true; result.Payoff = CalcAmericanBinaryOptionTradeKnockOutPayoff(td, binaryOption, useHighAmount: breachHighBarrier, _valueDate); } else if (td.ExerciseDate <= _valueDate) { result.IsKnockOut = true; result.Payoff = 0; } break; case "DoubleNoTouch": if (underlyingPrice >= UpperBarrier.Value || underlyingPrice <= strike) { //触碰上限或下限,买方无盈利,交易结束 result.IsKnockOut = true; result.Payoff = 0; } break; } return result; } /// /// 计算美式二元敲出 收益 /// /// /// /// /// private double CalcAmericanBinaryOptionTradeKnockOutPayoff(trade td, trade_binary_option binaryOption, bool useHighAmount,DateTime _valueDate) { var result = (td.Notional / td.OriginalNotional * (td.OriginalPrincipalSum ?? 0)) ?? 0; double refund; if (td.IsUsePremiumRate == true) { var rate = useHighAmount ? binaryOption.CashOrNothingAmountHighRate : binaryOption.CashOrNothingAmountRate; refund = Math.Abs((rate ?? 0) * (td.SpotPrice ?? 0) * td.Notional); } else { var amount = useHighAmount ? binaryOption.CashOrNothingAmountHigh : binaryOption.CashOrNothingAmount; refund = Math.Abs((amount ?? 0) * td.Notional); } if (binaryOption.RebateAnnualizedAtKO) { var rebateDayCountImpl = string.IsNullOrWhiteSpace(binaryOption.RebateDayCount) ? new Act365() : binaryOption.RebateDayCount.ToDayCountImpl(); var fraction = rebateDayCountImpl.CalcDayCountFraction(new Date(td.StartDate.Value), new Date(_valueDate)); refund *= fraction; refund += Math.Abs((td.TradePrice - td.TradePrice * fraction) ?? 0); } return (result + refund) * EodOperationBase.GetSign(td.BuySell); } } }