using YLErp.BLL; using YLErp.DBModels.Enums; using YLErp.DBModels.Helpers; using YLErp.Modules.EodModule; using YLErp.QdpModule; namespace YLErp.Modules.TradeModule.DealModule { /// /// 交易回退服务 /// public class TradeBackService : TradeServiceBase { public TradeBackService(OptUserInfo userInfo) : base(userInfo) { } public TradeBackService(YLBaseService baseService) : base(baseService) { } public TradeBackService(OptUserInfo userInfo, YLContext dbContext) : base(userInfo, dbContext) { } public trade Execute(int tradeId, bool backToBegin, TradeBackActionEnum actionEnum) { var trade = DbContext.trade.Find(tradeId); if (trade == null) { throw new ServiceException("交易数据不存在"); } new TradeExtendService(UserInfo, DbContext).SetTradeExtend(new[] { trade }, tracking: true); if (trade.TradeType == "累计期权") { backToBegin = true; if (trade.trade_accumulator_option.SettlementMode == "实物交割" || trade.trade_accumulator_option.SettlementMode == "现金实物合并结算") { var query = from ob in DbContext.autocall_observation join tf in DbContext.trade on ob.ConvTradeNumber equals tf.TradeNumber where ob.TradeId == trade.id && (ob.SettlementMode == "转远期" || ob.SettlementMode == "转掉期" || ob.SettlementMode == "现金当日&转远期") && tf.ValidState != ConsGlobal.InValid select ob; if (query.Any()) { throw new ServiceException($"操作失败,当前累计期权交易({trade.TradeNumber})已结算为远期交易,请将所有结算后的远期交易删除后重新执行回退操作!"); } } } var valueDate = trade.TradeDate.Value; var tradeCashIds = new List(); var actions = new List() { "系统操作-行权费", "系统操作-平仓费", "系统操作-票息", "系统操作-互换" }; var tcQuery = DbContext.trade_cash.Where(x => x.TradeId == tradeId && (actions.Contains(x.Action) || x.Action == "系统操作-期权费" && x.ValueDate != trade.TradeDate && x.ValueDate != trade.PremiumPayDate) && x.ValidState != ConsGlobal.InValid && !x.IsDeleted); var eodTrade = DbContext.eod_trade.Where(O => O.TradeId == tradeId && O.ValueDate == trade.TradeDate).FirstOrDefault(); var originTrade = eodTrade?.trade; if (originTrade == null) { originTrade = trade; new TradeExtendService(UserInfo, DbContext).SetTradeExtend(new[] { originTrade }); } var stockEqvNotionalUnwind = (originTrade.OriginalStockEqvNotional ?? 0) - originTrade.StockEqvNotional; var extensionTimeService = new ExtensionTimeService(UserInfo, DbContext); if (backToBegin) { var tcTemp = DbContext.trade_cash.Where(x => x.TradeId == tradeId && x.Action == "系统操作-期权费" && x.ValidState != ConsGlobal.InValid && !x.IsDeleted).FirstOrDefault(); if (tcTemp == null) { throw new ServiceException("未查询到该交易的开仓记录,请删除该笔交易重新操作"); } originTrade.TradeStatus = ConsTrade.确认成交; originTrade.OriginalNotional = tcTemp.Notional; originTrade.Notional = tcTemp.Notional; originTrade.StockEqvNotional = originTrade.OriginalStockEqvNotional ?? 0; DividendService.SetDividendTradeData(trade, originTrade); valueDate = trade.TradeDate.Value; tradeCashIds.AddRange(tcQuery.Select(O => O.id).ToList()); trade.UnWindDate = null; trade.FinalPrice = null; trade.UnWindNotional = null; trade.UnWindPrice = null; trade.HasPartialUnWind = null; extensionTimeService.DelExtensionTime(tradeId, DateTime.MinValue, actionEnum != TradeBackActionEnum.EditMaturityDate); } else { if (!tcQuery.Any()) { throw new ServiceException("未查询到该交易的了结记录,不可回退"); } //有行权记录先回撤行权记录,没有行权记录,依次倒序撤回平仓记录 var tradeCash = tcQuery.OrderByDescending(x => x.id).FirstOrDefault(); var et = extensionTimeService.QueryExtensionTimeList(tradeId).Where(O => O.OptDate > tradeCash.ValueDate).OrderByDescending(O => O.OptDate).FirstOrDefault(); if (et != null) { extensionTimeService.DelExtensionTime(et.TradeId, et.id); return trade; } trade.Notional = tradeCash.Notional; if (trade.TradeType == "现金流交易") { if (tradeCash.UnwindType == "全部平仓") { trade.StockEqvNotional = tradeCash.Notional; } else { trade.StockEqvNotional = trade.StockEqvNotional + tradeCash.UnwindNotional.Value; } } else { if (trade.IsUsePremiumRate == true) { //后期将会将所有已了结的交易均处理为0 if (ConsTrade.TradeCompleteStatus.Contains(trade.TradeStatus)) { trade.StockEqvNotional = 0; } trade.StockEqvNotional += trade.OriginalStockEqvNotional * tradeCash.UnwindPercentRate ?? 0; } else { if (trade.TradeType == "远期" && PS.Config.ErpElement.ForwardTradePriceModel == 0 && !string.IsNullOrWhiteSpace(trade.BasisUnderlyingCode)) { trade.StockEqvNotional += TradeHelper.GetStockEqvNotional(tradeCash.UnwindNotional / trade.OriginalNotional * trade.OriginalStockEqvNotional, trade.ParticipationRate, trade.AnnualizeFactor); } else { trade.StockEqvNotional = TradeHelper.GetStockEqvNotional(trade.Notional * trade.SpotPrice, trade.ParticipationRate, trade.AnnualizeFactor); } } } valueDate = tradeCash.ValueDate; tradeCashIds.Add(tradeCash.id); //分步回退时将倒数第二条平仓记录赋值给trade var lastSecondTradeCash = tcQuery.Where(x => x.id != tradeCash.id).OrderByDescending(x => x.id).FirstOrDefault(); if (lastSecondTradeCash != null && lastSecondTradeCash.Action == "系统操作-平仓费") { trade.UnWindDate = lastSecondTradeCash.ValueDate; trade.FinalPrice = lastSecondTradeCash.FinalPrice; trade.UnWindNotional = lastSecondTradeCash.UnwindNotional; trade.UnWindPrice = lastSecondTradeCash.UnwindPrice; trade.HasPartialUnWind = 1; } else { trade.UnWindDate = null; trade.FinalPrice = null; trade.UnWindNotional = null; trade.UnWindPrice = null; trade.HasPartialUnWind = null; } } trade.TradeAmount = trade.Notional; var varietyList = VarietyBLL.GetAllvarietyModel(); if (!string.IsNullOrWhiteSpace(trade.UnderlyingAssetClass)) { var variety = varietyList.FirstOrDefault(O => O.VarietyName == trade.UnderlyingAssetClass); if (variety != null) { trade.TradeUnit = variety.TradeUnit; trade.TradeAmount /= variety.CountRatio; } } trade.CheckStatus = null; trade.OptId = UserId; trade.OptName = UserName; trade.OptDate = DateTime.Now; trade.TradeStatus = ConsTrade.确认成交; trade.IsApproval = false; trade.ProcessOrderId = 0; trade.ProcessOptDate = null; trade.ProcessStatus = null; trade.DividendDate = new DateTime(2000, 1, 1); trade.SettlementFlag = 0; //if (trade.TradeType == "结构化交易") //{ // var tradeChildren = DbContext.trade.Where(x => x.ParentTradeId == trade.id).ToList(); // tradeChildren.ForEach(x => // { // Execute(x.id, true, actionEnum); // }); //} //结构化交易回退时传入的是子交易的Id,此时只需要删掉主交易的Eod记录即可; if (trade.ParentTradeId > 0) { RemoveEodTradeAndFutureInfo(false, trade.ParentTradeId, valueDate, backToBegin: backToBegin); } if (backToBegin) { if (trade.TradeType == "障碍期权") { trade.trade_barrier_option.KnockInOutStatus = null; trade.trade_barrier_option.KnockInOutDate = null; } else if (trade.TradeType == "双鲨期权") { trade.trade_double_sharkfin_option.KnockInOutStatus = null; trade.trade_double_sharkfin_option.KnockInOutDate = null; } else if (trade.TradeType == "凤凰期权") { trade.trade_autocall.KnockInOutStatus = null; trade.trade_autocall.KnockInOutDate = null; var autoCallObservations = DbContext.autocall_observation.Where(x => x.TradeId == trade.id); DbContext.autocall_observation.RemoveRange(autoCallObservations); } else if (trade.TradeType == "雪球期权") { if (trade.trade_snowball.IsInitialKnockedIn) { trade.trade_snowball.KnockInOutStatus = ConsTrade.KnockState.KnockedIn; trade.trade_snowball.KnockInOutDate = trade.TradeDate; } else { trade.trade_snowball.KnockInOutStatus = null; trade.trade_snowball.KnockInOutDate = null; } var autoCallObservations = DbContext.autocall_observation.Where(x => x.TradeId == trade.id); DbContext.autocall_observation.RemoveRange(autoCallObservations); } else if (trade.TradeType == "区间累积期权") { var autoCallObservations = DbContext.autocall_observation.Where(x => x.TradeId == trade.id); DbContext.autocall_observation.RemoveRange(autoCallObservations); } else if (trade.TradeType == "累计期权") { trade.trade_accumulator_option.KnockOutDate = null; var autoCallObservations = DbContext.autocall_observation.Where(x => x.TradeId == trade.id); DbContext.autocall_observation.RemoveRange(autoCallObservations); new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(trade, trade.TradeDate.Value); var accumulator = trade.trade_accumulator_option; if (accumulator != null) { var customObservDates = QdpHelper.ParseObservationDate(accumulator.KOObservationDates); if (customObservDates == null) { customObservDates = Qdp.Pricing.Base.Implementations.CalendarImpl.Get("chn") .BizDaysBetweenDatesExcluStartDay(trade.TradeDate.Value, trade.ExerciseDate.Value).ToArray(); } var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); accumulator.OriginalAccumuTradeAmount = (originTrade.OriginalNotional ?? 0) / underlying.CountRatio / customObservDates.Length; accumulator.AccumuTradeAmount = accumulator.OriginalAccumuTradeAmount; } } else if (trade.TradeType == "收益互换") { trade.trade_swap.GetFinalPrice = null; trade.trade_swap.PayFinalPrice = null; if (trade.IsGroup == 2) { var parentTrade = DbContext.trade.Find(trade.ParentTradeId); parentTrade.StockEqvNotional += stockEqvNotionalUnwind; parentTrade.TradeStatus = "确认成交"; var swapDetail = DbContext.trade_swap_detail.FirstOrDefault(x => x.TradeId == trade.ParentTradeId && x.ChildTradeId == trade.id); swapDetail.Notional = trade.Notional; } } else if (trade.TradeType == "气囊结构") { trade.trade_airbag.KnockInOutStatus = null; trade.trade_airbag.KnockInOutDate = null; trade.trade_airbag.KnockInOutNotional = null; } new ManuallyTradeObservationPriceService(OptUser).RemoveManuallyTradeObservationPrice(trade.id); } var actionService = new TradeActionDataService(this); RemoveEodTradeAndFutureInfo(false, trade.id, valueDate, tradeCashIds, backToBegin: backToBegin); AddTradeOperationHistoryAndSetParentTradeInfo(false, trade,"交易回退"); var backAction = actionService.CreateTradeAction(tradeId, BLL.valuedateBLL.ValueDate, TradeActionType.BackTrade); DbContext.TradeAction.Add(backAction); DbContext.SaveChanges(); actionService.SetInvalid(x => x.IsValid && x.TradeId == trade.id, backAction.id); return trade; } public trade Execute(int tradeId, DateTime valueDate, bool ignoreBodTrade = false) { var trade = DbContext.trade.Find(tradeId); if (trade == null) { throw new ServiceException("交易数据不存在"); } new TradeExtendService(UserInfo, DbContext).SetTradeExtend(new[] { trade }, tracking: true); if (valueDate == trade.TradeDate) { Execute(tradeId, true, TradeBackActionEnum.backTrade); } else { var bodTrade = DbContext.bod_Trade.FirstOrDefault(x => x.TradeId == trade.id && x.ValueDate == valueDate); if (bodTrade != null) { if (trade.TradeType == "累计期权") { if (trade.trade_accumulator_option.SettlementMode == "实物交割" || trade.trade_accumulator_option.SettlementMode == "现金实物合并结算") { var query = from ob in DbContext.autocall_observation join tf in DbContext.trade on ob.ConvTradeNumber equals tf.TradeNumber where ob.TradeId == trade.id && (ob.SettlementMode == "转远期" || ob.SettlementMode == "转掉期" || ob.SettlementMode == "现金当日&转远期") && ob.PaymentDate >= valueDate && tf.ValidState != ConsGlobal.InValid select ob; if (query.Any()) { throw new ServiceException($"操作失败,当前累计期权交易({trade.TradeNumber})已结算为远期交易,请将所有结算后的远期交易删除后重新执行回退操作!"); } } } var ets = DbContext.ExtensionTime.Where(x => x.OptDate >= valueDate && x.IsValid).ToList(); if (ets.Any()) { var extensionTimeService = new ExtensionTimeService(UserInfo, DbContext); extensionTimeService.DelExtensionTime(trade.id, valueDate, false, true); } trade.ExerciseDate = bodTrade.trade.ExerciseDate; trade.SettlementDate = bodTrade.trade.SettlementDate; trade.SettlementFlag = bodTrade.trade.SettlementFlag; //延期结算 >= 到期日才会有,为了回退取镜像数据 if (trade.ExerciseDate > valueDate && trade.SettlementFlag == 1) { trade.SettlementFlag = 0; } trade.SpotPrice = bodTrade.trade.SpotPrice; trade.Strike = bodTrade.trade.Strike; trade.OriginalNotional = bodTrade.trade.OriginalNotional; trade.Notional = bodTrade.trade.Notional; trade.TradeAmount = bodTrade.trade.TradeAmount; trade.StockEqvNotional = bodTrade.trade.StockEqvNotional; trade.UnWindDate = bodTrade.trade.UnWindDate; trade.FinalPrice = bodTrade.trade.FinalPrice; trade.UnWindNotional = bodTrade.trade.UnWindNotional; trade.UnWindPrice = bodTrade.trade.UnWindPrice; trade.HasPartialUnWind = bodTrade.trade.HasPartialUnWind; trade.CheckStatus = bodTrade.trade.CheckStatus; trade.TradeStatus = bodTrade.trade.TradeStatus; trade.ProcessOrderId = bodTrade.trade.ProcessOrderId; trade.ProcessOptDate = bodTrade.trade.ProcessOptDate; trade.ProcessStatus = bodTrade.trade.ProcessStatus; trade.DividendDate = bodTrade.trade.DividendDate; trade.IsApproval = bodTrade.trade.IsApproval; trade.OptId = UserId; trade.OptName = UserName; trade.OptDate = DateTime.Now; if (trade.ParentTradeId > 0) { RemoveEodTradeAndFutureInfo(false, trade.ParentTradeId, valueDate, isDelTradeCashIncludeStartDay: true); } if (trade.TradeType == "障碍期权") { trade.trade_barrier_option.KnockInOutStatus = bodTrade.trade.trade_barrier_option.KnockInOutStatus; trade.trade_barrier_option.KnockInOutDate = bodTrade.trade.trade_barrier_option.KnockInOutDate; } else if (trade.TradeType == "二元期权") { trade.trade_binary_option.UpperBarrier = bodTrade.trade.trade_binary_option.UpperBarrier; } else if (trade.TradeType == "双鲨期权") { trade.trade_double_sharkfin_option.BarrierHigh = bodTrade.trade.trade_double_sharkfin_option.BarrierHigh; trade.trade_double_sharkfin_option.BarrierLow = bodTrade.trade.trade_double_sharkfin_option.BarrierLow; trade.trade_double_sharkfin_option.StrikeHigh = bodTrade.trade.trade_double_sharkfin_option.StrikeHigh; trade.trade_double_sharkfin_option.StrikeLow = bodTrade.trade.trade_double_sharkfin_option.StrikeLow; trade.trade_double_sharkfin_option.KnockInOutStatus = bodTrade.trade.trade_double_sharkfin_option.KnockInOutStatus; trade.trade_double_sharkfin_option.KnockInOutDate = bodTrade.trade.trade_double_sharkfin_option.KnockInOutDate; } else if (trade.TradeType == "凤凰期权") { trade.trade_autocall.CouponBarrier = bodTrade.trade.trade_autocall.CouponBarrier; trade.trade_autocall.KIBarrier = bodTrade.trade.trade_autocall.KIBarrier; trade.trade_autocall.KOBarrier = bodTrade.trade.trade_autocall.KOBarrier; trade.trade_autocall.SpreadStrike = bodTrade.trade.trade_autocall.SpreadStrike; trade.trade_autocall.SpreadStrike1 = bodTrade.trade.trade_autocall.SpreadStrike1; trade.trade_autocall.KnockInOutStatus = bodTrade.trade.trade_autocall.KnockInOutStatus; trade.trade_autocall.KnockInOutDate = bodTrade.trade.trade_autocall.KnockInOutDate; } else if (trade.TradeType == "雪球期权") { trade.trade_snowball.KIBarrier = bodTrade.trade.trade_snowball.KIBarrier; trade.trade_snowball.KOBarrier = bodTrade.trade.trade_snowball.KOBarrier; trade.trade_snowball.SpreadStrikeAtKO = bodTrade.trade.trade_snowball.SpreadStrikeAtKO; trade.trade_snowball.SpreadStrikeAtKO1 = bodTrade.trade.trade_snowball.SpreadStrikeAtKO1; trade.trade_snowball.SpreadStrikeAtMaturity = bodTrade.trade.trade_snowball.SpreadStrikeAtMaturity; trade.trade_snowball.SpreadStrikeAtMaturity1 = bodTrade.trade.trade_snowball.SpreadStrikeAtMaturity1; trade.trade_snowball.KnockInOutStatus = bodTrade.trade.trade_snowball.KnockInOutStatus; trade.trade_snowball.KnockInOutDate = bodTrade.trade.trade_snowball.KnockInOutDate; } else if (trade.TradeType == "气囊结构") { trade.trade_airbag.HighStrike = bodTrade.trade.trade_airbag.HighStrike; trade.trade_airbag.Barrier = bodTrade.trade.trade_airbag.Barrier; } else if (trade.TradeType == "区间累积期权") { trade.trade_rangeaccrual.UpperRange = bodTrade.trade.trade_rangeaccrual.UpperRange; trade.trade_rangeaccrual.LowerRange = bodTrade.trade.trade_rangeaccrual.LowerRange; } else if (trade.TradeType == "累计期权") { trade.trade_accumulator_option.KOBarrier = bodTrade.trade.trade_accumulator_option.KOBarrier; trade.trade_accumulator_option.KnockOutDate = bodTrade.trade.trade_accumulator_option.KnockOutDate; trade.trade_accumulator_option.OriginalAccumuTradeAmount = bodTrade.trade.trade_accumulator_option.OriginalAccumuTradeAmount; trade.trade_accumulator_option.AccumuTradeAmount = bodTrade.trade.trade_accumulator_option.AccumuTradeAmount; } else if (trade.TradeType == "收益互换") { trade.trade_swap.GetSpotPrice = bodTrade.trade.trade_swap.GetSpotPrice; trade.trade_swap.PaySpotPrice = bodTrade.trade.trade_swap.PaySpotPrice; trade.trade_swap.GetFinalPrice = bodTrade.trade.trade_swap.GetFinalPrice; trade.trade_swap.PayFinalPrice = bodTrade.trade.trade_swap.PayFinalPrice; } var removeAutoCallObservations = DbContext.autocall_observation.Where(x => x.TradeId == trade.id && x.EndDate >= valueDate); DbContext.autocall_observation.RemoveRange(removeAutoCallObservations); var autoCallObservations = DbContext.autocall_observation.Where(x => x.TradeId == trade.id && x.EndDate < valueDate && x.PaymentDate >= valueDate).ToList(); autoCallObservations.ForEach(x => x.PaymentDate = trade.ExerciseDate.Value); if (trade.TradeType == "累计期权") { //由于回退操作是回退到valueDate的开盘状态,而换月操作是valueDate的日中操作,所以这里应该取前一天的; var preValueDate = QdpCalendarHelper.GetNonHolidayDefore(valueDate.AddDays(-1)); new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(trade, preValueDate); } new ManuallyTradeObservationPriceService(OptUser).RemoveManuallyTradeObservationPrice(trade.id, valueDate); } else { //黑箱交易子交易有可能在回退日期之前就已经完全了结了,而其他子交易以及主交易,在回退日期之后还是存续状态,需要回退 if (ignoreBodTrade) { return trade; } var lastBodTrade = DbContext.bod_Trade.Where(x => x.TradeId == trade.id && x.ValueDate < valueDate).OrderByDescending(x => x.ValueDate).FirstOrDefault(); if (lastBodTrade == null) { throw new ServiceException($"未查询到该交易在{valueDate.ToString("yyyy-MM-dd")}之前的收盘数据,只能回退到开仓日"); } else { throw new ServiceException($"未查询到该交易在{valueDate.ToString("yyyy-MM-dd")}前一天的收盘数据,最近一次可以回退的日期为{lastBodTrade.ValueDate.ToString("yyyy-MM-dd")}"); } } } var actionService = new TradeActionDataService(this); using (var trans = DbContext.Database.BeginTransaction()) { RemoveEodTradeAndFutureInfo(false, trade.id, valueDate, isDelTradeCashIncludeStartDay: true); AddTradeOperationHistoryAndSetParentTradeInfo(false, trade, "交易回退"); var backAction = actionService.CreateTradeAction(tradeId, BLL.valuedateBLL.ValueDate, TradeActionType.BackTrade); DbContext.TradeAction.Add(backAction); DbContext.SaveChanges(); actionService.SetInvalid(x => x.IsValid && x.TradeId == trade.id, backAction.id); trans.Commit(); } return trade; } #region 分组回退 /// /// 回退分组交易用 /// /// /// /// public trade BackGroup(int tradeId, bool backToBegin, TradeBackActionEnum actionEnum) { var tradeIds = new List(); var tradeCashIds = new List(); var extensionTimeService = new ExtensionTimeService(UserInfo, DbContext); //主交易处理 var trade = DbContext.trade.Find(tradeId); var valueDate = trade.TradeDate.Value; tradeIds.Add(tradeId); tradeCashIds.AddRange(BackGroupItem(tradeId, backToBegin, valueDate)); var tradeCashGrouActions = DbContext.trade_cash_group_action.Where(x => tradeCashIds.Contains(x.ParentTradeCashId)); DbContext.trade_cash_group_action.RemoveRange(tradeCashGrouActions); //DbContext.SaveChanges(); //子交易处理 if (backToBegin) { var tradeChildren = DbContext.trade.Where(x => x.ParentTradeId == tradeId).ToList(); tradeIds.AddRange(tradeChildren.Select(x => x.id).ToList()); foreach (var tradeChild in tradeChildren) { tradeCashIds.AddRange(BackGroupItem(tradeChild.id, backToBegin, valueDate)); } } else { var tradeCashId = tradeCashIds.FirstOrDefault(); var tradeCashChildren = DbContext.trade_cash.Where(x => x.ParentTradeCashId == tradeCashId).ToList(); var tradeCash = tradeCashChildren.FirstOrDefault(); if (tradeCash != null) { var et = extensionTimeService.QueryExtensionTimeList(tradeId).Where(O => O.OptDate > tradeCash.ValueDate).OrderByDescending(O => O.OptDate).FirstOrDefault(); if (et != null) { extensionTimeService.DelExtensionTime(et.TradeId, et.id); return trade; } } foreach (var tradeCashChild in tradeCashChildren) { tradeCashIds.AddRange(BackGroupChildItemByStep(tradeCashChild.TradeId, tradeCashChild.id, valueDate)); tradeIds.AddRange(tradeCashChildren.Select(x => x.TradeId)); } } extensionTimeService.DelExtensionTime(tradeId, DateTime.MinValue, actionEnum != TradeBackActionEnum.EditMaturityDate); RemoveGroupEodTradeAndFutureInfo(tradeIds, valueDate, tradeCashIds); DbContext.SaveChanges(); return trade; } private List BackGroupItem(int tradeId, bool backToBegin, DateTime valueDate) { var trade = DbContext.trade.Find(tradeId); var tradeCashIds = new List(); var actions = new List() { "系统操作-行权费", "系统操作-平仓费", "系统操作-票息", "系统操作-互换" }; var tcQuery = DbContext.trade_cash.Where(x => x.TradeId == tradeId && actions.Contains(x.Action) && x.ValidState != "InValid" && !x.IsDeleted); var eodTrade = DbContext.eod_trade.Where(O => O.TradeId == tradeId && O.ValueDate == trade.TradeDate).FirstOrDefault(); var originTrade = eodTrade?.trade; if (originTrade == null) { originTrade = trade; } if (backToBegin) { var tcTemp = DbContext.trade_cash.Where(x => x.TradeId == tradeId && x.Action == "系统操作-期权费" && x.ValidState != ConsGlobal.InValid && !x.IsDeleted).FirstOrDefault(); if (tcTemp == null) { throw new ServiceException("未查询到该交易的开仓记录,请删除该笔交易重新操作"); } originTrade.TradeStatus = ConsTrade.确认成交; originTrade.OriginalNotional = tcTemp.Notional; originTrade.Notional = tcTemp.Notional; originTrade.StockEqvNotional = originTrade.OriginalStockEqvNotional ?? 0; DividendService.SetDividendTradeData(trade, originTrade); valueDate = trade.TradeDate.Value; tradeCashIds.AddRange(tcQuery.Select(O => O.id).ToList()); trade.UnWindDate = null; trade.FinalPrice = null; trade.UnWindNotional = null; trade.UnWindPrice = null; trade.HasPartialUnWind = null; } else { if (!tcQuery.Any()) { throw new ServiceException("未查询到该交易的了结记录,不可回退"); } //有行权记录先回撤行权记录,没有行权记录,依次倒序撤回平仓记录 var tradeCash = tcQuery.OrderByDescending(x => x.id).FirstOrDefault(); trade.Notional = tradeCash.Notional; if (trade.TradeType == "现金流交易") { if (tradeCash.UnwindType == "全部平仓") { trade.StockEqvNotional = tradeCash.Notional; } else { trade.StockEqvNotional = trade.StockEqvNotional + tradeCash.UnwindNotional.Value; } } else { if (trade.IsUsePremiumRate == true) { //后期将会将所有已了结的交易均处理为0 if (ConsTrade.TradeCompleteStatus.Contains(trade.TradeStatus)) { trade.StockEqvNotional = 0; } trade.StockEqvNotional += trade.OriginalStockEqvNotional * tradeCash.UnwindPercentRate ?? 0; } else { if (trade.TradeType == "远期" && PS.Config.ErpElement.ForwardTradePriceModel == 0 && !string.IsNullOrWhiteSpace(trade.BasisUnderlyingCode)) { trade.StockEqvNotional += TradeHelper.GetStockEqvNotional(tradeCash.UnwindNotional / trade.OriginalNotional * trade.OriginalStockEqvNotional, trade.ParticipationRate, trade.AnnualizeFactor); } else { trade.StockEqvNotional = TradeHelper.GetStockEqvNotional(trade.Notional * trade.SpotPrice, trade.ParticipationRate, trade.AnnualizeFactor); } } } valueDate = tradeCash.ValueDate; tradeCashIds.Add(tradeCash.id); //分步回退时将倒数第二条平仓记录赋值给trade var lastSecondTradeCash = tcQuery.Where(x => x.id != tradeCash.id).OrderByDescending(x => x.id).FirstOrDefault(); if (lastSecondTradeCash != null && lastSecondTradeCash.Action == "系统操作-平仓费") { trade.UnWindDate = lastSecondTradeCash.ValueDate; trade.FinalPrice = lastSecondTradeCash.FinalPrice; trade.UnWindNotional = lastSecondTradeCash.UnwindNotional; trade.UnWindPrice = lastSecondTradeCash.UnwindPrice; trade.HasPartialUnWind = 1; } else { trade.UnWindDate = null; trade.FinalPrice = null; trade.UnWindNotional = null; trade.UnWindPrice = null; trade.HasPartialUnWind = null; } } trade.TradeAmount = trade.Notional; var varietyList = VarietyBLL.GetAllvarietyModel(); if (!string.IsNullOrWhiteSpace(trade.UnderlyingAssetClass)) { var variety = varietyList.FirstOrDefault(O => O.VarietyName == trade.UnderlyingAssetClass); if (variety != null) { trade.TradeUnit = variety.TradeUnit; trade.TradeAmount /= variety.CountRatio; } } trade.CheckStatus = null; trade.OptId = UserId; trade.OptName = UserName; trade.OptDate = DateTime.Now; trade.TradeStatus = ConsTrade.确认成交; trade.ProcessOrderId = 0; trade.ProcessOptDate = null; trade.ProcessStatus = null; trade.DividendDate = new DateTime(2000, 1, 1); if (backToBegin && (trade.TradeType == "障碍期权" || trade.StructureType == "障碍期权")) { var trade_barrier_option = DbContext.trade_barrier_option.Where(x => x.TradeId == trade.id).FirstOrDefault(); trade_barrier_option.KnockInOutStatus = null; trade_barrier_option.KnockInOutDate = null; } if (backToBegin && (trade.TradeType == "双鲨期权" || trade.StructureType == "双鲨期权")) { var trade_double_sharkfin_option = DbContext.trade_double_sharkfin_option.Where(x => x.TradeId == trade.id).FirstOrDefault(); trade_double_sharkfin_option.KnockInOutStatus = null; trade_double_sharkfin_option.KnockInOutDate = null; } if (backToBegin && (trade.TradeType == "凤凰期权" || trade.StructureType == "凤凰期权")) { var trade_autocall = DbContext.trade_autocall.Where(x => x.TradeId == trade.id).FirstOrDefault(); trade_autocall.KnockInOutStatus = null; trade_autocall.KnockInOutDate = null; var autoCallObservations = DbContext.autocall_observation.Where(x => x.TradeId == trade.id); DbContext.autocall_observation.RemoveRange(autoCallObservations); } if (backToBegin && (trade.TradeType == "雪球期权" || trade.StructureType == "雪球期权")) { var trade_snowball = DbContext.trade_snowball.Where(x => x.TradeId == trade.id).FirstOrDefault(); trade_snowball.KnockInOutStatus = null; trade_snowball.KnockInOutDate = null; } if (backToBegin && (trade.TradeType == "区间累积期权" || trade.StructureType == "区间累积期权")) { var autoCallObservations = DbContext.autocall_observation.Where(x => x.TradeId == trade.id); DbContext.autocall_observation.RemoveRange(autoCallObservations); } if (backToBegin && (trade.TradeType == "收益互换" || trade.StructureType == "收益互换")) { var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == trade.id); trade_swap.GetFinalPrice = null; trade_swap.PayFinalPrice = null; var trade_swap_details = DbContext.trade_swap_detail.Where(x => x.TradeId == trade.id).ToList(); trade_swap_details.ForEach(x => { x.Notional = x.OriginalNotional; x.SwapDate = null; x.FinalPrice = null; }); } if (backToBegin) { new ManuallyTradeObservationPriceService(OptUser).RemoveManuallyTradeObservationPrice(trade.id); } DateTime mindate = trade.TradeDate ?? DateTime.MinValue; var delTCArr = DbContext.trade_cash.Where(O => tradeCashIds.Contains(O.id)); if (delTCArr.Any()) { delTCArr.ToList().ForEach(O => { O.ValidState = "InValid"; O.Status = TradeCashStatusEnum.已执行; O.OptDate = DateTime.Now; O.IsDeleted = true; }); mindate = delTCArr.Min(O => (DateTime?)O.ValueDate).GetValueOrDefault(); } var trList = DbContext.trade_contract_r.Where(O => O.TradeId == tradeId && O.Type == "交易确认书").ToList(); foreach (var item in trList) { string infoTag = "_" + item.ContractCode.Replace("_", "-") + "_" + "了结_"; var notes = DbContext.sac_report_notes.Where(x => x.IsValid && x.InfoTag.Contains(infoTag) && x.ReportDate >= mindate).ToList(); foreach (var note in notes) { note.changeStatus = true; } } AddTradeOperationHistoryAndSetParentTradeInfo(false, trade, "交易回退"); DbContext.SaveChanges(); return tradeCashIds; } private List BackGroupChildItemByStep(int tradeId, int tradeCashId, DateTime valueDate) { var trade = DbContext.trade.Find(tradeId); var tradeCashIds = new List(); var actions = new List() { "系统操作-行权费", "系统操作-平仓费", "系统操作-票息", "系统操作-互换" }; var tradeCash = DbContext.trade_cash.Find(tradeCashId); var eodTrade = DbContext.eod_trade.Where(O => O.TradeId == tradeId && O.ValueDate == trade.TradeDate).FirstOrDefault(); var originTrade = eodTrade?.trade; if (originTrade == null) { originTrade = trade; } if (tradeCash == null) { throw new ServiceException("未查询到该交易的了结记录,不可回退"); } trade.Notional = tradeCash.Notional; if (trade.TradeType == "现金流交易") { if (tradeCash.UnwindType == "全部平仓") { trade.StockEqvNotional = tradeCash.Notional; } else { trade.StockEqvNotional = trade.StockEqvNotional + tradeCash.UnwindNotional.Value; } } else { if (trade.TradeType == "远期" && PS.Config.ErpElement.ForwardTradePriceModel == 0 && !string.IsNullOrWhiteSpace(trade.BasisUnderlyingCode)) { trade.StockEqvNotional += TradeHelper.GetStockEqvNotional(tradeCash.UnwindNotional / trade.OriginalNotional * trade.OriginalStockEqvNotional, trade.ParticipationRate, trade.AnnualizeFactor); } else { trade.StockEqvNotional = TradeHelper.GetStockEqvNotional(trade.Notional * trade.SpotPrice, trade.ParticipationRate, trade.AnnualizeFactor); } } valueDate = tradeCash.ValueDate; tradeCashIds.Add(tradeCash.id); //分步回退时将倒数第二条平仓记录赋值给trade var lastSecondTradeCash = DbContext.trade_cash.Where(x => x.TradeId == tradeId && x.id != tradeCash.id && x.ValidState != "InValid" && !x.IsDeleted).OrderByDescending(x => x.id).FirstOrDefault(); if (lastSecondTradeCash != null && lastSecondTradeCash.Action == "系统操作-平仓费") { trade.UnWindDate = lastSecondTradeCash.ValueDate; trade.FinalPrice = lastSecondTradeCash.FinalPrice; trade.UnWindNotional = lastSecondTradeCash.UnwindNotional; trade.UnWindPrice = lastSecondTradeCash.UnwindPrice; trade.HasPartialUnWind = 1; } else { trade.UnWindDate = null; trade.FinalPrice = null; trade.UnWindNotional = null; trade.UnWindPrice = null; trade.HasPartialUnWind = null; } trade.TradeAmount = trade.Notional; var varietyList = VarietyBLL.GetAllvarietyModel(); if (!string.IsNullOrWhiteSpace(trade.UnderlyingAssetClass)) { var variety = varietyList.FirstOrDefault(O => O.VarietyName == trade.UnderlyingAssetClass); if (variety != null) { trade.TradeUnit = variety.TradeUnit; trade.TradeAmount /= variety.CountRatio; } } trade.CheckStatus = null; trade.OptId = UserId; trade.OptName = UserName; trade.OptDate = DateTime.Now; trade.TradeStatus = ConsTrade.确认成交; trade.ProcessOrderId = 0; trade.ProcessOptDate = null; trade.ProcessStatus = null; trade.DividendDate = new DateTime(2000, 1, 1); DateTime mindate = trade.TradeDate ?? DateTime.MinValue; var delTCArr = DbContext.trade_cash.Where(O => tradeCashIds.Contains(O.id)); if (delTCArr.Any()) { delTCArr.ToList().ForEach(O => { O.ValidState = "InValid"; O.Status = TradeCashStatusEnum.已执行; O.OptDate = DateTime.Now; O.IsDeleted = true; }); mindate = delTCArr.Min(O => (DateTime?)O.ValueDate).GetValueOrDefault(); } var trList = DbContext.trade_contract_r.Where(O => O.TradeId == tradeId && O.Type == "交易确认书").ToArray(); foreach (var item in trList) { string infoTag = "_" + item.ContractCode.Replace("_", "-") + "_" + "了结_"; var notes = (from note in DbContext.sac_report_notes where note.IsValid && note.InfoTag.Contains(infoTag) && note.ReportDate >= mindate select note); foreach (var note in notes) { note.changeStatus = true; } } AddTradeOperationHistoryAndSetParentTradeInfo(false, trade, "交易回退"); DbContext.SaveChanges(); return tradeCashIds; } #endregion } public enum TradeBackActionEnum { backTrade, backTradeStepped, EditMaturityDate } }