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.BLL; using YLErp.DBModels; using YLErp.Modules.TradeModule.KnockOutModule.Dto; using YLErp.QdpModule; namespace YLErp.Modules.TradeModule.KnockOutModule { /// /// 障碍期权敲出服务 /// public class BarrierOptionTradeKnockOutService : ITradeKnockOutService { public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate, ITradeExtendDataProvider _tradeExtendDataProvider) { GetKnockOutPayoffResult result = new GetKnockOutPayoffResult { IsKnockOut = false }; var barrierOption = _tradeExtendDataProvider.GetTrade_Barrier_Option(td.id); if (barrierOption == null) { return new GetKnockOutPayoffResult { IsKnockOut = false }; } td.trade_barrier_option = barrierOption; return GetKnockOutPayoff(td, underlyingPrice, _valueDate); } public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate) { GetKnockOutPayoffResult result = new GetKnockOutPayoffResult { IsKnockOut = false }; var barrierOption = td.trade_barrier_option; if (barrierOption == null) { return result; } //连续每天观察 离散根据观察日判断 如果非观察日 不检测敲入敲出 if ("离散".Equals(barrierOption.Discrete)) { var observationDates = QdpHelper.GetObservationDatesFromString(barrierOption.ObservationDates); //每日观察或者当前结算日是观察日的时候,才检查是否会敲入敲出 if (observationDates != null && observationDates.Length > 0 && !observationDates.Contains(_valueDate)) { return result; } } var BarrierPrice = td.IsMoneynessOptionData ? barrierOption.BarrierPrice * td.SpotPrice : barrierOption.BarrierPrice; var UpperBarrierPrice = td.IsMoneynessOptionData ? barrierOption.UpperBarrierPrice * td.SpotPrice : barrierOption.UpperBarrierPrice; switch (barrierOption.BarrierType) { case "上升敲出": if (underlyingPrice >= BarrierPrice) { result.IsKnockOut = true; result.Payoff = CalcBarrierOptionTradeKnockOutPayoff(td, barrierOption, underlyingPrice, _valueDate); } break; case "下降敲出": if (underlyingPrice <= BarrierPrice) { result.IsKnockOut = true; result.Payoff = CalcBarrierOptionTradeKnockOutPayoff(td, barrierOption, underlyingPrice, _valueDate); } break; case "双障碍敲出": if (underlyingPrice >= UpperBarrierPrice || underlyingPrice <= BarrierPrice) { result.IsKnockOut = true; var upDown = underlyingPrice >= UpperBarrierPrice ? true : false; result.Payoff = CalcBarrierOptionTradeKnockOutPayoff(td, barrierOption, underlyingPrice, _valueDate, upDown); } break; } return result; } /// /// 计算具体收益 /// /// /// /// /// 双障碍敲出 才有用 /// private double CalcBarrierOptionTradeKnockOutPayoff(trade td, trade_barrier_option barrierOption, double underlyingPrice,DateTime _valueDate, bool upDown = false) { var spotPrice = td.SpotPrice ?? 0; double rebate, rebateRate; //计算补偿金额 if (upDown) { if (td.IsUsePremiumRate == true) { rebateRate = barrierOption.RebateHighRate ?? 0; rebate = rebateRate * spotPrice; } else { rebate = barrierOption.RebateHigh ?? 0; rebateRate = spotPrice > 0 ? rebate / spotPrice : 0; } } else { if (td.IsUsePremiumRate == true) { rebateRate = barrierOption.RebateRate ?? 0; rebate = rebateRate * spotPrice; } else { rebate = barrierOption.Rebate ?? 0; //补偿金额 rebateRate = spotPrice > 0 ? rebate / spotPrice : 0; } } if (barrierOption.RebateAnnualizedAtKO) //补偿按敲出日年化 { var rebateDayCountImpl = string.IsNullOrWhiteSpace(barrierOption.RebateDayCount) ? new Act365() : barrierOption.RebateDayCount.ToDayCountImpl(); var fraction = rebateDayCountImpl.CalcDayCountFraction(new Date(td.StartDate.Value), new Date(_valueDate)); rebate *= fraction; rebate += Math.Abs((td.TradeSinglePrice - td.TradeSinglePrice * fraction) ?? 0); } var payoff = td.Notional * rebate + ((td.Notional / td.OriginalNotional * td.OriginalPrincipalSum) ?? 0); // 补偿金额 * 持仓份额 + 保底收益总额*尺长比例 //交易员视角 if (valuedateBLL.SystemDate.UnwindAmountAngle == 1) { payoff = payoff * (td.BuySell == "卖出" ? -1 : 1); } else { payoff = payoff * EodOperationBase.GetSign(td.BuySell); } return payoff; } } }