using BaseOUDAL; using Qdp.Foundation.Implementations; using Qdp.Pricing.Base.Implementations; using Qdp.Pricing.Base.Utilities; using System.Linq; using YLErp.Abstract.DataProviders; using YLErp.Configuration.Enums; using YLErp.CustomizedBizLogic; using YLErp.DBModels.Consts; using YLErp.Modules.DataProviderModule; using YLErp.Modules.DictionaryModule; using YLErp.Modules.SalesModule; using YLErp.Modules.TradeModule.DealModule; using YLErp.QdpModule; namespace YLErp.Modules.TradeModule.AccumulatorOptionModule { /// /// 累计期权 /// public class TradeAccumulatorService : ExoticOptionModule.TradeCashServiceEx { public TradeAccumulatorService(OptUserInfo userInfo) : base(userInfo) { } public TradeAccumulatorService(YLBaseService baseService) : base(baseService) { } /// /// 检查累计期权观察状态 /// 这个方法会还原累计换月数据 /// public void CheckAccumulatorKnockInStatus(OtcTradeBase trade, trade_accumulator_option tradeAcc, DateTime valueDate, double closePrice) { if (trade is null) { throw new ArgumentNullException(nameof(trade)); } if (tradeAcc is null) { throw new ArgumentNullException(nameof(tradeAcc)); } //todo:远期无效以后应把关联的源交易关联数据删除掉 var query = from m in DbContext.autocall_observation join t in DbContext.trade on m.ConvTradeNumber equals t.TradeNumber where m.TradeId == trade.id && m.EndDate == valueDate && (m.SettlementMode == "转远期" || m.SettlementMode == "转掉期" || m.SettlementMode == "现金当日&转远期") && t.ValidState != ConsGlobal.InValid select new { m.ConvTradeNumber }; var observation = query.FirstOrDefault(); if (observation != null) { throw new ServiceException($"操作失败,当前累计期权交易({trade.TradeNumber})在'{valueDate:yyyy-MM-dd}'已结算为远期交易({observation.ConvTradeNumber})"); } if (trade.UnWindDate > valueDate) { throw new ServiceException("部分平仓或到期的累计期权不支持历史观察处理"); } var tradeStatus = trade.TradeStatus; var tdForwardList = new List(); var changeData = GetChangeDataOfSepecialDay(trade.id, valueDate); CheckAccumulatorPayoff(trade, tradeAcc, valueDate, closePrice, tdForwardList, changeData); if (tradeStatus != trade.TradeStatus) { //删除E/Bod_Trade记录 RemoveEodTradeAndFutureInfo(false, trade.id, valueDate); var obs = DbContext.autocall_observation.Where(x => x.TradeId == trade.id && x.SettlementMode != "转远期" && x.SettlementMode != "转掉期" && x.EndDate > valueDate); DbContext.autocall_observation.RemoveRange(obs); } } /// /// 检查结算状态 /// public void CheckSettleStatus(DateTime valueDate, IEodPriceProviderV2 priceProvider, out List tdForwardList, DateTime? startDate = null, Action afterKnowInOut = null, IEnumerable clienIds = null) { tdForwardList = null; priceProvider ??= new EodPriceProvider(valueDate); EodReferencePriceProvider eodReferencePriceProvider = null; if (PS.Config.Is厦门象屿) { eodReferencePriceProvider = new EodReferencePriceProvider(valueDate); } if (startDate == null) { startDate = valueDate.AddYears(-5); } var query = from trade in DbContext.trade join acc in DbContext.trade_accumulator_option on trade.id equals acc.TradeId where trade.TradeDate > startDate.Value && trade.TradeDate <= valueDate && trade.ExerciseDate >= valueDate && trade.TradeType == "累计期权" && ConsTrade.确认成交 == trade.TradeStatus && trade.ValidState != ConsGlobal.InValid && trade.DividendDate < valueDate && !( from ob in DbContext.autocall_observation join tf in DbContext.trade on ob.ConvTradeNumber equals tf.TradeNumber where ob.TradeId == trade.id && ob.EndDate == valueDate && (ob.SettlementMode == "转远期" || ob.SettlementMode == "转掉期" || ob.SettlementMode == "现金当日&转远期") && tf.ValidState != ConsGlobal.InValid select ob ).Any() select new { trade, tradeAcc = acc }; #region 增加客户筛选 tw if (clienIds != null) { query = query.Where(l => clienIds.Contains(l.trade.ClientId)); } #endregion var trades = query.ToList(); if (trades == null || !trades.Any()) { return; } var tradeIds = trades.Select(x => x.trade.id).ToArray(); var manuallyTradeObservationPrices = DbContext.manually_trade_observation_price .Where(x => tradeIds.Contains(x.TradeId) && x.ValueDate == valueDate).ToDictionary(n => n.TradeId); var cashList = (from cash in DbContext.ClientCashInCashOut join update in DbContext.clientcashincashout_update on cash.id equals update.ClientcashincashoutId where tradeIds.Contains(cash.TradeId ?? 0) && cash.HappenDate == valueDate && cash.Action != ClientCashInCashOut.系统操作_期权费 && update.State == "已确认" select cash.TradeId).ToHashSet(); tdForwardList = new List(); foreach (var tr in trades) { if (cashList.Contains(tr.trade.id)) { continue;//已观察过且修改过资金的交易不再观察; } if (tr.trade.ExerciseDate < valueDate) { continue;//已到期交易不再观察; } //部分平仓或到期的累计期权历史收盘不需要再进行观察处理 if (!(tr.trade.UnWindDate > SystemValueDate)) { tr.trade.trade_accumulator_option = tr.tradeAcc; var tradeStatus = tr.trade.TradeStatus; var changeData = GetChangeDataOfSepecialDay(tr.trade.id, valueDate); var closePrice = double.NaN; if (manuallyTradeObservationPrices.TryGetValue(tr.trade.id, out var manuallyTradeObservationPrice)) { closePrice = manuallyTradeObservationPrice.Price ?? 0; } else { var UnderlyingCode = changeData?.UnderlyingCode ?? tr.trade.UnderlyingCode; if (PS.Config.Is厦门象屿) { if (tr.trade.SettlementType == SettlementTypeEnum.ReferencePrice) {//2022-05-17 象屿希望以参考价结算的交易,观察价格也优先使用参考价,不存在则使用收盘价; if (eodReferencePriceProvider.TryGetPrice(UnderlyingCode, out var price)) { closePrice = price; } else { throw new Exception($"[{tr.trade.TradeType}:{tr.trade.TradeNumber}]标的:{UnderlyingCode} 未找到参考价"); } } } if (double.IsNaN(closePrice)) { if (!priceProvider.TryGetEodPrice(UnderlyingCode, out var eodprice)) { throw new Exception($"[{tr.trade.TradeType}:{tr.trade.TradeNumber}]标的:{UnderlyingCode} 未找到结算价"); } else { closePrice = eodprice.ClosePrice; } } } CheckAccumulatorPayoff(tr.trade, tr.tradeAcc, valueDate, closePrice, tdForwardList, changeData); if (tradeStatus != tr.trade.TradeStatus) { //删除E/Bod_Trade记录 RemoveEodTradeAndFutureInfo(false, tr.trade.id, valueDate); } if (afterKnowInOut != null) { afterKnowInOut(tr.trade, tr.tradeAcc); } DbContext.SaveChanges(); } } } /// /// 检查累计期权payoff /// private void CheckAccumulatorPayoff(OtcTradeBase td, trade_accumulator_option tdAcc, DateTime valueDate, double closePrice , List tdForwardList, TradeAccumulatorChangeData changeData) { //验证上一个观察日是否已经观察过 var customObservDates = QdpHelper.ParseAutocallCustomizedInfo(tdAcc.KOObservationDates); var koObservationDates = customObservDates.Item1; koObservationDates ??= CalendarImpl.Get("chn").BizDaysBetweenDatesExcluStartDay(td.TradeDate.Value, td.ExerciseDate.Value).ToArray(); var valueDateIndex = Array.IndexOf(koObservationDates, new Date(valueDate)); if (valueDateIndex >= 1) { var lastValueDate = koObservationDates[valueDateIndex - 1]; if (!DbContext.autocall_observation.Any(x => x.TradeId == td.id && x.EndDate == lastValueDate.DateTime)) { throw new ServiceException($"{td.TradeNumber}累计期权需要按顺序观察,请先在{lastValueDate.DateTime.ToString("yyyy-MM-dd")}进行观察或收盘处理"); } } var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); var notional = tdAcc.AccumuTradeAmount * underlying.CountRatio; CheckResult result = null; if (changeData != null) { //关键点:还原换月设置到交易时不要更新当前传入的trade和tradeAcc,因为这两个数据涉及到数据库更新 var tdClone = new trade(); YLAutoMapper.Map(td, tdClone); var tdAccClone = tdAcc.Clone(); tdClone.trade_accumulator_option = tdAccClone; TradeAccumulatorHelper.RestoreAccumulatorChangeData(tdClone, tdAccClone, changeData); result = CheckAccumulatorPayoff(tdClone, tdAccClone, valueDate, closePrice, notional); } else { result = CheckAccumulatorPayoff(td, tdAcc, valueDate, closePrice, notional); } if (result != null) { using (var trans = DbContext.Database.BeginTransaction()) { trade_cash tc = null; var action = "部分行权"; var exerciseWay = string.Empty; if (valueDate.Date == td.ExerciseDate.Value.Date) { action = "到期行权"; exerciseWay = TradeCashExerciseWayEnum.到期行权; } if (result.SettlementMode == "敲出") { tdAcc.KnockOutDate = valueDate; if (tdAcc.EarlyTerminate) { var req = new OptionTradeKnockoutRequest { ValueDate = valueDate, IgnoreLaterCashRecords = false, PaymentAmount = 0, UnderlyingPrice = closePrice }; var exeResult = new OptionTradeKnockoutService(this).Execute(td, tdAcc, req, trans); tc = exeResult.TradeCash; td.SetFullClosedStatus(valueDate, ConsTrade.已平仓); //生成确认书 if (PS.Config.IsAutoGenerateContracts) { //修改销售提成的状态 new SalesCommissionDataService(this).SetCommissionVaild(td.id); new TradeContractGenerateService(this).GenerateContractsAsync(new List { td.id }); } } else { if (valueDate.Date != td.ExerciseDate.Value.Date || tdAcc.SettlementMode != "现金期末") { tc = InnerSaveCash(trade: td, valueDate: valueDate, happenDate: valueDate, cashAction: action, exerciseWay: exerciseWay, closePrice: closePrice, paymentAmount: 0, isKnockOut: true, isLastAction: valueDate.Date == td.ExerciseDate.Value.Date); } } } else { tdAcc.KnockOutDate = null; if (result.ForwardTrade != null) //转远期 { SaveForwardTrade(result.ForwardTrade); tdForwardList.Add(result.ForwardTrade); tc = InnerSaveCash(trade: td, valueDate: result.PaymentDate, happenDate: result.PaymentDate, cashAction: action, exerciseWay: exerciseWay, closePrice: closePrice, paymentAmount: result.SettlementMode == "现金当日&转远期" ? result.PaymentAmount : 0, isKnockOut: false, isLastAction: valueDate.Date == td.ExerciseDate.Value.Date); } else if (result.SettlementMode == "票息" || result.SettlementMode == "现金当日") { tc = InnerSaveCash(trade: td, valueDate: result.PaymentDate, happenDate: result.PaymentDate, cashAction: action, exerciseWay: exerciseWay, closePrice: closePrice, paymentAmount: result.PaymentAmount, isKnockOut: false, isLastAction: valueDate.Date == td.ExerciseDate.Value.Date); } else if ((result.SettlementMode == "现金期末" || result.SettlementMode == "未知区间") && valueDate.Date != td.ExerciseDate.Value.Date) { tc = InnerSaveCash(trade: td, valueDate: result.PaymentDate, happenDate: result.PaymentDate, cashAction: action, exerciseWay: exerciseWay, closePrice: closePrice, paymentAmount: 0, isKnockOut: false, isLastAction: false); } } DbContext.SaveChanges(); SaveObservation(trade: td, cashId: tc?.id, valueDate: valueDate, result: result); //这里要保存,否则下面查询的时候,查不到最后一天的票息记录. DbContext.SaveChanges(); trans.Commit(); } if (td.TradeStatus == ConsTrade.已平仓) { return; } } //到期日生成票息资金记录 if (valueDate.Date == td.ExerciseDate.Value.Date) { if (tdAcc.SettlementMode == "现金期末") { var paymentAmount = DbContext.autocall_observation.Where(n => n.TradeId == td.id && n.SettlementMode == "现金期末") .Select(n => n.PaymentAmount).AsEnumerable().DefaultIfEmpty(0).Sum(); //根据买方角度计算盈亏 paymentAmount *= ConsGlobal.CallPut.IsCall(td.OptionType) ? closePrice - result.Strike : result.Strike - closePrice; paymentAmount = Commons.OtcFormatHelper.FormatValue(paymentAmount, 2); if (td.BuySell != "买入") { paymentAmount = -paymentAmount; } InnerSaveCash(trade: td, valueDate: valueDate, happenDate: valueDate , cashAction: ClientCashInCashOut.系统操作_行权费, exerciseWay: TradeCashExerciseWayEnum.到期行权 , closePrice: closePrice, paymentAmount: paymentAmount, isKnockOut: false, isLastAction: true); } td.SetFullClosedStatus(valueDate, ConsTrade.已到期); //生成确认书 if (PS.Config.IsAutoGenerateContracts) { //修改销售提成的状态 new SalesCommissionDataService(this).SetCommissionVaild(td.id); new TradeContractGenerateService(this).GenerateContractsAsync(new List { td.id }); } } } /// /// 结算方式选择“现金结算”,在每个观察日,系统自动计算收益并派发资金 /// public static CheckResult CheckAccumulatorPayoff(OtcTradeBase td, trade_accumulator_option tdAcc, DateTime valueDate, double closePrice, double notional) { if (td is null || tdAcc is null) { return null; } if (tdAcc.AccumulatorStructureType == AccumulatorStructureTypeEnum.Segmented) { return new InnerCheck2(td, tdAcc, valueDate, closePrice, notional).CheckOption(); } return new InnerCheck(td, tdAcc, valueDate, closePrice, notional).CheckOption(); } /// /// 保存 /// /// private void SaveForwardTrade(trade ftd) { ftd.CreateDate = DateTime.Now; ftd.CreatorId = UserId; ftd.CreatorName = UserName; DbContext.trade.Add(ftd); ftd.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(ftd, DbContext); var OptionType = ftd.OptionType; var BuySell = ftd.BuySell; if (PS.Config.ErpElement.OptionTypeAndBuySell == OptionTypeAndBuySell.固定多头判断买卖) { if (ftd.BuySell == "卖出" && ftd.OptionType == "看跌") { BuySell = "买入"; } if (ftd.BuySell == "买入" && ftd.OptionType == "看跌") { BuySell = "卖出"; } OptionType = "看涨"; } else if (PS.Config.ErpElement.OptionTypeAndBuySell == OptionTypeAndBuySell.固定买入判断多空) { if (ftd.BuySell == "卖出" && ftd.OptionType == "看涨") { OptionType = "看跌"; } if (ftd.BuySell == "卖出" && ftd.OptionType == "看跌") { OptionType = "看涨"; } BuySell = "买入"; } else if (PS.Config.ErpElement.OptionTypeAndBuySell == OptionTypeAndBuySell.固定卖出判断多空) { if (ftd.BuySell == "买入" && ftd.OptionType == "看涨") { OptionType = "看跌"; } if (ftd.BuySell == "买入" && ftd.OptionType == "看跌") { OptionType = "看涨"; } BuySell = "卖出"; } ftd.OptionType = OptionType; ftd.BuySell = BuySell; DbContext.SaveChanges(); InnerSaveCash(trade: ftd, valueDate: ftd.TradeDate.Value, happenDate: ftd.TradeDate.Value , cashAction: ClientCashInCashOut.系统操作_期权费, exerciseWay: null , closePrice: 0, paymentAmount: 0, isKnockOut: false, isLastAction: false); //生成确认书 if (PS.Config.IsAutoGenerateContracts) { //修改销售提成的状态 new SalesCommissionDataService(this).SetCommissionVaild(ftd.id); new TradeContractGenerateService(this).GenerateContractsAsync(new List { ftd.id }, "确认书"); } var forward = ftd.trade_forward; forward.TradeId = ftd.id; DbContext.trade_forward.Add(forward); foreach (var kv in ftd.MetaDic) { DbContext.TradeMeta.Add(new TradeMeta { TradeId = ftd.id, MetaKey = kv.Key, MetaValue = kv.Value, CreateTime = DateTime.Now }); } } /// /// 保存观察数据 /// private void SaveObservation(OtcTradeBase trade, int? cashId, DateTime valueDate, CheckResult result) { var observationRecord = DbContext.autocall_observation.FirstOrDefault(o => o.TradeId == trade.id && o.EndDate == valueDate.Date); if (observationRecord == null) { observationRecord = new autocall_observation { TradeId = trade.id, }; DbContext.autocall_observation.Add(observationRecord); } observationRecord.CashId = cashId; observationRecord.StartDate = result.StartDate; observationRecord.EndDate = valueDate.Date; observationRecord.StockEqvNotional = result.PaymentNotional * (trade.SpotPrice ?? 0); observationRecord.CouponRate = 0; observationRecord.PaymentDate = valueDate; observationRecord.ConvTradeNumber = null; observationRecord.SettlementMode = result.SettlementMode; observationRecord.PaymentAmount = result.PaymentAmount; observationRecord.PaymentNotional = result.PaymentNotional; if (result.ForwardTrade != null) { if (result.SettlementMode == "现金当日&转远期") { observationRecord.SettlementMode = "现金当日&转远期"; observationRecord.ConvTradeNumber = result.ForwardTrade.TradeNumber; } else { observationRecord.SettlementMode = "转远期"; observationRecord.ConvTradeNumber = result.ForwardTrade.TradeNumber; } } else { observationRecord.CouponRate = result.PaymentNotional != 0 ? result.PaymentAmount / result.PaymentNotional : 0; observationRecord.PaymentDate = result.PaymentDate; } } /// /// 保存资金记录 /// private trade_cash InnerSaveCash(OtcTradeBase trade, DateTime happenDate, DateTime valueDate, string cashAction, string exerciseWay, double closePrice, double paymentAmount, bool isLastAction, bool isKnockOut) { return SaveCash(trade: trade, cashAction: cashAction, exerciseWay: exerciseWay, paymentAmount: paymentAmount, valueDate: valueDate, underlyingPrice: closePrice, happenDate: happenDate, isKnockOut: isKnockOut, isLastAction: isLastAction); } public TradeAccumulatorChangeData GetChangeDataOfSepecialDay(int tradeId, DateTime valueDate) { var query = from a in DbContext.TradeAction.AsNoTracking() where a.IsValid && a.TradeId == tradeId && a.ValueDate <= valueDate && a.ActionType == TradeActionType.AccumulatorChange orderby a.ValueDate descending select a.ActionData; var actionData = query.FirstOrDefault(); return JsonHelper.Deserialize(actionData); } } public class CheckResult { /// /// 结算方式(敲出|转远期|现金当日|现金期末) /// public string SettlementMode { get; set; } /// /// 观察开始日 /// public DateTime StartDate { get; set; } /// /// 转远期 /// public trade ForwardTrade { get; set; } /// /// 支付日 /// public DateTime PaymentDate { get; set; } /// /// 交易员角度的支付金额或数量(实际是份额) /// public double PaymentAmount { get; set; } /// /// 结算份额(现在只有 累计期权 现金实物合并结算 结算方式有在用) /// public double PaymentNotional { get; set; } /// /// 执行价格 /// public double Strike { get; set; } /// /// 障碍价格 /// public double? Barrier { get; set; } /// /// 数量和份额的乘积因子 /// public int CountRatio { get; set; } } //------------------------------------------------------------ // 2021-10-28:以下转远期的交割价和期初标的价格先按照中粮的需求来(交割价和期初标的价格取累积期权的执行价) // 如果不按照中粮的需求来,期初标的价格取日终结算价格 //------------------------------------------------------------ public class InnerChecksBase { protected OtcTradeBase _td; protected trade_accumulator_option _tdAcc; protected DateTime _valueDate; protected double _closePrice; protected double _notional; protected bool _updownPriceMode; private readonly ErpBaseContext basedb = new(); protected InnerChecksBase(OtcTradeBase td, trade_accumulator_option tdAcc, DateTime valueDate, double closePrice, double notional) { _td = td ?? throw new ArgumentNullException(nameof(td)); _tdAcc = tdAcc ?? throw new ArgumentNullException(nameof(tdAcc)); _valueDate = valueDate; _closePrice = closePrice; _notional = notional; //累计三段式 暂时不使用该配置(原因与需求临界值有冲突) _updownPriceMode = GlobalConfig.AccumulatorCriticalMode == "updown"; } //票息率(绝对数值) protected (double, double) getCouponRate(double[] customCoupons, int valueDateIndex) { var couponRate = _tdAcc.Coupon; var couponRate2 = _tdAcc.Coupon2; if (customCoupons != null && customCoupons.Length > valueDateIndex) { couponRate = customCoupons[valueDateIndex]; } return (_tdAcc.CouponPercent ? couponRate * (_td.SpotPrice ?? 0) : couponRate, _tdAcc.CouponPercent ? (couponRate2 ?? 0) * (_td.SpotPrice ?? 0) : (couponRate2 ?? 0)); } //年化比例 protected double getDayCountFraction(DateTime startDate, DateTime settleDate, bool includeStartDate) { if (_tdAcc.IsFixedCoupon) { return 1; } var couponDayCount = (_tdAcc.CouponDayCount?.Trim() ?? "Act365").ToDayCountImpl(); if (startDate == settleDate) { return couponDayCount.OneDayFraction(); } var dayCountFraction = couponDayCount.CalcDayCountFraction(startDate, settleDate); if (includeStartDate && _td.StartDate == startDate) { return dayCountFraction + couponDayCount.OneDayFraction(); } return dayCountFraction; } //结算日期 protected DateTime GetSettleDate(int valueDateIndex) { var settleDates = QdpHelper.ParseObservationDate(_tdAcc.KOObservationSettleDates); if (settleDates != null && settleDates.Length > valueDateIndex) { var date = settleDates[valueDateIndex]; return QdpCalendarHelper.GetNonHoliday(date); } return _valueDate; } /// /// 转远期交易 /// /// 执行价格 /// 数量 /// 远期到期日类型 /// 远期期初价类型 protected trade ConvertToForward(double forwardStrike, double notional, string ForwardDateTypeStr, string ForwardPriceTypeStr) { var ftd = new trade(); YLAutoMapper.Map(_td, ftd); //标的信息 var um = DataCacheProvider.GetUnderlyingDataSource().GetData(ftd.UnderlyingCode); if (um == null) { throw new Exception($"累计期权'{_td.TradeNumber}'找不到标的信息:{ftd.UnderlyingCode},(转远期)失败"); } ftd.id = 0; ftd.ParentTradeId = 0; ftd.IsGroup = 0; ftd.TradeNumber = null; ftd.TradeType = "远期"; ftd.StructureType = "远期"; ftd.StructureIntroduction = null; ftd.ExtendInfo = null; ftd.ExerciseMode = null; ftd.TradeStatus = ConsTrade.确认成交; ftd.Comments += "累计期权:" + _td.TradeNumber; var date = um.MaturityDate.GetValueOrDefault(DateTime.MaxValue); //交易日期 switch (ForwardDateTypeStr) { case "标的到期日": ftd.ExerciseDate = um.MaturityDate; break; case "期权到期日": ftd.ExerciseDate = _td.ExerciseDate; break; default: var dictionarySerivice = new DictionarySerivice(); var dic = dictionarySerivice.GetForwardDateDic(); var dicModel = dic.FirstOrDefault(l => l.Value == ForwardDateTypeStr); if (dicModel.Value != null) { var model = basedb.DictionaryItems.Find(dicModel.Key); var lastMonth = Convert.ToInt32(model.Name); if (model.ShortName.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Any()) { var lastDay = Convert.ToInt32(model.ShortName.Split(",")[0]); var typeEnum = (ForwardDateTypeEnum)Convert.ToInt32(model.ShortName.Split(",")[1]); var isbefore = true; if (Convert.ToInt32(model.ShortName.Split(",")[1]) > 0) { isbefore = model.ShortName.Split(",")[2] == "0"; } ftd.ExerciseDate = dictionarySerivice.GetForwardDateType(date, lastMonth, lastDay, typeEnum, isbefore); } } else { ftd.ExerciseDate = _td.ExerciseDate; } break; } ////远期交易到期日(中粮需求:转远期时交易到期日取标的到期日) //if (PS.Config.Company == Configuration.CompanyEnum.中粮) //{ // ftd.ExerciseDate = um.MaturityDate; // ftd.SettlementDate = um.MaturityDate; //} ftd.SettlementDate = ftd.ExerciseDate; ftd.TradeDate = _valueDate; ftd.StartDate = _valueDate; ftd.CreateDate = DateTime.Now; //价格 ftd.IsMoneynessOption = null; ftd.Strike = forwardStrike; //期初价格 switch (ForwardPriceTypeStr) { case "期权期初价格": ftd.SpotPrice = _td.SpotPrice; break; case "远期开仓现价": ftd.SpotPrice = _closePrice; break; case "期权成交日收盘价": //标的收盘价 var dataSource = new EodPriceProvider(_td.StartDate.Value); ftd.SpotPrice = dataSource.GetPrice(ftd.UnderlyingCode, SettlementTypeEnum.ClosePrice); break; case "期权行权价格": default: ftd.SpotPrice = ftd.Strike; break; } if (_tdAcc.SettlementMode == "现金实物合并结算") { ftd.Strike = ftd.SpotPrice; } //开仓费用 ftd.TradePrice = 0; ftd.TradeSinglePrice = 0; ftd.PremiumRate = 0; ftd.PremiumPayDate = null; ftd.IsUsePremiumRate = false; ftd.IsTradePricePayType = false; ftd.IsAnnualized = false; ftd.AnnualizeFactor = null; ftd.ParticipationRate = null; ftd.PrincipalRate = null; //todo:保底收益率 //ftd.PrincipalSum = null; //ftd.PrincipalRateWrite = null; //ftd.SinglePrincipalWrite = null; //ftd.OriginalPrincipalSum = null; //ftd.OriginalPrincipalSum = null; //预付金 ftd.InitialMargin = null; ftd.InitialMarginRatio = null; ftd.MarginRate = 0; ftd.MarginTemplateName = null; ftd.MarginType = DBModels.Enums.MarginTypeEnum.DEFAULT; ftd.PositionMarginRate = 0; ftd.CalcFlag = 0; //基差 ftd.BasisGap = null; ftd.BasisUnderlyingCode = null; ftd.BasisUnderlyingId = null; //交易数量及名义本金 ftd.Notional = notional; ftd.Lots = ftd.Notional / um.ContractSize; ftd.TradeAmount = notional / um.CountRatio; ftd.OriginalNotional = ftd.Notional; ftd.StockEqvNotionalMax = null; ftd.OriginalStockEqvNotional = ftd.StockEqvNotionalReal = ftd.StockEqvNotional = Math.Abs(ftd.Notional * (ftd.SpotPrice ?? 0)); if (_td.MetaDic == null || _td.MetaDic.Count == 0) { _td.MetaDic = new TradeMetaService(OptUserInfo.SystemUser).GetTradeMeta(_td.id); } if (_td.MetaDic.TryGetValue("组合标的", out var value) && value?.Length > 2) { var synthetic = JsonHelper.Deserialize(value); if (PS.Config.Company == Configuration.CompanyEnum.浙期) { var arr = synthetic.SuList.OrderByDescending(O => O.Price).Select(O => O).ToArray(); var price = arr[0].Price; for (var i = 1; i < arr.Length - 1; i++) { price -= arr[i].Price * (arr[i].Coefficient > 0 ? 1 : -1); } arr[arr.Length - 1].Price = price + ftd.SpotPrice.Value * (arr[arr.Length - 1].Coefficient > 0 ? 1 : -1); synthetic.Price = ftd.SpotPrice.Value; } else { var suList = new Dictionary(); var suList2 = new Dictionary(); foreach (var item in synthetic.SuList) { if (ForwardPriceTypeStr == "期权行权价格" || ForwardPriceTypeStr == "远期开仓现价") { //标的收盘价 var dataSource = new EodPriceProvider(ftd.StartDate.Value); item.Price = dataSource.GetPrice(item.UnderlyingCode, SettlementTypeEnum.ClosePrice); } if (ForwardPriceTypeStr == "期权成交日收盘价") { //标的收盘价 var dataSource = new EodPriceProvider(_td.StartDate.Value); item.Price = dataSource.GetPrice(item.UnderlyingCode, SettlementTypeEnum.ClosePrice); } suList.Add(item.UnderlyingCode, item.Price); suList2.Add(item.UnderlyingCode, item.Price * item.Coefficient); } suList = suList.OrderBy(n => n.Value).ToDictionary(p => p.Key, o => o.Value); var minUnderlyingCode = suList.FirstOrDefault().Key; suList.Remove(minUnderlyingCode); suList2.Remove(minUnderlyingCode); var totalPrice = suList2.Sum(n => n.Value); if (ftd.SpotPrice.Value > totalPrice) { synthetic.SuList.FirstOrDefault(n => n.UnderlyingCode == minUnderlyingCode).Price = ftd.SpotPrice.Value + (suList2.Sum(n => n.Value) * -1); } else { synthetic.SuList.FirstOrDefault(n => n.UnderlyingCode == minUnderlyingCode).Price = (ftd.SpotPrice.Value * -1) + suList2.Sum(n => n.Value); } } ftd.MetaDic["组合标的"] = synthetic.ToJson(); } if (_td.MetaDic.TryGetValue("中央对手方清算", out var value2) && value2?.Length > 0) { ftd.MetaDic["中央对手方清算"] = value2; } if (_td.MetaDic.TryGetValue("中央清算平台", out var value3) && value3?.Length > 0) { ftd.MetaDic["中央清算平台"] = value3; } if (_td.MetaDic.TryGetValue("交易平台", out var value4) && value4?.Length > 0) { ftd.MetaDic["交易平台"] = value4; } if (_td.MetaDic.TryGetValue("ExchangeRate", out var value5) && value5?.Length > 0) { ftd.MetaDic["ExchangeRate"] = value5; } if (PS.Config.Is浙期 && um.IsCommoditySpot()) { ftd.MetaDic["ActualExerciseDate"] = ftd.ExerciseDate?.ToString("yyyy-MM-dd"); } //标的价格1,标的价格2 ftd.MetaDic["期初信息"] = $"[{ftd.SpotPrice:0.0###}]"; if (PS.Config.ErpElement.ForwardValueIsSupplyOrPay == YLErp.Configuration.Enums.ForwardValueIsSupplyOrPay.Type2) { ftd.MetaDic.Add("IsSupplyForwardValue", "-1"); } else { ftd.MetaDic.Add("IsSupplyForwardValue", "0"); } //累计转远期时,存一下累计期权的编号 ftd.MetaDic.Add("累计期权交易编号", _td.TradeNumber); //波动率/分红率 ftd.Vol = null; ftd.VolType = null; ftd.TradeOpenVolatility = null; ftd.TradeCloseVolatility = null; ftd.TradeSavedVol = null; ftd.YesterDayTradeSavedVol = null; ftd.NumOfSmoothingDays = null; ftd.DividendRatio = 0; ftd.DividendDate = DateTime.MinValue; //确认书 ftd.ContractCode = null; ftd.ContractVersion = null; ftd.IsSingleContract = null; ftd.SentMailCount = null; //审核 ftd.CheckStatus = null; ftd.CheckTradeUpdate = null; ftd.ProcessOptDate = null; ftd.ProcessOrderId = 0; ftd.ProcessStatus = null; //unwind ftd.UnWindDate = null; ftd.UnWindFee = ftd.UnWindNotional = ftd.UnWindPrice = null; ftd.UnWindTimes = 0; ftd.UnWindTotalAmount = null; ftd.UnWindTradePrice = null; ftd.UnWindUnderlyingPrice = null; ftd.FinalPrice = null; ftd.HasPartialUnWind = null; //配对交易 ftd.PairTrade = ftd.PairTradeNumber = null; var forward = new trade_forward { AnnualMarginRate = 0, AnnualStoragePrice = 0, ForwardValue = ((ftd.SpotPrice - ftd.Strike) * ftd.Notional * ((ftd.BuySell == "买入" && ftd.OptionType == "看涨") || (ftd.BuySell == "卖出" && ftd.OptionType == "看跌") ? 1 : -1)) ?? 0, ObservationDates = null, OpenCommission = 0, OptDate = DateTime.Now, OptId = 0, OptName = "系统", TradeId = 0 }; //forward.ForwardValue = new ForwardTradeImportService(null).GetForwardValue(forwardSpotPrice, forwardStrike, ftd.TradeAmount, um.CountRatio, ftd.OptionType, ftd.BuySell); ftd.trade_forward = forward; return ftd; } } /// /// 内部检查封装类,这个类不涉及到对交易数据的修改仅获取检查结果 /// public class InnerCheck : InnerChecksBase { public InnerCheck(OtcTradeBase td, trade_accumulator_option tdAcc, DateTime valueDate, double closePrice, double notional) : base(td, tdAcc, valueDate, closePrice, notional) { } /// /// 累购期权 /// /// 行权价 /// 障碍价 /// 观察日 /// 票息 /// 观察状态 /// 支付日期 /// 支付数量 /// 支付总额 /// 远期交易 private void CheckCallOption(double strike, double barrier, Date[] koObservationDates, Lazy lazyCouponCalcInfo, out string settleMode, out DateTime paymentDate, out double paymentNotional, out double paymentAmount, out trade forwardTrade) { forwardTrade = null; paymentDate = _valueDate; //超出上限则敲出 if (_closePrice > barrier || (_updownPriceMode && Math.Abs(_closePrice - barrier) < 1e-6)) { settleMode = "敲出"; paymentAmount = paymentNotional = 0; } //低于下限(执行价格)则买方赔付(使用看跌乘数) else if (_closePrice < strike || (_updownPriceMode && Math.Abs(_closePrice - strike) < 1e-6)) { paymentNotional = _tdAcc.PutMultiplier * _notional; //子弹类型到期日当天赔付数量膨胀 if (_tdAcc.AccumuType == "子弹" && _td.ExerciseDate == _valueDate) { paymentNotional *= koObservationDates.Length; } if (string.IsNullOrWhiteSpace(_tdAcc.SettlementMode) || _tdAcc.SettlementMode == "现金当日") { settleMode = "现金当日"; //赔付现金,当标的资产价格低于行权价时,赔付看跌乘数倍的看跌期权损失 paymentAmount = (_closePrice - strike) * paymentNotional; } else if (_tdAcc.SettlementMode == "现金期末") { settleMode = "现金期末"; paymentAmount = paymentNotional; } else if (_tdAcc.SettlementMode == "实物交割") { settleMode = "转远期"; paymentAmount = paymentNotional; //赔付的时候交割价使用执行价即可 forwardTrade = ConvertToForward(forwardStrike: strike, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType, ForwardPriceTypeStr: _tdAcc.ForwardPriceType); } else if (_tdAcc.SettlementMode == "现金实物合并结算") { settleMode = "现金当日&转远期"; paymentAmount = (_closePrice - strike) * paymentNotional; //赔付的时候交割价使用执行价即可 forwardTrade = ConvertToForward(forwardStrike: strike, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType, ForwardPriceTypeStr: _tdAcc.ForwardPriceType); } else { throw new ServiceException("未知的结算方式:" + _tdAcc.SettlementMode); } } //在上下限之间则买方获得收益(使用看涨乘数) else { paymentNotional = _tdAcc.CallMultiplier * _notional; if (_tdAcc.SettlementMode == "实物交割") { if (_tdAcc.AccumuType == "区间现金结算") { if (_tdAcc.PayoffType == "固定") { settleMode = "票息"; //固定:当标的资产价格高于行权价且低于障碍价格时,获得票息收益 paymentAmount = lazyCouponCalcInfo.Value.singleCoupon * paymentNotional; paymentDate = lazyCouponCalcInfo.Value.settleDate; } else { settleMode = "现金当日"; //当标的资产价格高于行权价且低于障碍价格时,买方获得看涨乘数倍的看涨期权收益 paymentAmount = (_closePrice - strike) * paymentNotional; } } else { settleMode = "转远期"; paymentAmount = paymentNotional; forwardTrade = ConvertToForward(forwardStrike: strike, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType, ForwardPriceTypeStr: _tdAcc.ForwardPriceType); } } else if (_tdAcc.SettlementMode == "现金实物合并结算") { if (_tdAcc.AccumuType == "区间现金结算") { if (_tdAcc.PayoffType == "固定") { settleMode = "票息"; //固定:当标的资产价格高于行权价且低于障碍价格时,获得票息收益 paymentAmount = lazyCouponCalcInfo.Value.singleCoupon * paymentNotional; paymentDate = lazyCouponCalcInfo.Value.settleDate; } else { settleMode = "现金当日"; //当标的资产价格高于行权价且低于障碍价格时,买方获得看涨乘数倍的看涨期权收益 paymentAmount = (_closePrice - strike) * paymentNotional; } } else { settleMode = "现金当日&转远期"; if (_tdAcc.PayoffType == "固定") { paymentAmount = lazyCouponCalcInfo.Value.singleCoupon * paymentNotional; } else { paymentAmount = (_closePrice - strike) * paymentNotional; } forwardTrade = ConvertToForward(forwardStrike: strike, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType, ForwardPriceTypeStr: _tdAcc.ForwardPriceType); } } //现金-固定票息 else if (_tdAcc.PayoffType == "固定") { settleMode = "票息"; //固定:当标的资产价格高于行权价且低于障碍价格时,获得票息收益 paymentAmount = lazyCouponCalcInfo.Value.singleCoupon * paymentNotional; paymentDate = lazyCouponCalcInfo.Value.settleDate; } //现金-浮动收益 else if (_tdAcc.SettlementMode == "现金期末") { settleMode = "现金期末"; paymentAmount = paymentNotional; } else if (string.IsNullOrWhiteSpace(_tdAcc.SettlementMode) || _tdAcc.SettlementMode == "现金当日") { settleMode = "现金当日"; //当标的资产价格高于行权价且低于障碍价格时,买方获得看涨乘数倍的看涨期权收益 paymentAmount = (_closePrice - strike) * paymentNotional; } else { throw new ServiceException("未知的结算方式:" + _tdAcc.SettlementMode); } } } /// /// 累沽期权 /// /// 行权价 /// 障碍价 /// 观察日 /// 票息 /// 观察状态 /// 支付日期 /// 支付数量 /// 支付总额 /// 远期交易 private void CheckPutOption(double strike, double barrier, Date[] koObservationDates, Lazy couponCalcInfo, out string settleMode, out DateTime paymentDate, out double paymentNotional, out double paymentAmount, out trade forwardTrade) { forwardTrade = null; paymentDate = _valueDate; //低于下限则敲出 if (_closePrice < barrier || (_updownPriceMode && Math.Abs(_closePrice - barrier) < 1e-6)) { settleMode = "敲出"; paymentAmount = paymentNotional = 0; } //超过上限(执行价)则买方赔付(使用看涨乘数) else if (_closePrice > strike || (_updownPriceMode && Math.Abs(_closePrice - strike) < 1e-6)) { paymentNotional = _tdAcc.CallMultiplier * _notional; //子弹类型到期日当天赔付数量膨胀 if (_tdAcc.AccumuType == "子弹" && _td.ExerciseDate == _valueDate) { paymentNotional *= koObservationDates.Length; } if (string.IsNullOrWhiteSpace(_tdAcc.SettlementMode) || _tdAcc.SettlementMode == "现金当日") { settleMode = "现金当日"; //赔付现金,当标的资产价格高于行权价时,赔付看涨乘数倍的看涨期权损失 paymentAmount = (strike - _closePrice) * paymentNotional; } else if (_tdAcc.SettlementMode == "现金期末") { settleMode = "现金期末"; paymentAmount = paymentNotional; } else if (_tdAcc.SettlementMode == "实物交割") { settleMode = "转远期"; paymentAmount = paymentNotional; forwardTrade = ConvertToForward(forwardStrike: strike, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType, ForwardPriceTypeStr: _tdAcc.ForwardPriceType); } else if (_tdAcc.SettlementMode == "现金实物合并结算") { settleMode = "现金当日&转远期"; //赔付现金,当标的资产价格高于行权价时,赔付看涨乘数倍的看涨期权损失 paymentAmount = (strike - _closePrice) * paymentNotional; forwardTrade = ConvertToForward(forwardStrike: strike, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType, ForwardPriceTypeStr: _tdAcc.ForwardPriceType); } else { throw new ServiceException("未知的结算方式:" + _tdAcc.SettlementMode); } } //在上下限之间则买方获得收益(使用看跌乘数) else { paymentNotional = _tdAcc.PutMultiplier * _notional; if (_tdAcc.SettlementMode == "实物交割") { if (_tdAcc.AccumuType == "区间现金结算") { if (_tdAcc.PayoffType == "固定") { settleMode = "票息"; //固定:当标的资产价格高于行权价且低于障碍价格时,获得票息收益 paymentAmount = couponCalcInfo.Value.singleCoupon * paymentNotional; paymentDate = couponCalcInfo.Value.settleDate; } else { settleMode = "现金当日"; //当标的资产价格低于行权价且高于障碍价格时,获得看跌乘数倍的看跌期权收益 paymentAmount = (strike - _closePrice) * paymentNotional; } } else { settleMode = "转远期"; paymentAmount = paymentNotional; forwardTrade = ConvertToForward(forwardStrike: strike, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType, ForwardPriceTypeStr: _tdAcc.ForwardPriceType); } } else if (_tdAcc.SettlementMode == "现金实物合并结算") { if (_tdAcc.AccumuType == "区间现金结算") { if (_tdAcc.PayoffType == "固定") { settleMode = "票息"; //固定:当标的资产价格高于行权价且低于障碍价格时,获得票息收益 paymentAmount = couponCalcInfo.Value.singleCoupon * paymentNotional; paymentDate = couponCalcInfo.Value.settleDate; } else { settleMode = "现金当日"; //当标的资产价格低于行权价且高于障碍价格时,获得看跌乘数倍的看跌期权收益 paymentAmount = (strike - _closePrice) * paymentNotional; } } else { settleMode = "现金当日&转远期"; if (_tdAcc.PayoffType == "固定") { paymentAmount = couponCalcInfo.Value.singleCoupon * paymentNotional; } else { paymentAmount = (strike - _closePrice) * paymentNotional; } forwardTrade = ConvertToForward(forwardStrike: strike, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType, ForwardPriceTypeStr: _tdAcc.ForwardPriceType); } } //现金-固定票息 else if (_tdAcc.PayoffType == "固定") { settleMode = "票息"; //当标的资产价格低于行权价且高于障碍价格时,获得票息收益 paymentAmount = couponCalcInfo.Value.singleCoupon * paymentNotional; paymentDate = couponCalcInfo.Value.settleDate; } //现金-浮动收益 else if (_tdAcc.SettlementMode == "现金期末") { settleMode = "现金期末"; paymentAmount = paymentNotional; } else if (string.IsNullOrWhiteSpace(_tdAcc.SettlementMode) || _tdAcc.SettlementMode == "现金当日") { settleMode = "现金当日"; //当标的资产价格低于行权价且高于障碍价格时,获得看跌乘数倍的看跌期权收益 paymentAmount = (strike - _closePrice) * paymentNotional; } else { throw new ServiceException("未知的结算方式:" + _tdAcc.SettlementMode); } } } /// /// 累计期权结算检查(交易员角度) /// public CheckResult CheckOption() { //解析观测日期 var customObservDates = QdpHelper.ParseAutocallCustomizedInfo(_tdAcc.KOObservationDates); var koObservationDates = customObservDates.Item1; var customKOBarriers = customObservDates.Item2; double[] customCoupons = null;// customObservDates.Item3; koObservationDates ??= CalendarImpl.Get("chn").BizDaysBetweenDatesExcluStartDay(_td.TradeDate.Value, _td.ExerciseDate.Value).ToArray(); var valueDateIndex = Array.IndexOf(koObservationDates, new Date(_valueDate)); if (valueDateIndex < 0) { return null; } //执行价和障碍价格 var strike = _td.Strike ?? 0; double? barrier = _tdAcc.KOBarrier, barrier2 = null; if (customKOBarriers != null && customKOBarriers.Length > valueDateIndex) { barrier = customKOBarriers[valueDateIndex]; } if (_td.IsMoneynessOptionData) { strike *= _td.SpotPrice.Value; barrier *= _td.SpotPrice.Value; } if (barrier.HasValue) { barrier2 = barrier; } else { barrier = ConsGlobal.CallPut.IsCall(_td.OptionType) ? 1e10 : -1e10; } //观察开始日 var startDate = valueDateIndex > 0 ? koObservationDates[valueDateIndex - 1] : new Date(_td.StartDate.Value); //以买方角度计算金额或数量 string settleMode = null; trade forwardTrade = null; DateTime paymentDate; double paymentAmount, paymentNotional; var lazyCouponCalcInfo = new Lazy(() => { var settleDate = GetSettleDate(valueDateIndex); //var includeStartDate = valueDateIndex == 0; return new CouponCalcInfo { settleDate = settleDate, singleCoupon = getCouponRate(customCoupons, valueDateIndex).Item1 * getDayCountFraction(startDate: startDate, settleDate: settleDate, includeStartDate: false) }; }); //累购期权 if (_td.OptionType == "看涨") { CheckCallOption(strike, barrier.Value, koObservationDates, lazyCouponCalcInfo, out settleMode, out paymentDate, out paymentNotional, out paymentAmount, out forwardTrade); } //累沽期权 else { CheckPutOption(strike, barrier.Value, koObservationDates, lazyCouponCalcInfo, out settleMode, out paymentDate, out paymentNotional, out paymentAmount, out forwardTrade); } var result = new CheckResult { SettlementMode = settleMode, StartDate = startDate, ForwardTrade = forwardTrade, PaymentDate = paymentDate, PaymentAmount = paymentAmount, PaymentNotional = paymentNotional, Strike = strike, Barrier = barrier2 }; if (result.SettlementMode == "现金期末" || result.SettlementMode == "转远期" || result.SettlementMode == "转掉期") { result.PaymentAmount = paymentNotional; } else { //支付票息时精确到分 result.PaymentAmount = Commons.OtcFormatHelper.FormatValue(paymentAmount, 2); if (_td.BuySell != "买入") { result.PaymentAmount = -result.PaymentAmount; //转换为交易员角度 } } result.CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(_td.UnderlyingCode)?.CountRatio ?? 1; return result; } } /// /// 累计三段式 /// public class InnerCheck2 : InnerChecksBase { public InnerCheck2(OtcTradeBase td, trade_accumulator_option tdAcc, DateTime valueDate, double closePrice, double notional) : base(td, tdAcc, valueDate, closePrice, notional) { } /// /// 累购期权 三段式 /// /// 行权价 /// 障碍价 /// 观察日 /// 票息 /// 观察状态 /// 支付日期 /// 支付数量 /// 支付总额 /// 远期交易 private void CheckCallOption(double strike, double strike2, double strike3, double barrier, Date[] koObservationDates, Lazy lazyCouponCalcInfo, out string settleMode, out DateTime paymentDate, out double paymentNotional, out double paymentAmount, out trade forwardTrade) { forwardTrade = null; paymentDate = _valueDate; //腿一 if (_closePrice < strike)//0<=S strike3 || (Math.Abs(_closePrice - strike3) < 1e-6 && _tdAcc.PayoffType == "固定")) { paymentNotional = _notional * (_tdAcc.Multiplier3 ?? 0); //转远期则直接返回结果 if (_tdAcc.SettlementMode3 == "实物交割") { settleMode = "转远期"; paymentAmount = paymentNotional; //赔付的时候交割价使用执行价即可 forwardTrade = ConvertToForward(forwardStrike: strike3, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType3, ForwardPriceTypeStr: _tdAcc.ForwardPriceType3); } else if (_tdAcc.SettlementMode3 == "现金实物合并结算") { settleMode = "现金当日&转远期"; if (_tdAcc.PayoffType == "固定") { paymentAmount = lazyCouponCalcInfo.Value.singleCoupon2 * paymentNotional; } else { paymentAmount = (_closePrice - strike3) * paymentNotional; } //赔付的时候交割价使用执行价即可 forwardTrade = ConvertToForward(forwardStrike: strike3, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType3, ForwardPriceTypeStr: _tdAcc.ForwardPriceType3); } else if (_tdAcc.PayoffType == "固定")//票息支付 { settleMode = "票息"; paymentAmount = lazyCouponCalcInfo.Value.singleCoupon2 * paymentNotional; paymentDate = lazyCouponCalcInfo.Value.settleDate; } else if (_tdAcc.SettlementMode3 == "现金当日")//Aca112*(S-K3) { settleMode = "现金当日"; paymentAmount = (_closePrice - strike3) * paymentNotional; } else { throw new ServiceException("未知的结算方式:" + _tdAcc.SettlementMode3); } } else { settleMode = "现金当日"; paymentAmount = paymentNotional = 0; } } /// /// 累沽期权 三段式 /// /// 行权价 /// 障碍价 /// 观察日 /// 票息 /// 观察状态 /// 支付日期 /// 支付数量 /// 支付总额 /// 远期交易 private void CheckPutOption(double strike, double strike2, double strike3, double barrier, Date[] koObservationDates, Lazy couponCalcInfo, out string settleMode, out DateTime paymentDate, out double paymentNotional, out double paymentAmount, out trade forwardTrade) { forwardTrade = null; paymentDate = _valueDate; if (_closePrice < strike || (Math.Abs(_closePrice - strike) < 1e-6 && _tdAcc.PayoffType == "固定"))//0<=S 1e-6) || (Math.Abs(_closePrice - strike) < 1e-6 && _tdAcc.PayoffType == "浮动"))//K1<=S<=B || UpdownPriceMode && K1 strike3)//S>K3 || UpdownPriceMode && S>=K3 payoff -Acall*(S-K3) { paymentNotional = _notional * (_tdAcc.Multiplier3 ?? 0); if (string.IsNullOrWhiteSpace(_tdAcc.SettlementMode3) || _tdAcc.SettlementMode3 == "现金当日") { settleMode = "现金当日"; paymentAmount = (strike3 - _closePrice) * paymentNotional; } //转远期则直接返回结果 else if (_tdAcc.SettlementMode3 == "实物交割") { settleMode = "转远期"; paymentAmount = paymentNotional; //赔付的时候交割价使用执行价即可 forwardTrade = ConvertToForward(forwardStrike: strike3, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType3, ForwardPriceTypeStr: _tdAcc.ForwardPriceType3); } else if (_tdAcc.SettlementMode3 == "现金实物合并结算") { settleMode = "现金当日&转远期"; paymentAmount = (strike3 - _closePrice) * paymentNotional; //赔付的时候交割价使用执行价即可 forwardTrade = ConvertToForward(forwardStrike: strike3, notional: paymentNotional, ForwardDateTypeStr: _tdAcc.ForwardDateType3, ForwardPriceTypeStr: _tdAcc.ForwardPriceType3); } else { throw new ServiceException("未知的结算方式:" + _tdAcc.SettlementMode3); } } else//K2<=S<=K3 || UpdownPriceMode && K2<=S /// 累计期权结算检查(交易员角度) 三段式 /// public CheckResult CheckOption() { //解析观测日期 var customObservDates = QdpHelper.ParseAutocallCustomizedInfo(_tdAcc.KOObservationDates); var koObservationDates = customObservDates.Item1; var customKOBarriers = customObservDates.Item2; double[] customCoupons = null;// customObservDates.Item3; koObservationDates ??= CalendarImpl.Get("chn").BizDaysBetweenDatesExcluStartDay(_td.TradeDate.Value, _td.ExerciseDate.Value).ToArray(); var valueDateIndex = Array.IndexOf(koObservationDates, new Date(_valueDate)); if (valueDateIndex < 0) { return null; } //执行价和障碍价格 var strike = _td.Strike ?? 0; var strike2 = _tdAcc.Strike2 ?? 0; var strike3 = _tdAcc.Strike3 ?? 0; double? barrier = _tdAcc.KOBarrier, barrier2 = null; if (customKOBarriers != null && customKOBarriers.Length > valueDateIndex) { barrier = customKOBarriers[valueDateIndex]; } if (_td.IsMoneynessOptionData) { strike *= _td.SpotPrice.Value; strike2 *= _td.SpotPrice.Value; strike3 *= _td.SpotPrice.Value; barrier *= _td.SpotPrice.Value; } if (barrier.HasValue) { barrier2 = barrier; } else { barrier = ConsGlobal.CallPut.IsCall(_td.OptionType) ? 1e10 : -1e10; } //观察开始日 var startDate = valueDateIndex > 0 ? koObservationDates[valueDateIndex - 1] : new Date(_td.StartDate.Value); //以买方角度计算金额或数量 string settleMode = null; trade forwardTrade = null; DateTime paymentDate; double paymentAmount, paymentNotional; var lazyCouponCalcInfo = new Lazy(() => { var settleDate = GetSettleDate(valueDateIndex); var couponModle = getCouponRate(customCoupons, valueDateIndex); //var includeStartDate = valueDateIndex == 0; return new CouponCalcInfo { settleDate = settleDate, singleCoupon = couponModle.Item1 * getDayCountFraction(startDate: startDate, settleDate: settleDate, includeStartDate: false), singleCoupon2 = couponModle.Item2 * getDayCountFraction(startDate: startDate, settleDate: settleDate, includeStartDate: false) }; }); //累购期权 if (_td.OptionType == "看涨") { CheckCallOption(strike, strike2, strike3, barrier.Value, koObservationDates, lazyCouponCalcInfo, out settleMode, out paymentDate, out paymentNotional, out paymentAmount, out forwardTrade); } //累沽期权 else { CheckPutOption(strike, strike2, strike3, barrier.Value, koObservationDates, lazyCouponCalcInfo, out settleMode, out paymentDate, out paymentNotional, out paymentAmount, out forwardTrade); } var result = new CheckResult { SettlementMode = settleMode, StartDate = startDate, ForwardTrade = forwardTrade, PaymentDate = paymentDate, PaymentAmount = paymentAmount, PaymentNotional = paymentNotional, Strike = strike, Barrier = barrier2 }; if (result.SettlementMode == "现金期末" || result.SettlementMode == "转远期" || result.SettlementMode == "转掉期") { result.PaymentAmount = paymentNotional; } else { //支付票息时精确到分 result.PaymentAmount = Commons.OtcFormatHelper.FormatValue(paymentAmount, 2); if (_td.BuySell != "买入") { result.PaymentAmount = -result.PaymentAmount; //转换为交易员角度 } } result.CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(_td.UnderlyingCode)?.CountRatio ?? 1; return result; } } struct CouponCalcInfo { public double singleCoupon { get; set; } public double singleCoupon2 { get; set; } public DateTime settleDate { get; set; } } }