using YLErp.BLL; using YLErp.BLL.Eod; using YLErp.DBModels.Consts; using YLErp.DBModels.Helpers; using YLErp.Model; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.Modules.TradeModule.DealModule; namespace YLErp.Modules.TradeDalModule { /// /// 交易操作服务 /// public class TradeDalService : YLBaseService { public TradeDalService(YLBaseService baseService) : base(baseService) { } public TradeDalService(OptUserInfo userInfo) : base(userInfo) { } public void SetStructureInfo(IEnumerable trades) { IEnumerable lists = trades.Select(O => new trade { TradeType = O.TradeType, id = O.id, }).ToArray(); SetStructureInfo(lists); foreach (var item in lists) { if (item.id <= 0) { continue; } var t = trades.First(O => O.id == item.id); t.SubTrades = item.SubTrades; } } /// /// 获取结构化交易信息 /// public void SetStructureInfo(IEnumerable trades) { trades = trades.Where(n => n.TradeType == "结构化交易").ToArray(); if (!trades.Any()) { return; } var tradeids = trades.Select(r => r.id).ToList(); var subTradeDic = new Dictionary(); var subGrps = DbContext.trade.Where(n => tradeids.Contains(n.ParentTradeId)).Select(n => new OtcTradeDto { Strike = n.Strike, BuySell = n.BuySell, IsMoneynessOption = n.IsMoneynessOption, ParentTradeId = n.ParentTradeId }).ToArray().GroupBy(n => n.ParentTradeId).ToArray(); foreach (var grp in subGrps) { var trad = trades.First(n => n.id == grp.Key); trad.SubTrades = grp.Select(O => new trade { Strike = O.Strike, BuySell = O.BuySell, IsMoneynessOption = O.IsMoneynessOption, ParentTradeId = O.ParentTradeId }).ToList(); } } public void SetStructureInfo(IEnumerable trades,List childTrades) { if (trades == null || childTrades == null) { return; } trades = trades.Where(n => n.TradeType == "结构化交易").ToArray(); if (!trades.Any()) { return; } var tradeids = trades.Select(r => r.id).ToList(); var subTradeDic = new Dictionary(); var subGrps = childTrades.Where(n => tradeids.Contains(n.ParentTradeId)).Select(n => new OtcTradeDto { Strike = n.Strike, BuySell = n.BuySell, IsMoneynessOption = n.IsMoneynessOption, ParentTradeId = n.ParentTradeId }).ToArray().GroupBy(n => n.ParentTradeId).ToArray(); foreach (var grp in subGrps) { var trad = trades.First(n => n.id == grp.Key); trad.SubTrades = grp.Select(O => new trade { Strike = O.Strike, BuySell = O.BuySell, IsMoneynessOption = O.IsMoneynessOption, ParentTradeId = O.ParentTradeId }).ToList(); } } /// /// 设置交易 /// public void SetSubTradeList(List trades) { var subTradeDic = trades.Where(t => t.ParentTradeId > 0).AsEnumerable().GroupBy(t => t.ParentTradeId).ToDictionary(g => g.Key, g => g.ToList()); foreach (var trade in trades) { if (trade.TradeType == "结构化交易" && subTradeDic.ContainsKey(trade.id)) { trade.SubTrades = subTradeDic[trade.id]; } } } public TradeWithSettlement GetTradeWithSettlementTradeCash(trade trade) { var result = new TradeWithSettlement(); if (!ConsTrade.TradeTypesForHedge.Contains(trade.TradeType) && trade.TradeType != "现金流交易") { var CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetCountRatio(trade.UnderlyingCode); trade.TradeOriginalAmount = trade.OriginalNotional / CountRatio; } trade.LotsNewInfo = TradeLotsCalc.GetLots(trade.UnderlyingCode, trade.Notional); if (!string.IsNullOrEmpty(trade.PairTrade)) { var pairTrade = DbContext.trade.FirstOrDefault(x => x.id.ToString() == trade.PairTrade); trade.PairTradeNumber = pairTrade == null ? "" : pairTrade.TradeNumber; } else { trade.PairTradeNumber = ""; } if (trade.TradeType == "合成价差期权") { trade.SyntheticUnderlyingTipsInfo = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode); } tradeBLL.SetFieldsByTradeType(trade); //了结交易的持仓数量及份额需要为0 if (ConsTrade.TradeCompleteStatus.Contains(trade.TradeStatus)) { trade.TradeAmount = 0; trade.Notional = 0; } if (!ConsTrade.TradeTypesForHedge.Contains(trade.TradeType)) { var tradeCashList = DbContext.trade_cash.Where(t => t.TradeId == trade.id && t.ValidState != ConsGlobal.InValid && !t.IsDeleted && (t.Action == ClientCashInCashOut.系统操作_行权费 || t.Action == ClientCashInCashOut.系统操作_平仓费 || t.Action == ClientCashInCashOut.系统操作_互换 || t.Action == ClientCashInCashOut.系统操作_票息)).OrderBy(t => t.ValueDate).ToList(); var tradeCashSwaps = DbContext.trade_cash_swap.Where(x => x.TradeId == trade.id).ToList(); tradeCashList.ForEach(tradeCash => { if (trade.IsGroup == 1) { var winloss = 0.0; var tradeCashs = DbContext.trade_cash.Where(x => x.ParentTradeCashId == tradeCash.id).ToList(); tradeCashs.ForEach(x => { var tradeCashDetail = DbContext.trade_cash_detail.Where(y => y.TradeCashId == x.id); var amount = tradeCashDetail.Any() ? tradeCashDetail.Sum(y => y.Amount ?? 0) : x.Amount; var childTrade = DbContext.trade.Find(x.TradeId); winloss += amount + (childTrade.TradePrice ?? 0) * (x.UnwindPercentRate ?? 0) * ((childTrade.BuySell == "卖出") ? 1 : -1); }); tradeCash.WinLoss = winloss.OtcFormatMoney(grouping: false); } else { var tradeCashDetail = DbContext.trade_cash_detail.Where(x => x.TradeCashId == tradeCash.id); var amount = tradeCashDetail.Any() ? tradeCashDetail.Sum(x => x.Amount ?? 0) : tradeCash.Amount; tradeCash.WinLoss = (amount + (trade.TradePrice ?? 0) * (tradeCash.UnwindPercentRate ?? 0) * ((trade.BuySell == "卖出" || trade.TradeType == "远期") ? 1 : -1)).OtcFormatMoney(grouping: false); if (PS.Config.IsGuoJun) { var Quoteamount = tradeCashDetail.Any() ? tradeCashDetail.Sum(y => y.QuoteAmount ?? 0) : (tradeCash.QuoteAmount ?? 0); tradeCash.QuoteWinloss = (Quoteamount + (trade.TradePrice ?? 0) / (tradeCash.CurrencyRate ?? 1) * (tradeCash.UnwindPercentRate ?? 0) * ((trade.BuySell == "卖出") ? 1 : -1)).OtcFormatMoney(grouping: false); } } tradeCash.SingleWinPrice = Math.Abs(tradeCash.Action == "系统操作-平仓费" && trade.IsUsePremiumRate == true ? TradeHelper.GetTradeSinglePriceByPremiumRate(tradeCash.UnwindPricePercentRate, trade.SpotPrice) : (tradeCash.UnwindPrice ?? 0)); tradeCash.SingleWinPriceString = trade.IsUsePremiumRate == true && tradeCash.Action == "系统操作-平仓费" ? (tradeCash.UnwindPricePercentRate ?? 0).OtcFormat(OtcFormatFlag.premiumRateP) : tradeCash.SingleWinPrice.OtcFormat(OtcFormatFlag.tradeSinglePrice); tradeCash.SingleWinPricePercent = tradeCash.UnwindPricePercentRate ?? 0; if (trade.TradeType == "收益互换") { tradeCash.trade_cash_swap = tradeCashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id); } }); var unWindTradeCashList = tradeCashList.Where(t => t.Action == ClientCashInCashOut.系统操作_平仓费 || (t.Action == ClientCashInCashOut.系统操作_行权费 && t.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权)) .OrderBy(t => t.ValueDate).ToList(); if (trade.TradeType == "累计期权") { //部分行权的记录展示在累计收益tab页面了,所以过滤掉 unWindTradeCashList = unWindTradeCashList.Where(x => x.UnwindType != "部分行权").ToList(); } var swapTradeCashList = tradeCashList.Where(t => t.Action == ClientCashInCashOut.系统操作_互换) .OrderBy(t => t.ValueDate).ToList(); var couponTradeCashList = tradeCashList.Where(t => t.Action == ClientCashInCashOut.系统操作_票息) .OrderBy(t => t.ValueDate).ToList(); var maturityTradeCash = tradeCashList.FirstOrDefault(t => t.Action == ClientCashInCashOut.系统操作_行权费 && t.ExerciseWay != TradeCashExerciseWayEnum.提前终止行权 && t.IsLastAction); if (maturityTradeCash != null) { maturityTradeCash.NotionalPercent = maturityTradeCash.UnwindPercentRate ?? 0; } bool ActualHasMinusValueOptions = valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1 ? ConsTrade.HasMinusValueOptions.Contains(trade.TradeType) : !ConsTrade.HasMinusValueOptions.Contains(trade.TradeType); unWindTradeCashList.ForEach(x => { x.NotionalPercent = x.UnwindPercentRate ?? 0; x.UnwindStockEqvNotional = (trade.OriginalStockEqvNotional ?? 0) * (x.UnwindPercentRate ?? 0); if (x.HappenedDate != null) { x.ValueDate = x.HappenedDate.Value; } x.UnwindPrice = ActualHasMinusValueOptions || trade.TradeType == "远期" || trade.TradeType == "收益互换" ? x.UnwindPrice : x.UnwindPrice * (trade.BuySell == "买入" ? 1 : -1); x.UnwindPricePercentRate = ActualHasMinusValueOptions || trade.TradeType == "远期" || trade.TradeType == "收益互换" ? x.UnwindPricePercentRate : x.UnwindPricePercentRate * (trade.BuySell == "买入" ? 1 : -1); x.Amount = x.Amount * (valuedateBLL.SystemDate.UnwindAmountAngle == 1 || trade.TradeType == "远期" || trade.TradeType == "收益互换" ? 1 : EodOperationBase.GetSign(trade.BuySell)); x.QuoteAmount = x.QuoteAmount * (valuedateBLL.SystemDate.UnwindAmountAngle == 1 || trade.TradeType == "远期" || trade.TradeType == "收益互换" ? 1 : EodOperationBase.GetSign(trade.BuySell)); }); swapTradeCashList.ForEach(x => { x.InitialAmount = x.Amount - (x.ExtraAmount ?? 0); x.InitialSpotPrice = trade.SpotPrice ?? 0; x.StockEqvNotional = (trade.OriginalStockEqvNotional ?? 0) * (x.NotionalPercentRate ?? 0); }); result.UnwindTradeCashList = unWindTradeCashList; if (trade.IsGroup == 1 && trade.TradeType == "收益互换" && unWindTradeCashList.Any()) { var unwindTradeCash = unWindTradeCashList.FirstOrDefault(); var childrenTradeCashList = DbContext.trade_cash.Where(t => t.ParentTradeCashId == unwindTradeCash.id && t.ValidState != "InValid" && !t.IsDeleted && (t.Action == ClientCashInCashOut.系统操作_行权费 || t.Action == ClientCashInCashOut.系统操作_平仓费 || t.Action == ClientCashInCashOut.系统操作_互换)).OrderBy(t => t.ValueDate).ToList(); var childrenTradeCashIds = childrenTradeCashList.Select(x => x.id).ToList(); var childrenTradeCashSwaps = DbContext.trade_cash_swap.Where(x => childrenTradeCashIds.Contains(x.TradeCashId)).ToList(); var childrenTradeIds = childrenTradeCashList.Select(x => x.TradeId).ToList(); var childrenTrades = DbContext.trade.Where(x => childrenTradeIds.Contains(x.id)).ToList(); var childrenTradeSwaps = DbContext.trade_swap.Where(x => childrenTradeIds.Contains(x.TradeId)).ToList(); childrenTradeCashList.ForEach(tradeCash => { var childTrade = childrenTrades.FirstOrDefault(y => y.id == tradeCash.TradeId); var childrenTradeSwap = childrenTradeSwaps.FirstOrDefault(y => y.TradeId == tradeCash.TradeId); tradeCash.UnderlyingCode = childTrade.UnderlyingCode; tradeCash.CallPut = childrenTradeSwap.IsPayFloatingProfit ? childrenTradeSwap.PayLongShort : childrenTradeSwap.GetLongShort; var tradeCashDetail = DbContext.trade_cash_detail.Where(x => x.TradeCashId == tradeCash.id); var amount = tradeCashDetail.Any() ? tradeCashDetail.Sum(x => x.Amount ?? 0) : tradeCash.Amount; tradeCash.WinLoss = (amount + (childTrade.TradePrice ?? 0) * (tradeCash.UnwindPercentRate ?? 0) * ((childTrade.BuySell == "卖出") ? 1 : -1)).OtcFormatMoney(grouping: false); if (childTrade.TradeType == "收益互换") { tradeCash.trade_cash_swap = childrenTradeCashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id); } }); result.UnwindChildrenTradeCashList = childrenTradeCashList; } result.MaturityTradeCash = maturityTradeCash; result.SwapTradeCashList = swapTradeCashList; result.CouponTradeCashList = couponTradeCashList; if (trade.ExerciseDate < valuedateBLL.ValueDate && trade.CanExpire()) { if (EodPriceQueryService.TryGetEodPrice(trade.ExerciseDate.Value, trade.UnderlyingCode, out var eodPrice)) { trade.FinalPrice = eodPrice.GetPrice(trade.SettlementType); } } } result.Trade = trade; return result; } /// /// 获取交易信息 /// 优先从eod表中取 /// /// /// /// 是否需要跟踪引用,用于需要对结果进行修改并保存的操作 /// public List GetTradeOrEodTrade(IEnumerable ids, DateTime valueDate, bool useTracking = false) { if (ids is null) { throw new ArgumentNullException(nameof(ids)); } var eodTradeArr = (from et in DbContext.eod_trade.AsNoTracking() where et.ValueDate == valueDate && ids.Contains(et.TradeId) select et).ToArray(); var newIds = ids.Except(eodTradeArr.Select(O => O.TradeId)).ToArray(); List tradeList = null; if (newIds.Length < 1) { tradeList = new List(); } else { tradeList = (useTracking ? DbContext.trade : DbContext.trade.AsNoTracking()) .Where(t => newIds.Contains(t.id) && t.ValidState != "InValid").ToList(); tradeBLL.SetFieldsByTradeType(tradeList); foreach (var t in tradeList) { if (t.TradeType == "累计期权") { new TradeModule.OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(t, valueDate); } } } if (useTracking) { tradeList.AddRange(TrackTrade(eodTradeArr)); } else { tradeList.AddRange(eodTradeArr.Select(O => O.trade)); } return tradeList; } /// /// 根据tradeId或子交易Id /// 用于生成交易确认书的,该方法会根据交易日去获取eodtrade而非valuedate /// public List GetTradeOrEodTradeOfTidASid(IEnumerable tradeIds, DateTime valueDate, bool useTracking = false, bool withNoGroupChildrenTrades = true, bool useTradeDate = true) { if (tradeIds is null) { throw new ArgumentNullException(nameof(tradeIds)); } var pids = DbContext.trade.Where(c => tradeIds.Contains(c.id) && c.ParentTradeId > 0).Select(d => d.ParentTradeId).ToArray(); var idset = new HashSet(tradeIds.Concat(pids).ToArray()); return GetTradeOrEodTradeOfTidAPid(idset, valueDate, useTracking, withNoGroupChildrenTrades, useTradeDate); } /// /// 根据tradeId或ParentTradeId获取交易信息 /// 优先从eod表中取 /// public List GetTradeOrEodTradeOfTidAPid(IEnumerable tradeIds, DateTime valueDate, bool useTracking = false, bool withNoGroupChildrenTrades = true, bool useTradeDate = false) { if (tradeIds is null) { throw new ArgumentNullException(nameof(tradeIds)); } var eodTradeArr = (from et in DbContext.eod_trade where et.ValueDate == valueDate && (tradeIds.Contains(et.TradeId) || tradeIds.Contains(et.ParentTradeId)) select et).ToArray(); //生成确认书时,需要根据交易日获取当天的收盘数据,以防trade表会因为除权除息改变数据了 if (useTradeDate) { eodTradeArr = (from et in DbContext.eod_trade join trade in DbContext.trade on new { id = et.TradeId, tradeDate = et.ValueDate } equals new { trade.id, tradeDate = trade.TradeDate ?? DateTime.Now } where tradeIds.Contains(et.TradeId) || tradeIds.Contains(et.ParentTradeId) select et).ToArray(); } var eodTradeIds = eodTradeArr.Select(O => O.TradeId).ToArray(); var tradeList = (from t in useTracking ? DbContext.trade : DbContext.trade.AsNoTracking() where !eodTradeIds.Contains(t.id) && (tradeIds.Contains(t.id) || tradeIds.Contains(t.ParentTradeId)) && t.ValidState != "InValid" select t).ToList(); if (withNoGroupChildrenTrades) { tradeList = (from t in useTracking ? DbContext.trade : DbContext.trade.AsNoTracking() where !eodTradeIds.Contains(t.id) && (tradeIds.Contains(t.id) || tradeIds.Contains(t.ParentTradeId)) && t.ValidState != "InValid" && t.IsGroup != 2 select t).ToList(); } tradeBLL.SetFieldsByTradeType(tradeList); if (useTracking) { tradeList.AddRange(TrackTrade(eodTradeArr)); } else { tradeList.AddRange(eodTradeArr.Select(O => O.trade)); } return tradeList; } /// /// 获取结构化交易信息 /// 优先从eod表中取 /// /// /// /// public List GetStructTradeFromTradeOrEodTrade(IEnumerable parentIds, DateTime valueDate, bool useTracking = false) { if (parentIds is null) { throw new ArgumentNullException(nameof(parentIds)); } var eodTradeArr = (from et in DbContext.eod_trade where et.ValueDate == valueDate && (parentIds.Contains(et.ParentTradeId)) select et).ToArray(); List tradeList = null; var newIds = parentIds.Except(eodTradeArr.Select(O => O.ParentTradeId)).ToArray(); if (newIds.Length < 1) { tradeList = new List(); } else { tradeList = (from t in useTracking ? DbContext.trade : DbContext.trade.AsNoTracking() where newIds.Contains(t.ParentTradeId) && t.ValidState != "InValid" select t).ToList(); } if (useTracking) { tradeList.AddRange(TrackTrade(eodTradeArr)); } else { tradeList.AddRange(eodTradeArr.Select(O => O.trade)); } return tradeList; } /// /// 将交易还原到某日收盘之前 /// 主要针对除权除息过的交易 /// /// /// public void RollbackToBeforeSettle(trade t, DateTime valueDate) { var originTrade = GetTradeOrEodTrade(new[] { t.id }, valueDate).FirstOrDefault(); if (originTrade != null && originTrade.Notional > 0) { //将交易信息还原到收盘前 DividendService.SetDividendTradeData(t, originTrade); } } private List TrackTrade(IEnumerable eodTrades) { var result = new List(); var eodIds = eodTrades.Select(O => O.TradeId); var trades = eodTrades.Select(O => O.trade); var trackTrades = DbContext.trade.Where(O => eodIds.Contains(O.id)).ToDictionary(K => K.id, V => V); foreach (var item in trades) { DividendService.SetDividendTradeData(trackTrades[item.id], item); result.Add(trackTrades[item.id]); } return result; } } }