using System.Linq.Expressions; using YLErp.BLL; using YLErp.Modules.DataProviderModule; using YLErp.Modules.TradeModule; using YLErp.Modules.TradeModule.ForwardModule; namespace YLErp.Modules.EodModule.SettlementModule { /// /// 用于结算的数据查询服务 /// public class EodSettleDataQueryService : YLBaseService { public EodSettleDataQueryService(OptUserInfo optUser) : base(optUser) { } public EodSettleDataQueryService(YLBaseService baseService) : base(baseService) { } /// /// 获取要结算的交易数据 /// /// 结算日期 /// 交易数据查询过滤条件 /// 交易资金提供接口 /// 上个结算日(多交易日历场景下的假日到期交易处理时使用) public List GetOtcTrades(DateTime settleDate, Expression> tradeDataPredicate , out TradeCashDataProvider tradecashProvider, DateTime preSettleDate = default) { if (tradeDataPredicate is null) { throw new ArgumentNullException(nameof(tradeDataPredicate)); } var tradeList = new List(1000); //------------------------------------------------------ // eod trades //------------------------------------------------------ var etQuery = from et in DbContext.eod_trade join t in DbContext.trade.Where(tradeDataPredicate) on et.TradeId equals t.id where et.ValueDate == settleDate select new { t.id, et.TradeId, et.TradeJson, t.BuySell, t.AssetId, t.ExerciseDate, t.DividendRate, t.TradeType }; var etList = etQuery.ToArray(); List structProductTradeMetaList = null; if (etList != null && etList.Length > 0) { var structProductTradeIds = etList.Where(p => "结构化产品".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList(); if (structProductTradeIds != null && structProductTradeIds.Count > 0) { structProductTradeMetaList = DbContext.TradeMeta.AsNoTracking().Where(d => structProductTradeIds.Contains(d.TradeId)).ToList(); } } if (structProductTradeMetaList == null) { structProductTradeMetaList = new List(); } foreach (var item in etList) { try { var t = TradeHelper2.Deserialize(item.TradeJson); t.id = item.TradeId; t.BuySell = item.BuySell; t.AssetId = item.AssetId; if (t.ExerciseDate != item.ExerciseDate && !DbContext.ExtensionTime.Any(x => x.TradeId == t.id && x.IsValid && x.OldMaturityDate == t.ExerciseDate && x.NewMaturityDate == item.ExerciseDate && x.OptDate >= settleDate)) { t.ExerciseDate = item.ExerciseDate; } t.MetaDic["from_eod_trade"] = "true"; tradeList.Add(t); //先简单处理一下避免某些情况下删除eodtrade表数据 //比如手动在数据库改了观察频率回到历史收盘(手动改是因为回到历史收盘太慢了而且涉及到除权除息的各种问题) if (t.TradeType == "雪球期权") { var snowball = DbContext.trade_snowball.Where(n => n.TradeId == item.id).Select(n => new { n.KOObservationDates, n.ObservationDates, n.KOObservationSettleDates }).FirstOrDefault(); if (snowball != null && t.trade_snowball != null) { t.trade_snowball.ObservationDates = snowball.ObservationDates; t.trade_snowball.KOObservationDates = snowball.KOObservationDates; t.trade_snowball.KOObservationSettleDates = snowball.KOObservationSettleDates; } } else if (t.TradeType == "凤凰期权") { var autocall = DbContext.trade_autocall.Where(n => n.TradeId == item.id).Select(n => new { n.ObservationDates, n.KOObservationDates }).FirstOrDefault(); if (autocall != null && t.trade_autocall != null) { t.trade_autocall.ObservationDates = autocall.ObservationDates; t.trade_autocall.KOObservationDates = autocall.KOObservationDates; } } else if (t.TradeType == "累计期权") { t.MetaDic.Remove("from_eod_trade"); new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(t, settleDate); } else if (t.TradeType == "远期") { var forwardTrade = DbContext.trade_forward.Where(n => n.TradeId == item.id).Select(n => new { n.ForwardValue, n.OpenCommission }).FirstOrDefault(); } else if (t.TradeType == "结构化产品") { var tradeMetas = structProductTradeMetaList.Where(d => d.TradeId == t.id).ToDictionary(g => g.MetaKey, g => g.MetaValue); if (tradeMetas != null && tradeMetas.Count > 0) { foreach (var d in tradeMetas) { if (!t.MetaDic.ContainsKey(d.Key)) { t.MetaDic.Add(d.Key, d.Value); } } } } else if (t.TradeType == "亚式期权") { if (t.trade_asian_option.PayoffType == "EnhancedArithmeticAverage" && t.trade_asian_option.EnhancedPrice == 0 && t.TradeDate < new DateTime(2023, 2, 19) && t.Strike.HasValue) { t.trade_asian_option.EnhancedPrice = t.Strike.Value; } } //解决收盘时从hisdata取了null并且存入了eodtrade的情况下数据问题 if (t.DividendRate == null) { t.DividendRate = item.DividendRate; } } catch (Exception ex) { LogFactory.GetLogger("eod_trade.TradeJson解析").Error(ex); } } //------------------------------------------------------ // 多交易日历场景下的假日到期交易处理 //------------------------------------------------------ if (PS.Config.ErpElement.SupportMultiCalendar) { var pretQuery = from et in DbContext.eod_trade join t in DbContext.trade on et.TradeId equals t.id where et.ValueDate == preSettleDate && !DbContext.trade.Where(tradeDataPredicate).Any(n => n.id == et.TradeId) select new { et.TradeId, et.TradeJson, t.BuySell, t.UnderlyingCode }; var pretList = pretQuery.ToArray(); if (pretList.Any()) { var exHolidaySet = DataCacheProvider.GetMarketDataSource().AsQueryable() .Where(n => !string.IsNullOrEmpty(n.ExchangeNo) && QdpModule.QdpCalendarHelper.IsHoliday(preSettleDate, n.CalendarName.TrimToNull() ?? ConsGlobal.DefaultCalendar)) .Select(n => n.ExchangeNo.ToUpperInvariant()).ToHashSet(); foreach (var item in pretList) { if (!tradeList.Any(x => x.id == item.TradeId)) { var un = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode); if (!string.IsNullOrEmpty(un.MarketCode) && exHolidaySet.Contains(un.MarketCode)) { try { var t = TradeHelper2.Deserialize(item.TradeJson); t.id = item.TradeId; t.BuySell = item.BuySell; t.MetaDic["from_eod_trade"] = "true"; tradeList.Add(t); } catch (Exception ex) { LogFactory.GetLogger("eod_trade.TradeJson解析").Error(ex); } } } } } } //------------------------------------------------------ // 没有出现在eodtrae表中的交易数据 //------------------------------------------------------ var eodTradeIds = tradeList.Select(n => n.id); tradeDataPredicate = tradeDataPredicate.And(t => !eodTradeIds.Contains(t.id)); var trades = DbContext.trade.AsNoTracking().Where(tradeDataPredicate).ToArray(); //------------------------------------------------------ // 交易资金接口 //------------------------------------------------------ var tradeIds = trades.Select(x => x.id).ToList(); tradecashProvider = new TradeCashDataProvider().Initialize(eodTradeIds.Concat(tradeIds).ToArray()); var tradecashPreProvider = new TradeCashPreDataProvider().Initialize(eodTradeIds.Concat(tradeIds).ToArray()); //------------------------------------------------------ // 交易数据结果集 //------------------------------------------------------ if (!trades.Any()) { return tradeList; } tradeList.AddRange(trades); structProductTradeMetaList = null; if (trades != null && trades.Length > 0) { var structProductTradeIds = trades.Where(p => "结构化产品".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList(); if (structProductTradeIds != null && structProductTradeIds.Count > 0) { structProductTradeMetaList = DbContext.TradeMeta.AsNoTracking().Where(d => structProductTradeIds.Contains(d.TradeId)).ToList(); } } if (structProductTradeMetaList == null) { structProductTradeMetaList = new List(); } foreach (var t in trades) { if (t.TradeType == "累计期权") { new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(t, settleDate); } if (t.TradeType == "结构化产品") { var tradeMetas = structProductTradeMetaList.Where(d => d.TradeId == t.id).ToDictionary(g => g.MetaKey, g => g.MetaValue); if (tradeMetas != null && tradeMetas.Count > 0) { foreach (var d in tradeMetas) { if (!t.MetaDic.ContainsKey(d.Key)) { t.MetaDic.Add(d.Key, d.Value); } } } } ProcessTrade(settleDate, tradecashProvider, tradecashPreProvider, t); } return tradeList; } public static void ProcessTrade(DateTime settleDate, TradeCashDataProvider tradecashProvider, TradeCashPreDataProvider tradecashPreProvider, trade t) { //存在收盘之后的了结记录,代表收盘日那天,交易为确认成交状态 var tradeCashs = tradecashProvider.GetTradeCashes(t.id).Where(x => x.ValidState != "InValid" && !x.IsDeleted && x.Action != "系统操作-期权费" && (x.HappenedDate > settleDate || x.ValueDate > settleDate && x.HappenedDate == null)); t.TradeStatus = tradeCashs.Any() ? ConsTrade.确认成交 : t.TradeStatus; //收历史盘时,找到收盘日之前最近一次的了结日期 var lastSecondTradeCash = tradecashProvider.GetTradeCashes(t.id).Where(x => x.ValidState != "InValid" && !x.IsDeleted && x.Action != "系统操作-期权费" && (x.HappenedDate <= settleDate || x.ValueDate <= settleDate && x.HappenedDate == null)).OrderByDescending(y => y.id).FirstOrDefault(); t.UnWindDate = lastSecondTradeCash?.HappenedDate ?? lastSecondTradeCash?.ValueDate; if (ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus)) { t.Notional = 0; t.TradeAmount = 0; t.StockEqvNotional = 0; } else { var tc = tradeCashs.Where(x => x.Notional != 0).FirstOrDefault(); if (tc != null) { t.Notional = tc.Notional; } else { //取第一个ValueDate大于settleDate的TradeCash数据(TradeCashPreDataProvider类中ValueDate已做正序处理) var tcPrePredicate = new Func(x => x.Action != "系统操作-期权费" && x.Notional != 0 && x.ValueDate > settleDate && (x.HappenedDate > settleDate || x.HappenedDate == null)); var tcPre = tradecashPreProvider.GetTradeCashPres(t.id).FirstOrDefault(tcPrePredicate); if (tcPre != null) { t.Notional = tcPre.Notional; } } if (t.TradeType == ConsGlobal.TradeType.CashFlow) { t.TradeAmount = 0; t.StockEqvNotional = t.Notional; } else { var CountRatio = (DataCacheProvider.GetUnderlyingDataSource().GetData(t.UnderlyingId)?.CountRatio) ?? 1; t.TradeAmount = t.Notional / CountRatio; t.StockEqvNotional = t.OriginalNotional == 0 ? 0 : (t.Notional / t.OriginalNotional * t.OriginalStockEqvNotional) ?? 0; } } tradeBLL.SetFieldsByTradeType(t, settleDate); } } }