using Microsoft.EntityFrameworkCore; using System.Text; using YLErp.BLL; using YLErp.BLL.Calculation.V2; using YLErp.BLL.Eod; using YLErp.BLL.EodSettlement; using YLErp.Commons; using YLErp.DBModels.Consts; using YLErp.DBModels.Enums; using YLErp.DBModels.Helpers; using YLErp.Modules.ClientModule; using YLErp.Modules.DataProviderModule; using YLErp.QdpModule; namespace YLErp.Modules.TradeModule.DealModule { /// /// 将单个交易标记为到期(并增加一条收益为零的trade_cash记录,直接到期的交易记录期末价格为0) /// public class TradeExpireConfirmService : TradeServiceBase { public TradeExpireConfirmService(OptUserInfo userInfo) : base(userInfo) { } public TradeExpireConfirmService(YLBaseService baseService) : base(baseService) { } public TradeExpireConfirmResult TradeExpireConfirm(int tradeId, double spotPrice = 0) { var td = DbContext.trade.Find(tradeId); var error = checkCanTradeExpire(td); //如果有配对交易,配对交易也要到期 if (!string.IsNullOrEmpty(td.PairTrade)) { var pairid = Convert.ToInt32(td.PairTrade); var pairtd = DbContext.trade.Find(pairid); if (pairtd.TradeStatus == ConsTrade.已到期) { //执行单笔已到期 } else { var error2 = checkCanTradeExpire(pairtd); if (string.IsNullOrEmpty(error) && string.IsNullOrEmpty(error2)) { //2个交易都可以到到期才到期 tradeExpireInner(td, spotPrice); tradeExpireInner(pairtd, spotPrice); //生成文档 if (PS.Config.IsAutoGenerateContracts) { new TradeContractGenerateService(this).GenerateContractsAsync(new List { td.id, pairid }); } AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "过期交易到期"); AddTradeOperationHistoryAndSetParentTradeInfo(false, pairtd, "过期交易到期"); DbContext.SaveChanges(); return new TradeExpireConfirmResult(td) { Success = true, Message = $"确认到期成功,且配对交易{pairtd.TradeNumber}也到期成功" }; } return new TradeExpireConfirmResult(td) { Success = false, Message = error + error2 }; } } //无匹配交易 if (string.IsNullOrEmpty(error)) { tradeExpireInner(td, spotPrice); //生成文档 if (PS.Config.IsAutoGenerateContracts) { new TradeContractGenerateService(this).GenerateContractsAsync(new List { td.id }); } SaveTradeOperationHistory(td, "过期交易到期"); return new TradeExpireConfirmResult(td) { Success = true, Message = "确认到期成功" }; } return new TradeExpireConfirmResult(td) { Success = false, Message = error }; } /// /// 检查交易是否可以到期,返回错误信息,空为成功 /// private string checkCanTradeExpire(trade td) { if (PS.Config.TradeElement.ExecuteAfterGeneratedConfirmDoc && !td.HasGeneratedConfirmBook() && td.TradeType != "自定义交易") { return "请先去生成交易确认书"; } var valueDate = valuedateBLL.ValueDate; if (td.TradeStatus == ConsTrade.确认成交 && ((td.ExerciseMode == "European" && td.ExerciseDate <= valueDate) || (td.ExerciseMode == "American" && valueDate >= td.StartDate) || string.IsNullOrEmpty(td.ExerciseMode))) { return string.Empty; } return $"确认到期失败,交易必须为[确认成交]状态并且[欧式期权]必须到期日{td.ExerciseDate}之后,美式期权必须在开始日{td.StartDate}之后"; } /// /// 执行到期 /// private void tradeExpireInner(trade td, double spotPrice = 0) { //到期日期如果是节假日,取节假日后的第一个工作日 var exerciseDate = QdpCalendarHelper.GetNonHoliday(td.ExerciseDate ?? valuedateBLL.ValueDate); var valueDate = valuedateBLL.ValueDate; td.TradeStatus = ConsTrade.已到期; td.UnWindDate = exerciseDate; td.OptDate = DateTime.Now; // 直接到期的交易设置 var tc = DbContext.trade_cash.FirstOrDefault(t => t.TradeId == td.id && t.Action == ClientCashInCashOut.系统操作_行权费 && !t.IsDeleted); if (tc == null) { tc = new trade_cash(); DbContext.trade_cash.Add(tc); } #region 设置期末价格和执行价格 var finalPrice = EodPriceQueryService.TryGetEodPrice(exerciseDate, td.UnderlyingCode, out var eodPrice) ? eodPrice.GetPrice(td.SettlementType) : 0; if (finalPrice <= 0) { throw new Exception("标的收盘价不合法,请检查后再进行到期操作"); } SettlementCalcCommons.SetPossibleExec(tc, td, finalPrice, true); if (td.TradeType != "亚式期权") { tc.FinalPrice = finalPrice; tc.Strike = td.Strike; } else { tc.SpotPrice = spotPrice; } //修改只收买方行权费 tc.ExtraAmount = Math.Abs(td.StockEqvNotional * (valuedateBLL.SystemDate.ExerciseCostRatioReal ?? 0)) * ("卖出".Equals(td.BuySell) ? 1 : 0); tc.Amount += tc.ExtraAmount ?? 0; #endregion tc.ValidState = "Valid"; tc.OptId = UserId; tc.OptName = UserName; tc.OptDate = DateTime.Now; tc.Action = ClientCashInCashOut.系统操作_行权费; tc.IsLastAction = true; tc.ValueDate = exerciseDate; tc.Notional = td.Notional; var CountRatio = UnderlyingDataProvider.GetCountRatio(td.UnderlyingCode); tc.TradeAmount = tc.Notional / CountRatio; tc.Status = TradeCashStatusEnum.已执行; tc.TradeType = td.BuySell; tc.TradeId = td.id; tc.ParentTradeId = td.ParentTradeId; tc.ExerciseWay = TradeCashExerciseWayEnum.到期行权; tc.UnwindVol = 0;//到期交易不需要存平仓波动率 DbContext.SaveChanges(); if (tc.IsPossibleExec) { new TradeCashService(this).SaveTradeCashDetail(tc); //增加出入金记录 var cl = DataCacheProvider.GetClientDataSource().GetData(td.ClientId); var ee = new ClientCashInCashOut { Direction = "应收", Number = UniqueTimeId.GetStr(), ClientId = cl.id, ClientNumber = cl.Number, ClientName = cl.Name, //客户和交易员反方向 Money = tc.Amount * -1, HappenDate = tc.ValueDate, State = ClientCashInCashOut.已确认, //ee.OpenBankId = bc.id + ""; //ee.OpenBankCard = bc.Card; TradeId = tc.TradeId, TradeCashId = tc.id, OptId = tc.OptId, OptName = tc.OptName, OptDate = tc.OptDate, CreatorId = tc.OptId, CreatorName = tc.OptName, CreateDate = tc.OptDate, Action = ClientCashInCashOut.系统操作_行权费, TradeNumber = td.TradeNumber, IsGroup = td.IsGroup }; DbContext.ClientCashInCashOut.Add(ee); td.TradeStatus = ConsTrade.已执行; } //结构化子交易到期行权时,检查另外一个兄弟子交易是否已了结,如果已了结,则主交易状态也跟着当前子交易状态变化 if (td.ParentTradeId > 0) { var otherTrade = DbContext.trade.Where(x => x.ParentTradeId == td.ParentTradeId && x.id != td.id); if (otherTrade.All(n => ConsTrade.TradeCompleteStatus.Contains(n.TradeStatus))) { var parentTrade = DbContext.trade.Find(td.ParentTradeId); parentTrade.TradeStatus = td.TradeStatus; parentTrade.UnWindDate = td.UnWindDate; } } //删除E/Bod数据 RemoveEodTradeAndFutureInfo(false, td.id, tc.ValueDate); DbContext.SaveChanges(); } /// /// 将多个交易标记为到期 /// public void MultipleTradeExpireConfirm(IEnumerable tradeIds, out string successMsg) { var valueDate = valuedateBLL.ValueDate; successMsg = "执行到期成功:"; //批量行权到期 获取所有交易到期日小于当前系统日期非通道交易 var buySellList = new List { "卖出", "买入" }; //所有应行权到期的通道自营交易(如果前一天是假日,要显示包含假日的交易) var preday = QdpCalendarHelper.GetNonHolidayDefore(valueDate.AddDays(-1)); var dateEnd = valueDate.AddDays(1); IQueryable tradeQuery = DbContext.trade; if (tradeIds != null && tradeIds.Any(n => n > 0)) { var selectParentTradeIds = DbContext.trade.Where(t => tradeIds.Contains(t.id) && t.ParentTradeId != 0).Select(x => x.ParentTradeId).ToHashSet().ToArray(); tradeQuery = DbContext.trade.Where(t => tradeIds.Contains(t.id) || tradeIds.Contains(t.ParentTradeId) || selectParentTradeIds.Contains(t.ParentTradeId)); } tradeQuery = tradeQuery.Where(t => t.ClientId > 0 && t.ExerciseDate > preday && t.ExerciseDate < dateEnd && t.TradeStatus == ConsTrade.确认成交 && t.ValidState != "InValid" && t.ClientId > 0 && t.TradeNumber != null && !ConsTrade.NonOptionTradeTypes.Contains(t.TradeType) && t.TradeType != "自定义交易"); var needKnockInTradeIds = tradeQuery.Where(t => t.TradeType == "雪球期权" || t.TradeType == "凤凰期权").Select(x => x.id).ToList(); var unKnockInTradeIds = DbContext.trade_autocall.Where(x => needKnockInTradeIds.Contains(x.TradeId) && x.KnockInOutStatus != ConsTrade.KnockState.KnockedIn).Select(x => x.TradeId).Union(DbContext.trade_snowball.Where(x => needKnockInTradeIds.Contains(x.TradeId) && x.KnockInOutStatus != "KnockedIn").Select(x => x.TradeId)).ToList(); tradeQuery = tradeQuery.Where(x => !unKnockInTradeIds.Contains(x.id)); var tradeUnwindTrades = tradeQuery.ToList(); if (!tradeUnwindTrades.Any()) { throw new ServiceException($"不存在可批量执行到期的交易,或者勾选的交易不可被批量执行到期"); } var tradeCashList = new List(); var clientCashList = new List(); trade_cash tradeCash = null; //日终价格 var underlyingIds = tradeUnwindTrades.Select(t => t.UnderlyingId).ToList(); var EodPriceProvider = new EodPriceProvider(valueDate); //批量结算的全是现金流交易就不用结算价 if (!EodPriceQueryService.CheckDbExists(valueDate) && tradeQuery.Any(t => t.TradeType != "现金流交易")) { throw new ServiceException($"当日交易的结算价或收盘价未找到!"); } var sbMsg = new StringBuilder().AppendLine(successMsg); var parentTradeIds = new List(); foreach (var t in tradeUnwindTrades) { if (t.ParentTradeId > 0 && t.IsGroup == 0) { parentTradeIds.Add(t.ParentTradeId); } if (PS.Config.TradeElement.ExecuteAfterGeneratedConfirmDoc && !t.HasGeneratedConfirmBook() && t.TradeType != "远期" && t.TradeType != "现金流交易") { throw new ServiceException($"交易{t.TradeNumber}的交易确认书没有生成。"); } double settlePrice = 0; var CountRatio = 1; if (t.TradeType != "现金流交易") { //结算价 if (EodPriceProvider.TryGetEodPrice(t.UnderlyingCode, out var eodPrice)) { settlePrice = eodPrice.GetPrice(t.SettlementType); } else { throw new ServiceException($"交易{t.TradeNumber},标的[{t.UnderlyingCode}]{valueDate}结算价或收盘价或参考价不存在!"); } CountRatio = UnderlyingDataProvider.GetCountRatio(t.UnderlyingCode); } var client = ClientDataQueryService.GetClient(t.ClientId); if (client == null) { throw new ServiceException($"交易{t.TradeNumber}的客户{t.ClientName}在系统中不存在!请检查数据后再操作。"); } if (t.TradeType == "收益互换") { //t.trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == t.id); //if(t.trade_swap == null) //{ // throw new ServiceException($"交易{t.TradeNumber}对应的trade_swap数据不存在!"); //} //var unwindPercentRate = t.OriginalNotional > 0 ? t.Notional / t.OriginalNotional : 0; //var initialAmount = t.SpotPrice > 0 ? (settlePrice / (t.FinalPrice ?? t.SpotPrice) - 1) * (t.OriginalStockEqvNotional * (t.FinalPrice ?? t.SpotPrice) / t.SpotPrice) * unwindPercentRate * (t.BuySell == "买入" ? 1 : -1) * (t.OptionType == "看涨" ? 1 : -1) : 0; //int days = (valueDate - (t.UnWindDate ?? t.StartDate.Value)).Days; //var extraAmount = t.OriginalStockEqvNotional * unwindPercentRate * t.trade_swap.GetSwapRate * ((double)days / t.trade_swap.AnnualDays) * (t.BuySell == "买入" ? -1 : 1); //var amount = (initialAmount ?? 0) + (extraAmount ?? 0); //tradeCash = new trade_cash //{ // ValueDate = valueDate, // TradeId = t.id, // ExceciseType = "到期行权", // CallPut = t.CallPut, // Notional = t.Notional, // UnwindNotional = t.Notional, // TradeAmount = t.Notional / CountRatio, // UnwindPercentRate = unwindPercentRate, // NotionalPercentRate = unwindPercentRate, // FinalPrice = settlePrice.Value, // Amount = amount, // ExtraAmount = extraAmount, // Action = ClientCashInCashOut.系统操作_互换, // Status = TradeCashStatusEnum.已执行, // OptId = UserId, // OptName = UserName, // OptDate = DateTime.Now, // ExerciseWay = TradeCashExerciseWayEnum.到期行权 //}; //tradeCashList.Add(tradeCash); //clientCashList.Add(new ClientCashInCashOut //{ // Direction = "应收", // Number = UniqueTimeId.GetStr(), // ClientId = client.id, // ClientNumber = client.Number, // ClientName = client.Name, // ClientIdentityNumber = client.IdentificationNumber, // //客户和交易员反方向 // Money = amount * -1, // HappenDate = valueDate == DateTime.Now.Date ? DateTime.Now : valueDate, // State = ClientCashInCashOut.已确认, // TradeId = tradeCash.TradeId, // OptId = tradeCash.OptId, // OptName = tradeCash.OptName, // OptDate = tradeCash.OptDate, // Action = ClientCashInCashOut.系统操作_互换, // TradeNumber = t.TradeNumber //}); //t.TradeStatus = ConsTrade.已到期; //t.UnWindDate = valueDate; //t.FinalPrice = settlePrice; } else { var parentTradeCash = DbContext.trade_cash.OrderByDescending(x => x.id).FirstOrDefault(x => x.TradeId == t.ParentTradeId && x.Action != "系统操作-期权费" && x.Status == null && x.ValidState != "InValid"); var parentTrade = DbContext.trade.Find(t.ParentTradeId); if (t.IsGroup == 2) { //主交易和子交易都是当天到期 if (parentTrade.ExerciseDate > preday && parentTrade.ExerciseDate < dateEnd) { if (parentTradeCash == null) { parentTradeCash = new trade_cash() { Action = ClientCashInCashOut.系统操作_行权费, ExerciseWay = "到期行权", IsLastAction = true, TradeType = parentTrade.BuySell, Notional = parentTrade.Notional, TradeAmount = parentTrade.TradeAmount, UnwindNotional = parentTrade.Notional, UnwindTradeAmount = parentTrade.TradeAmount, UnwindPercentRate = parentTrade.OriginalNotional > 0 ? parentTrade.Notional / parentTrade.OriginalNotional : 0, TradeId = t.ParentTradeId, HappenedDate = valueDate, ValueDate = valueDate, OptId = UserId, OptName = UserName, OptDate = DateTime.Now }; parentTrade.TradeStatus = "已到期"; parentTrade.UnWindDate = valueDate; parentTrade.FinalPrice = settlePrice; parentTrade.UnWindNotional = parentTrade.Notional; parentTrade.Notional = 0; parentTrade.TradeAmount = 0; parentTrade.StockEqvNotional = 0; DbContext.trade_cash.Add(parentTradeCash); DbContext.SaveChanges(); #region---存入ClientCashInCashOut--- var cl = ClientDataQueryService.GetClient(parentTrade.ClientId, true); var ee = new ClientCashInCashOut { Direction = "应收", Number = UniqueTimeId.GetStr(), ClientId = cl.id, ClientNumber = cl.Number, ClientName = cl.Name, HappenDate = parentTradeCash.ValueDate, State = ClientCashInCashOut.已确认, OptId = parentTradeCash.OptId, OptName = parentTradeCash.OptName, OptDate = parentTradeCash.OptDate, CreatorId = parentTradeCash.OptId, CreatorName = parentTradeCash.OptName, CreateDate = parentTradeCash.OptDate, TradeId = parentTradeCash.TradeId, TradeCashId = parentTradeCash.id, Action = parentTradeCash.Action, TradeNumber = parentTrade.TradeNumber, IsGroup = parentTrade.IsGroup }; DbContext.ClientCashInCashOut.Add(ee); #endregion } } else { if (parentTradeCash == null) { //主交易非当日到期 parentTrade.UnWindDate = valueDate; parentTrade.FinalPrice = settlePrice; var childrenExerciseDateCount = DbContext.trade.Where(x => x.ParentTradeId == parentTrade.id && x.ValidState != "InValid").Select(x => x.ExerciseDate).Distinct().Count(); parentTrade.UnWindNotional = 1.0 / childrenExerciseDateCount * parentTrade.OriginalNotional; parentTradeCash = new trade_cash() { Action = ClientCashInCashOut.系统操作_平仓费, ExerciseWay = "提前终止行权", IsLastAction = false, TradeType = parentTrade.BuySell, Notional = parentTrade.Notional, TradeAmount = parentTrade.TradeAmount, UnwindNotional = parentTrade.UnWindNotional, UnwindTradeAmount = parentTrade.UnWindNotional / (parentTrade.CountRatio ?? 1), UnwindPercentRate = parentTrade.OriginalNotional > 0 ? parentTrade.UnWindNotional / parentTrade.OriginalNotional : 0, TradeId = t.ParentTradeId, HappenedDate = valueDate, ValueDate = valueDate, OptId = UserId, OptName = UserName, OptDate = DateTime.Now }; parentTrade.Notional -= (parentTradeCash.UnwindNotional ?? 0); parentTrade.TradeAmount -= (parentTradeCash.UnwindTradeAmount ?? 0); parentTrade.StockEqvNotional -= ((parentTrade.OriginalStockEqvNotional ?? 0) * (parentTradeCash.UnwindPercentRate ?? 0)); DbContext.trade_cash.Add(parentTradeCash); DbContext.SaveChanges(); #region---存入ClientCashInCashOut--- var cl = ClientDataQueryService.GetClient(parentTrade.ClientId, true); var ee = new ClientCashInCashOut { Direction = "应收", Number = UniqueTimeId.GetStr(), ClientId = cl.id, ClientNumber = cl.Number, ClientName = cl.Name, HappenDate = parentTradeCash.ValueDate, State = ClientCashInCashOut.已确认, OptId = parentTradeCash.OptId, OptName = parentTradeCash.OptName, OptDate = parentTradeCash.OptDate, CreatorId = parentTradeCash.OptId, CreatorName = parentTradeCash.OptName, CreateDate = parentTradeCash.OptDate, TradeId = parentTradeCash.TradeId, TradeCashId = parentTradeCash.id, Action = parentTradeCash.Action, TradeNumber = parentTrade.TradeNumber, IsGroup = parentTrade.IsGroup }; DbContext.ClientCashInCashOut.Add(ee); #endregion } } var tradeCashGroupAction = new trade_cash_group_action() { TradeId = t.id, ParentTradeId = t.ParentTradeId, ParentTradeCashId = parentTradeCash.id, Status = "已完成", OptId = UserId, OptName = UserName, OptDate = DateTime.Now, IsFinishedUnwindPercent = true }; DbContext.trade_cash_group_action.Add(tradeCashGroupAction); } tradeCash = new trade_cash { ValueDate = valueDate, TradeId = t.id, ParentTradeId = t.ParentTradeId, ExceciseType = "现金", CallPut = t.CallPut, Strike = t.IsMoneynessOptionData ? (t.Strike * t.SpotPrice) : t.Strike, Notional = t.Notional, UnwindNotional = t.Notional, UnwindPercentRate = t.OriginalNotional > 0 ? t.Notional / t.OriginalNotional : 0, FinalPrice = settlePrice, Action = ClientCashInCashOut.系统操作_行权费, IsLastAction = true, Status = TradeCashStatusEnum.已执行, OptId = UserId, OptName = UserName, OptDate = DateTime.Now, ExerciseWay = TradeCashExerciseWayEnum.到期行权, TradeType = t.BuySell }; tradeCash.SpotPrice = DataCacheProvider.GetUnderlyingDataSource().GetPrice(t.UnderlyingCode); tradeCash.TradeAmount = tradeCash.Notional / CountRatio; //计算行权收益 SettlementCalcCommons.SetPossibleExec(tradeCash, t, tradeCash.FinalPrice ?? 0.0, true); if (t.TradeType == "现金流交易") { var udm = new underlying_manager { QuotationDate = valueDate }; var OptionValue = ValueCalculator.GetOptionValueResultV2( userId: OptUser.UserId.ToString(), underlying: udm, trade: t, vols: new double[] { t.StockEqvNotional }, spotPrices: new double[] { udm.Price ?? 0.0 }, fixing: null, timeToMaturityDays: 0, preciseTimeMode: true, request: QdpPricingRequest.BASIC_PRICING); var amount = OptionValue.Pv; tradeCash.IsPossibleExec = true; tradeCash.Amount = OtcFormatHelper.FormatValue(amount, 2); tradeCash.InitialAmount = OtcFormatHelper.FormatValue(amount, 2); } //额外的行权费 //根据买卖方向 针对买方才会收行权费 var ExtraAmount = Math.Abs(t.StockEqvNotional * (valuedateBLL.SystemDate.ExerciseCostRatioReal ?? 0)) * ("卖出".Equals(t.BuySell) ? 1 : 0); //行权净收益 var Amount = tradeCash.Amount + ExtraAmount; //判断客户行权如果收益小于0 则行权收益为0 则不可行权 var flag = true; if (EodOperationBase.GetSign(t.BuySell) * Amount <= 0 && (t.TradeType != "雪球期权" && t.TradeType != "凤凰期权")) { Amount = 0; flag = false; } //查看是否可以行权 行权收益为正数时可行权 if (tradeCash.IsPossibleExec && flag) { sbMsg.Append("交易编号[").Append(t.TradeNumber).Append("],行权收益:").Append(Amount).AppendLine(",行权。"); tradeCash.Amount = Amount; tradeCash.ExtraAmount = ExtraAmount; tradeCash.UnwindType = "全部行权"; t.TradeStatus = ConsTrade.已执行; clientCashList.Add(new ClientCashInCashOut { Direction = "应收", Number = UniqueTimeId.GetStr(), ClientId = client.id, ClientNumber = client.Number, ClientName = client.Name, //客户和交易员反方向 Money = Amount * -1, HappenDate = valueDate == DateTime.Now.Date ? DateTime.Now : valueDate, State = ClientCashInCashOut.已确认, //ee.OpenBankId = bc.id + ""; //ee.OpenBankCard = bc.Card; TradeId = tradeCash.TradeId, OptId = tradeCash.OptId, OptName = tradeCash.OptName, OptDate = tradeCash.OptDate, CreatorId = tradeCash.OptId, CreatorName = tradeCash.OptName, CreateDate = tradeCash.OptDate, Action = ClientCashInCashOut.系统操作_行权费, TradeNumber = t.TradeNumber, IsGroup = t.IsGroup }); } else { sbMsg.Append("交易编号[").Append(t.TradeNumber).AppendLine("],到期。"); tradeCash.Amount = 0.0; tradeCash.ExtraAmount = 0.0; tradeCash.UnwindType = "到期"; tradeCash.ValueDate = t.ExerciseDate.Value; t.TradeStatus = "已到期"; } if (t.TradeType != "现金流交易") { tradeCash.UnwindPrice = TradeHelper.GetTradeSinglePriceByTradePrice(tradeCash.Amount, t.Notional, t.PrincipalSum(), t.BuySell, t.TradeType, false); tradeCash.UnwindPricePercentRate = TradeHelper.GetPremiumRateByTradePrice(tradeCash.Amount, t.StockEqvNotional, t.ParticipationRate, t.PrincipalSum(), t.AnnualizeFactor, t.BuySell, t.TradeType, false); t.FinalPrice = tradeCash.FinalPrice; } t.UnWindDate = valueDate; //行权/到期都不需要平仓波动率 tradeCash.UnwindVol = 0; tradeCashList.Add(tradeCash); if (t.IsGroup == 2) { tradeCash.ParentTradeCashId = parentTradeCash.id; parentTradeCash.FinalPrice = settlePrice; parentTradeCash.Amount += tradeCash.Amount; parentTradeCash.UnwindPrice = TradeHelper.GetTradeSinglePriceByTradePrice(parentTradeCash.Amount, parentTradeCash.UnwindNotional, parentTrade.PrincipalSum(), parentTrade.BuySell, parentTrade.TradeType, false); parentTradeCash.UnwindPricePercentRate = TradeHelper.GetPremiumRateByTradePrice(parentTradeCash.Amount, parentTrade.OriginalStockEqvNotional * parentTradeCash.UnwindPercentRate, parentTrade.ParticipationRate, parentTrade.PrincipalSum(), parentTrade.AnnualizeFactor, parentTrade.BuySell, parentTrade.TradeType, false); //当天到期的子交易均已经到期处理了 if (!DbContext.trade.Any(x => x.ParentTradeId == parentTrade.id && x.ValidState != "InValid" && x.ExerciseDate > preday && x.ExerciseDate < dateEnd && x.id != t.id && !ConsTrade.TradeCompleteStatus.Contains(x.TradeStatus))) { parentTradeCash.Status = TradeCashStatusEnum.已执行; AddTradeOperationHistoryAndSetParentTradeInfo(false, parentTrade, "批量执行到期"); } } DbContext.SaveChanges(); } AddTradeOperationHistoryAndSetParentTradeInfo(false, t, "批量执行到期"); }; if (tradeCashList.Count > 0) { DbContext.trade_cash.AddRange(tradeCashList); DbContext.SaveChanges(); } if (clientCashList.Count > 0) { clientCashList.ForEach(x => x.TradeCashId = tradeCashList.First(y => y.TradeId == x.TradeId).id); DbContext.ClientCashInCashOut.AddRange(clientCashList); } DbContext.SaveChanges(); var tradeCashDetails = new List(); tradeCashList.ForEach(x => { var tradeCashDetail = new trade_cash_detail() { TradeId = x.TradeId, TradeCashId = x.id, Amount = x.Amount, ExtraAmount = x.ExtraAmount, SinglePrice = x.UnwindPrice, SinglePricePercentRate = x.UnwindPricePercentRate, Action = x.Action, ValueDate = x.ValueDate, OptDate = DateTime.Now, OptId = x.OptId, OptName = x.OptName }; tradeCashDetails.Add(tradeCashDetail); }); DbContext.trade_cash_detail.AddRange(tradeCashDetails); DbContext.SaveChanges(); //结构化子交易到期时,检查子交易是否都已了结,如果已了结,则主交易状态也跟着当前子交易状态变化 if (parentTradeIds.Count > 0) { foreach (var id in parentTradeIds) { var tradeStatus = ConsTrade.确认成交; var UnwindDate = DateTime.MinValue; var tradeChildren = DbContext.trade.Where(x => x.ParentTradeId == id); foreach (var child in tradeChildren) { if (ConsTrade.TradeCompleteStatus.Contains(child.TradeStatus)) { if (child.UnWindDate > UnwindDate) { UnwindDate = child.UnWindDate ?? DateTime.MinValue; tradeStatus = child.TradeStatus; } } else { tradeStatus = ConsTrade.确认成交; } } if (tradeStatus != ConsTrade.确认成交) { var tradeParent = DbContext.trade.Find(id); if (tradeParent != null) { tradeParent.TradeStatus = tradeStatus; } DbContext.SaveChanges(); } } } //生成文档 if (PS.Config.IsAutoGenerateContracts) { new TradeContractGenerateService(this).GenerateContractsAsync(tradeCashList.Select(tc => tc.TradeId).ToList()); } successMsg = sbMsg.ToString(); } } /// /// 到期确认操作结果 /// public class TradeExpireConfirmResult { public trade Trade; public bool Success; public string Message; public TradeExpireConfirmResult(trade trade) { Trade = trade; } } }