using System.Data; using YLErp.BLL; using YLErp.Commons; using YLErp.DBModels.Consts; using YLErp.DBModels.Helpers; using YLErp.Model; using YLErp.Modules.DataProviderModule; using YLErp.Modules.UnderlyingModule; using YLErp.QdpModule; namespace YLErp.Modules.TradeModule.DealModule { /// /// 除权除息操作(请使用正常英文单词) /// public class DividendService : YLBaseService { public DividendService(OptUserInfo userInfo) : base(userInfo) { } /// /// 场内交易除权除息 /// /// 除权日 /// 持仓列表 public List Execute(DateTime settleDate, IEnumerable positions) { var result = new List(); var dict = DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate == settleDate).ToDictionary(K => K.UnderlyingId, V => V); foreach (var item in positions) { double cost = item.Cost, amount = item.Amount; //averagePrice = item.AveragePrice; var bodPosition = new BodTradePosition(); if (dict.ContainsKey(item.UnderlyingId)) { var averagePrice = Math.Abs(item.Cost / item.Amount); amount = GetPositionAmount(amount, dict[item.UnderlyingId]); averagePrice = GetPrice(averagePrice, dict[item.UnderlyingId]); cost = amount * averagePrice; } bodPosition.ValueDate = settleDate; bodPosition.HedgeUniqueCode = item.HedgeUniqueCode; bodPosition.ExchangeOptionCode = item.ExchangeOptionCode; bodPosition.TradeType = item.TradeType; bodPosition.PositionType = item.PositionType; bodPosition.BookId = item.BookId; bodPosition.UnderlyingId = item.UnderlyingId; bodPosition.UnderlyingCode = item.UnderlyingCode; bodPosition.BuySell = item.BuySell; bodPosition.Cost = cost; bodPosition.Amount = amount; //bodPosition.AveragePrice = averagePrice; bodPosition.Commission = item.Commission; bodPosition.OptId = item.OptId; bodPosition.OptName = item.OptName; bodPosition.OptDate = DateTime.Now; result.Add(bodPosition); } return result; } /// /// 场外交易除权除息 /// /// 除权日 /// 交易列表 /// 是否将结果保存到trade表 /// public List Execute(DateTime settleDate, IEnumerable trades, out List useSaveTrades, out List useSaveUndedrlyings) { useSaveTrades = new List(); useSaveUndedrlyings = new List(); var result = new List(); var dict = DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate == settleDate).ToDictionary(K => K.UnderlyingId, V => V); var tradeIds = trades.Select(O => O.id); var dividendRatioDict = new DbRecordChangesService(this).GetValue(ConsInfoChangeType.UserChange, tradeIds, nameof(trade.DividendRatio), settleDate).ToDictionary(K => K.RecordId, V => { return double.TryParse(V.NewValue, out var temp) ? (double?)temp : null; }); foreach (var t in trades) { var bodTrade = new bod_trade(); if (dict.TryGetValue(t.UnderlyingId, out var dividendInfo)) { var ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null; //避免该字段为NULL时amount和notion不一致 //股票的amount和notion应相等 var unwindNotional = t.OriginalNotional - t.Notional; t.TradeOriginalAmount = t.TradeOriginalAmount ?? t.OriginalNotional; t.SpotPrice = GetPrice(t.SpotPrice, dividendInfo, ratio); var annualizeFactor = t.AnnualizeFactor; if (t.TradeType == "凤凰期权") { annualizeFactor = t.trade_autocall.AnnualizeFactor2; } else if (t.TradeType == "雪球期权") { annualizeFactor = t.trade_snowball.AnnualizeFactor2; } t.StockEqvNotionalReal = t.StockEqvNotionalReal == 0 ? TradeHelper.GetStockEqvNotionalReal(t.OriginalStockEqvNotional, t.ParticipationRate, annualizeFactor) : t.StockEqvNotionalReal; t.OriginalNotional = t.StockEqvNotionalReal / t.SpotPrice; t.TradeOriginalAmount = t.OriginalNotional / (t.CountRatio ?? 1); //不管是不是名义本金方式了结,都应该按照比例了结。--时嬴政 //if (t.IsUsePremiumRate.HasValue && t.IsUsePremiumRate.Value) //{ var settlePercent = (t.StockEqvNotional / t.OriginalStockEqvNotional) ?? 0; t.Notional = (t.OriginalNotional * settlePercent) ?? 0; t.TradeAmount = (t.TradeOriginalAmount * settlePercent) ?? 0; //} //else //{ // t.Notional = (t.OriginalNotional - unwindNotional) ?? 0; // t.TradeAmount = (t.TradeOriginalAmount - unwindNotional) ?? 0; //} t.TradeSinglePrice = TradeHelper.GetTradeSinglePriceByTradePrice(t.TradePrice, t.OriginalNotional, t.PrincipalSum(), t.BuySell, t.TradeType, true); if (t.TradeType == "彩虹期权") { t.trade_rainbow_option.SpotPrice1 = GetPrice(t.trade_rainbow_option.SpotPrice1, dividendInfo, ratio); t.trade_rainbow_option.SpotPrice2 = GetPrice(t.trade_rainbow_option.SpotPrice2, dividendInfo, ratio); } if (!t.IsMoneynessOptionData) { t.Strike = GetPrice(t.Strike, dividendInfo, ratio); switch (t.TradeType) { case "亚式期权": //获取fixings的时候,函数内部处理除权除息逻辑; break; case "障碍期权": t.trade_barrier_option.BarrierPrice = GetPrice(t.trade_barrier_option.BarrierPrice, dividendInfo, ratio); t.trade_barrier_option.UpperBarrierPrice = GetPrice(t.trade_barrier_option.UpperBarrierPrice, dividendInfo, ratio); break; case "彩虹期权": t.trade_rainbow_option.Strike = GetPrice(t.trade_rainbow_option.Strike, dividendInfo, ratio); t.trade_rainbow_option.Strike2 = GetPrice(t.trade_rainbow_option.Strike2, dividendInfo, ratio); break; case "凤凰期权": t.trade_autocall.KIBarrier = GetPrice(t.trade_autocall.KIBarrier, dividendInfo, ratio); t.trade_autocall.KOBarrier = GetPrice(t.trade_autocall.KOBarrier, dividendInfo, ratio); t.trade_autocall.CouponBarrier = GetPrice(t.trade_autocall.CouponBarrier, dividendInfo, ratio); t.trade_autocall.SpreadStrike = GetPrice(t.trade_autocall.SpreadStrike, dividendInfo, ratio); t.trade_autocall.SpreadStrike1 = GetPrice(t.trade_autocall.SpreadStrike1, dividendInfo, ratio); var obsInfos = QdpHelper.ParseAutocallCustomizedInfo(t.trade_autocall.KOObservationDates); for (var i = 0; i < obsInfos.Item2.Length; i++) { obsInfos.Item2[i] = GetPrice(obsInfos.Item2[i], dividendInfo, ratio); } t.trade_autocall.KOObservationDates = $"{string.Join(",", obsInfos.Item1.Select(O => O.ToString()))};{string.Join(",", obsInfos.Item2.Select(O => O.OtcFormatUmPrice()))};{string.Join(",", obsInfos.Item3.Select(O => O.OtcFormatFlex(2)))}"; break; case "双鲨期权": t.trade_double_sharkfin_option.BarrierHigh = GetPrice(t.trade_double_sharkfin_option.BarrierHigh, dividendInfo, ratio); t.trade_double_sharkfin_option.BarrierLow = GetPrice(t.trade_double_sharkfin_option.BarrierLow, dividendInfo, ratio); t.trade_double_sharkfin_option.StrikeHigh = GetPrice(t.trade_double_sharkfin_option.StrikeHigh, dividendInfo, ratio); t.trade_double_sharkfin_option.StrikeLow = GetPrice(t.trade_double_sharkfin_option.StrikeLow, dividendInfo, ratio); break; case "区间累积期权": t.trade_rangeaccrual.LowerRange = GetPrice(t.trade_rangeaccrual.LowerRange, dividendInfo, ratio); t.trade_rangeaccrual.UpperRange = GetPrice(t.trade_rangeaccrual.UpperRange, dividendInfo, ratio); break; case "雪球期权": t.trade_snowball.KIBarrier = GetPrice(t.trade_snowball.KIBarrier, dividendInfo, ratio); t.trade_snowball.KOBarrier = GetPrice(t.trade_snowball.KOBarrier, dividendInfo, ratio); t.trade_snowball.SpreadStrikeAtKO = GetPrice(t.trade_snowball.SpreadStrikeAtKO, dividendInfo, ratio); t.trade_snowball.SpreadStrikeAtKO1 = GetPrice(t.trade_snowball.SpreadStrikeAtKO1, dividendInfo, ratio); t.trade_snowball.SpreadStrikeAtMaturity = GetPrice(t.trade_snowball.SpreadStrikeAtMaturity, dividendInfo, ratio); t.trade_snowball.SpreadStrikeAtMaturity1 = GetPrice(t.trade_snowball.SpreadStrikeAtMaturity1, dividendInfo, ratio); obsInfos = QdpHelper.ParseAutocallCustomizedInfo(t.trade_snowball.KOObservationDates); for (var i = 0; i < obsInfos.Item2.Length; i++) { obsInfos.Item2[i] = GetPrice(obsInfos.Item2[i], dividendInfo, ratio); } t.trade_snowball.KOObservationDates = $"{string.Join(",", obsInfos.Item1.Select(O => O.ToString()))};{string.Join(",", obsInfos.Item2.Select(O => O.OtcFormatUmPrice()))};{string.Join(",", obsInfos.Item3.Select(O => O.OtcFormatFlex(2)))}"; break; case "气囊结构": t.trade_airbag.Barrier = GetPrice(t.trade_airbag.Barrier, dividendInfo, ratio); t.trade_airbag.HighStrike = GetPrice(t.trade_airbag.HighStrike, dividendInfo, ratio); break; case "累计期权": t.trade_accumulator_option.KOBarrier = GetPrice(t.trade_accumulator_option.KOBarrier, dividendInfo, ratio); break; default: break; } } if (t.TradeType == "累计期权") { var customObservDates = QdpHelper.ParseObservationDate(t.trade_accumulator_option.KOObservationDates); if (customObservDates == null) { customObservDates = Qdp.Pricing.Base.Implementations.CalendarImpl.Get("chn") .BizDaysBetweenDatesExcluStartDay(t.TradeDate.Value, t.ExerciseDate.Value).ToArray(); } var unwindPercent = t.trade_accumulator_option.AccumuTradeAmount / t.trade_accumulator_option.OriginalAccumuTradeAmount; t.trade_accumulator_option.OriginalAccumuTradeAmount = (t.OriginalNotional ?? 0) / (t.CountRatio ?? 1) / customObservDates.Length; t.trade_accumulator_option.AccumuTradeAmount = t.trade_accumulator_option.OriginalAccumuTradeAmount * unwindPercent; } t.DividendDate = settleDate; useSaveTrades.Add(t); } if (t.TradeType == "收益互换") { var originalNotional = 0d; var notional = 0d; if ((t.trade_swap.PayUnderlyingId ?? 0) > 0) { if (t.pay_trade_swap_details?.Count > 0) { double? ratio = 0d; foreach (var item in t.pay_trade_swap_details) { var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode); if (dict.TryGetValue(um.id, out dividendInfo)) { ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null; var unwindNotional = item.OriginalNotional - item.Notional; var OriginalStockEqvNotional = item.SpotPrice * item.OriginalNotional; var StockEqvNotional = item.SpotPrice * item.Notional; item.SpotPrice = GetPrice(item.SpotPrice, dividendInfo, ratio); item.OriginalNotional = OriginalStockEqvNotional / item.SpotPrice; if (t.IsUsePremiumRate.HasValue && t.IsUsePremiumRate.Value) { var settlePercent = (StockEqvNotional / OriginalStockEqvNotional) ?? 0; item.Notional = (item.OriginalNotional * settlePercent) ?? 0; } else { item.Notional = (item.OriginalNotional - unwindNotional) ?? 0; } } } originalNotional = t.pay_trade_swap_details.Sum(O => O.OriginalNotional ?? 0); notional = t.pay_trade_swap_details.Sum(O => O.Notional ?? 0); if (!useSaveTrades.Contains(t)) { t.DividendDate = settleDate; useSaveTrades.Add(t); } } else { originalNotional = t.OriginalNotional ?? 1; notional = t.Notional; var useDividend = false; double? ratio = 0d; var payUm = DataCacheProvider.GetUnderlyingDataSource().GetData(t.trade_swap.PayUnderlyingId.Value); if (payUm.IsBasket() && payUm.SubData != null) { var umchanges = new DbRecordChangesService(this).GetValue(ConsInfoChangeType.Dividend, payUm.id, nameof(underlying_manager.SubData), settleDate); if (umchanges != null) { payUm.SubData = umchanges.FieldValue; } else { useSaveUndedrlyings.Add(payUm); } var data = JsonHelper.Deserialize>(payUm.SubData); var originWeight = data.Sum(O => O.weight); foreach (var item in data) { var tempUm = DataCacheProvider.GetUnderlyingDataSource().GetData(item.code); if (dict.TryGetValue(tempUm?.id ?? 0, out dividendInfo)) { ratio = (dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null) ?? GetRatio(dividendInfo); item.weight *= ratio.Value; useDividend = true; } } payUm.SubData = data.ToJson(); useSaveUndedrlyings.Add(payUm); var newWeight = data.Sum(O => O.weight); ratio = newWeight / originWeight; } else { if (dict.TryGetValue(t.trade_swap.PayUnderlyingId ?? 0, out dividendInfo)) { ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null; useDividend = true; } } if (useDividend) { t.trade_swap.PaySpotPrice = GetPrice(t.trade_swap.PaySpotPrice, dividendInfo, ratio); t.StockEqvNotionalReal = t.StockEqvNotionalReal == 0 ? TradeHelper.GetStockEqvNotionalReal(t.OriginalStockEqvNotional, t.ParticipationRate, t.AnnualizeFactor) : t.StockEqvNotionalReal; t.trade_swap.PayNotional = t.StockEqvNotionalReal / t.trade_swap.PaySpotPrice; //设置交易数量 var underlyingManager = DataCacheProvider.GetUnderlyingDataSource().GetData(t.trade_swap.PayUnderlyingCode); var CountRatio = underlyingManager?.CountRatio ?? 1; t.trade_swap.PayTradeAmount = t.trade_swap.PayNotional / CountRatio; t.DividendDate = settleDate; originalNotional = NumberHelper.Normalize(t.OriginalStockEqvNotional / t.trade_swap.PaySpotPrice); notional = NumberHelper.Normalize(t.StockEqvNotional / t.trade_swap.PaySpotPrice); if (!useSaveTrades.Contains(t)) { t.DividendDate = settleDate; useSaveTrades.Add(t); } } } } if ((t.trade_swap.GetUnderlyingId ?? 0) > 0) { if (t.get_trade_swap_details?.Count > 0) { double? ratio = 0d; foreach (var item in t.get_trade_swap_details) { var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode); if (dict.TryGetValue(um.id, out dividendInfo)) { ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null; var unwindNotional = item.OriginalNotional - item.Notional; var OriginalStockEqvNotional = item.SpotPrice * item.OriginalNotional; var StockEqvNotional = item.SpotPrice * item.Notional; item.SpotPrice = GetPrice(item.SpotPrice, dividendInfo, ratio); item.OriginalNotional = OriginalStockEqvNotional / item.SpotPrice; if (t.IsUsePremiumRate.HasValue && t.IsUsePremiumRate.Value) { var settlePercent = (StockEqvNotional / OriginalStockEqvNotional) ?? 0; item.Notional = (item.OriginalNotional * settlePercent) ?? 0; } else { item.Notional = (item.OriginalNotional - unwindNotional) ?? 0; } } } originalNotional = t.get_trade_swap_details.Sum(O => O.OriginalNotional ?? 0); notional = t.get_trade_swap_details.Sum(O => O.Notional ?? 0); if (!useSaveTrades.Contains(t)) { t.DividendDate = settleDate; useSaveTrades.Add(t); } } else { originalNotional = t.OriginalNotional ?? 1; notional = t.Notional; double? ratio = 0d; var useDividend = false; var getUm = DataCacheProvider.GetUnderlyingDataSource().GetData(t.trade_swap.GetUnderlyingId.Value); if (getUm.IsBasket() && getUm.SubData != null) { var umchanges = new DbRecordChangesService(this).GetValue(ConsInfoChangeType.Dividend, getUm.id, nameof(underlying_manager.SubData), settleDate); if (umchanges != null) { getUm.SubData = umchanges.FieldValue; } else { useSaveUndedrlyings.Add(getUm); } var data = JsonHelper.Deserialize>(getUm.SubData); var originWeight = data.Sum(O => O.weight); foreach (var item in data) { var tempUm = DataCacheProvider.GetUnderlyingDataSource().GetData(item.code); if (dict.TryGetValue(tempUm?.id ?? 0, out dividendInfo)) { ratio = (dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null) ?? GetRatio(dividendInfo); item.weight *= ratio.Value; useDividend = true; } } getUm.SubData = data.ToJson(); var newWeight = data.Sum(O => O.weight); ratio = newWeight / originWeight; } else { if (dict.TryGetValue(t.trade_swap.GetUnderlyingId ?? 0, out dividendInfo)) { ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null; useDividend = true; } } if (useDividend) { t.trade_swap.GetSpotPrice = GetPrice(t.trade_swap.GetSpotPrice, dividendInfo, ratio); t.StockEqvNotionalReal = t.StockEqvNotionalReal == 0 ? TradeHelper.GetStockEqvNotionalReal(t.OriginalStockEqvNotional, t.ParticipationRate, t.AnnualizeFactor) : t.StockEqvNotionalReal; t.trade_swap.GetNotional = t.StockEqvNotionalReal / t.trade_swap.GetSpotPrice; //设置交易数量 var underlyingManager = DataCacheProvider.GetUnderlyingDataSource().GetData(t.trade_swap.GetUnderlyingCode); var CountRatio = underlyingManager?.CountRatio ?? 1; t.trade_swap.GetTradeAmount = t.trade_swap.GetNotional / CountRatio; t.DividendDate = settleDate; originalNotional = NumberHelper.Normalize(t.OriginalStockEqvNotional / t.trade_swap.GetSpotPrice); notional = NumberHelper.Normalize(t.StockEqvNotional / t.trade_swap.GetSpotPrice); if (!useSaveTrades.Contains(t)) { t.DividendDate = settleDate; useSaveTrades.Add(t); } } } } t.OriginalNotional = originalNotional; t.TradeOriginalAmount = originalNotional; t.Notional = notional; } bodTrade.AssetId = t.AssetId; bodTrade.ClientId = t.ClientId; bodTrade.OptDate = DateTime.Now; bodTrade.ParentTradeId = t.ParentTradeId; bodTrade.TradeId = t.id; bodTrade.TradeNumber = t.TradeNumber; bodTrade.TradeStatus = t.TradeStatus; bodTrade.TradeType = t.TradeType; bodTrade.UnderlyingCode = t.UnderlyingCode; bodTrade.UnderlyingId = t.UnderlyingId; bodTrade.ValueDate = settleDate; bodTrade.TradeJson = TradeHelper2.Serialize(t, settleDate); result.Add(bodTrade); } return result; } /// /// /// public static List GetDividendChanges(trade trade, trade NewValue) { TradeChanges compar(double? originValue, double? newValue, params string[] fieldName) { TradeChanges tc = null; if ((originValue == null && newValue != null) || (originValue != null && newValue == null) || originValue != newValue || (ConsGlobal.IgnoreTSV((originValue ?? 0) - (newValue ?? 0)) != 0)) { tc = new TradeChanges { ChangeType = ConsInfoChangeType.Dividend, RecordId = trade.id, FieldName = string.Join(".", fieldName), FieldValue = originValue?.ToString() ?? "", NewValue = newValue?.ToString() ?? "", OptDate = NewValue.DividendDate, Update = DateTime.Now }; } return tc; } TradeChanges comparStr(string originValue, string newValue, params string[] fieldName) { TradeChanges tc = null; if ((originValue == null && newValue != null) || (originValue != null && newValue == null) || originValue != newValue) { tc = new TradeChanges { ChangeType = ConsInfoChangeType.Dividend, RecordId = trade.id, FieldName = string.Join(".", fieldName), FieldValue = originValue ?? "", NewValue = newValue ?? "", OptDate = NewValue.DividendDate, Update = DateTime.Now }; } return tc; } var list = new List { compar(trade.SpotPrice, NewValue.SpotPrice, nameof(trade.SpotPrice)), compar(trade.OriginalNotional, NewValue.OriginalNotional, nameof(trade.OriginalNotional)), compar(trade.TradeOriginalAmount ?? trade.OriginalNotional, NewValue.TradeOriginalAmount, nameof(trade.TradeOriginalAmount)), compar(trade.Notional, NewValue.Notional, nameof(trade.Notional)), compar(trade.TradeAmount, NewValue.TradeAmount, nameof(trade.TradeAmount)), compar(trade.TradeSinglePrice, NewValue.TradeSinglePrice, nameof(trade.TradeSinglePrice)), compar(trade.Strike, NewValue.Strike, nameof(trade.Strike)) }; switch (trade.TradeType) { case "障碍期权": list.Add(compar(trade.trade_barrier_option.BarrierPrice, NewValue.trade_barrier_option.BarrierPrice, nameof(trade.trade_barrier_option), nameof(trade.trade_barrier_option.BarrierPrice))); list.Add(compar(trade.trade_barrier_option.UpperBarrierPrice, NewValue.trade_barrier_option.UpperBarrierPrice, nameof(trade.trade_barrier_option), nameof(trade.trade_barrier_option.UpperBarrierPrice))); break; case "彩虹期权": list.Add(compar(trade.trade_rainbow_option.SpotPrice1, NewValue.trade_rainbow_option.SpotPrice1, nameof(trade.trade_rainbow_option), nameof(trade.trade_rainbow_option.SpotPrice1))); list.Add(compar(trade.trade_rainbow_option.SpotPrice2, NewValue.trade_rainbow_option.SpotPrice2, nameof(trade.trade_rainbow_option), nameof(trade.trade_rainbow_option.SpotPrice2))); list.Add(compar(trade.trade_rainbow_option.Strike, NewValue.trade_rainbow_option.Strike, nameof(trade.trade_rainbow_option), nameof(trade.trade_rainbow_option.Strike))); list.Add(compar(trade.trade_rainbow_option.Strike2, NewValue.trade_rainbow_option.Strike2, nameof(trade.trade_rainbow_option), nameof(trade.trade_rainbow_option.Strike2))); break; case "凤凰期权": list.Add(compar(trade.trade_autocall.KIBarrier, NewValue.trade_autocall.KIBarrier, nameof(trade.trade_autocall), nameof(trade.trade_autocall.KIBarrier))); list.Add(compar(trade.trade_autocall.KOBarrier, NewValue.trade_autocall.KOBarrier, nameof(trade.trade_autocall), nameof(trade.trade_autocall.KOBarrier))); list.Add(compar(trade.trade_autocall.CouponBarrier, NewValue.trade_autocall.CouponBarrier, nameof(trade.trade_autocall), nameof(trade.trade_autocall.CouponBarrier))); list.Add(compar(trade.trade_autocall.SpreadStrike, NewValue.trade_autocall.SpreadStrike, nameof(trade.trade_autocall), nameof(trade.trade_autocall.SpreadStrike))); list.Add(compar(trade.trade_autocall.SpreadStrike1, NewValue.trade_autocall.SpreadStrike, nameof(trade.trade_autocall), nameof(trade.trade_autocall.SpreadStrike1))); list.Add(comparStr(trade.trade_autocall.KOObservationDates, NewValue.trade_autocall.KOObservationDates, nameof(trade.trade_autocall), nameof(trade.trade_autocall.KOObservationDates))); break; case "双鲨期权": list.Add(compar(trade.trade_double_sharkfin_option.BarrierHigh, NewValue.trade_double_sharkfin_option.BarrierHigh, nameof(trade.trade_double_sharkfin_option), nameof(trade.trade_double_sharkfin_option.BarrierHigh))); list.Add(compar(trade.trade_double_sharkfin_option.BarrierLow, NewValue.trade_double_sharkfin_option.BarrierLow, nameof(trade.trade_double_sharkfin_option), nameof(trade.trade_double_sharkfin_option.BarrierLow))); list.Add(compar(trade.trade_double_sharkfin_option.StrikeHigh, NewValue.trade_double_sharkfin_option.StrikeHigh, nameof(trade.trade_double_sharkfin_option), nameof(trade.trade_double_sharkfin_option.StrikeHigh))); list.Add(compar(trade.trade_double_sharkfin_option.StrikeLow, NewValue.trade_double_sharkfin_option.StrikeLow, nameof(trade.trade_double_sharkfin_option), nameof(trade.trade_double_sharkfin_option.StrikeLow))); break; case "区间累积期权": list.Add(compar(trade.trade_rangeaccrual.LowerRange, NewValue.trade_rangeaccrual.LowerRange, nameof(trade.trade_rangeaccrual), nameof(trade.trade_rangeaccrual.LowerRange))); list.Add(compar(trade.trade_rangeaccrual.UpperRange, NewValue.trade_rangeaccrual.UpperRange, nameof(trade.trade_rangeaccrual), nameof(trade.trade_rangeaccrual.UpperRange))); break; case "雪球期权": list.Add(compar(trade.trade_snowball.KIBarrier, NewValue.trade_snowball.KIBarrier, nameof(trade.trade_snowball), nameof(trade.trade_snowball.KIBarrier))); list.Add(compar(trade.trade_snowball.KOBarrier, NewValue.trade_snowball.KOBarrier, nameof(trade.trade_snowball), nameof(trade.trade_snowball.KOBarrier))); list.Add(compar(trade.trade_snowball.SpreadStrikeAtKO, NewValue.trade_snowball.SpreadStrikeAtKO, nameof(trade.trade_snowball), nameof(trade.trade_snowball.SpreadStrikeAtKO))); list.Add(compar(trade.trade_snowball.SpreadStrikeAtKO1, NewValue.trade_snowball.SpreadStrikeAtKO1, nameof(trade.trade_snowball), nameof(trade.trade_snowball.SpreadStrikeAtKO1))); list.Add(compar(trade.trade_snowball.SpreadStrikeAtMaturity, NewValue.trade_snowball.SpreadStrikeAtMaturity, nameof(trade.trade_snowball), nameof(trade.trade_snowball.SpreadStrikeAtMaturity))); list.Add(compar(trade.trade_snowball.SpreadStrikeAtMaturity1, NewValue.trade_snowball.SpreadStrikeAtMaturity1, nameof(trade.trade_snowball), nameof(trade.trade_snowball.SpreadStrikeAtMaturity1))); list.Add(comparStr(trade.trade_snowball.KOObservationDates, NewValue.trade_snowball.KOObservationDates, nameof(trade.trade_snowball), nameof(trade.trade_snowball.KOObservationDates))); break; case "气囊结构": list.Add(compar(trade.trade_airbag.Barrier, NewValue.trade_airbag.Barrier, nameof(trade.trade_airbag), nameof(trade.trade_airbag.Barrier))); list.Add(compar(trade.trade_airbag.HighStrike, NewValue.trade_airbag.HighStrike, nameof(trade.trade_airbag), nameof(trade.trade_airbag.HighStrike))); break; case "收益互换": if (trade.trade_swap != null) { list.Add(compar(trade.trade_swap.PaySpotPrice, NewValue.trade_swap.PaySpotPrice, nameof(trade.trade_swap), nameof(trade.trade_swap.PaySpotPrice))); list.Add(compar(trade.trade_swap.PayNotional, NewValue.trade_swap.PayNotional, nameof(trade.trade_swap), nameof(trade.trade_swap.PayNotional))); list.Add(compar(trade.trade_swap.PayTradeAmount, NewValue.trade_swap.PayTradeAmount, nameof(trade.trade_swap), nameof(trade.trade_swap.PayTradeAmount))); if (trade.pay_trade_swap_details != null) { foreach (var item in trade.pay_trade_swap_details) { if (!ConsGlobal.IsValid(item.ValidState)) { continue; } var newDetail = NewValue.pay_trade_swap_details.Find(O => O.id == item.id); list.Add(compar(item.SpotPrice, newDetail.SpotPrice, $"{nameof(trade.pay_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.SpotPrice))); list.Add(compar(item.OriginalNotional, newDetail.OriginalNotional, $"{nameof(trade.pay_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.OriginalNotional))); list.Add(compar(item.Notional, newDetail.Notional, $"{nameof(trade.pay_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.Notional))); } } list.Add(compar(trade.trade_swap.GetSpotPrice, NewValue.trade_swap.GetSpotPrice, nameof(trade.trade_swap), nameof(trade.trade_swap.GetSpotPrice))); list.Add(compar(trade.trade_swap.GetNotional, NewValue.trade_swap.GetNotional, nameof(trade.trade_swap), nameof(trade.trade_swap.GetNotional))); list.Add(compar(trade.trade_swap.GetTradeAmount, NewValue.trade_swap.GetTradeAmount, nameof(trade.trade_swap), nameof(trade.trade_swap.GetTradeAmount))); if (trade.get_trade_swap_details != null) { foreach (var item in trade.get_trade_swap_details) { if (!ConsGlobal.IsValid(item.ValidState)) { continue; } var newDetail = NewValue.get_trade_swap_details.Find(O => O.id == item.id); list.Add(compar(item.SpotPrice, newDetail.SpotPrice, $"{nameof(trade.get_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.SpotPrice))); list.Add(compar(item.OriginalNotional, newDetail.OriginalNotional, $"{nameof(trade.get_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.OriginalNotional))); list.Add(compar(item.Notional, newDetail.Notional, $"{nameof(trade.get_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.Notional))); } } } break; case "累计期权": list.Add(compar(trade.trade_accumulator_option.KOBarrier, NewValue.trade_accumulator_option.AccumuTradeAmount, nameof(trade.trade_accumulator_option), nameof(trade.trade_accumulator_option.KOBarrier))); list.Add(compar(trade.trade_accumulator_option.AccumuTradeAmount, NewValue.trade_accumulator_option.AccumuTradeAmount, nameof(trade.trade_accumulator_option), nameof(trade.trade_accumulator_option.AccumuTradeAmount))); list.Add(compar(trade.trade_accumulator_option.OriginalAccumuTradeAmount, NewValue.trade_accumulator_option.OriginalAccumuTradeAmount, nameof(trade.trade_accumulator_option), nameof(trade.trade_accumulator_option.OriginalAccumuTradeAmount))); break; default: break; } list.RemoveAll(O => O == null); return list; } /// /// /// public static void SetDividendTradeData(trade trade, trade NewValue) { trade.SpotPrice = NewValue.SpotPrice; trade.OriginalNotional = NewValue.OriginalNotional; trade.OriginalStockEqvNotional = NewValue.OriginalStockEqvNotional; trade.StockEqvNotionalReal = NewValue.StockEqvNotionalReal; trade.StockEqvNotional = NewValue.StockEqvNotional; trade.Notional = NewValue.Notional; trade.TradeSinglePrice = TradeHelper.GetTradeSinglePriceByTradePrice(NewValue.TradePrice, NewValue.OriginalNotional, NewValue.PrincipalSum(), NewValue.BuySell, NewValue.TradeType, true); trade.TradeOriginalAmount = NewValue.TradeOriginalAmount; trade.TradeAmount = NewValue.TradeAmount; trade.Strike = NewValue.Strike; trade.DividendDate = NewValue.DividendDate; switch (trade.TradeType) { case "亚式期权": //获取fixings的时候,函数内部处理除权除息逻辑; break; case "障碍期权": trade.trade_barrier_option.BarrierPrice = NewValue.trade_barrier_option.BarrierPrice; trade.trade_barrier_option.UpperBarrierPrice = NewValue.trade_barrier_option.UpperBarrierPrice; break; case "彩虹期权": trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1; trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2; trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike; trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2; break; case "凤凰期权": trade.trade_autocall.KIBarrier = NewValue.trade_autocall.KIBarrier; trade.trade_autocall.KOBarrier = NewValue.trade_autocall.KOBarrier; trade.trade_autocall.CouponBarrier = NewValue.trade_autocall.CouponBarrier; trade.trade_autocall.SpreadStrike = NewValue.trade_autocall.SpreadStrike; trade.trade_autocall.SpreadStrike1 = NewValue.trade_autocall.SpreadStrike1; trade.trade_autocall.KOObservationDates = NewValue.trade_autocall.KOObservationDates; break; case "双鲨期权": trade.trade_double_sharkfin_option.BarrierHigh = NewValue.trade_double_sharkfin_option.BarrierHigh; trade.trade_double_sharkfin_option.BarrierLow = NewValue.trade_double_sharkfin_option.BarrierLow; trade.trade_double_sharkfin_option.StrikeHigh = NewValue.trade_double_sharkfin_option.StrikeHigh; trade.trade_double_sharkfin_option.StrikeLow = NewValue.trade_double_sharkfin_option.StrikeLow; break; case "区间累积期权": trade.trade_rangeaccrual.LowerRange = NewValue.trade_rangeaccrual.LowerRange; trade.trade_rangeaccrual.UpperRange = NewValue.trade_rangeaccrual.UpperRange; break; case "雪球期权": trade.trade_snowball.KIBarrier = NewValue.trade_snowball.KIBarrier; trade.trade_snowball.KOBarrier = NewValue.trade_snowball.KOBarrier; trade.trade_snowball.SpreadStrikeAtKO = NewValue.trade_snowball.SpreadStrikeAtKO; trade.trade_snowball.SpreadStrikeAtKO1 = NewValue.trade_snowball.SpreadStrikeAtKO1; trade.trade_snowball.SpreadStrikeAtMaturity = NewValue.trade_snowball.SpreadStrikeAtMaturity; trade.trade_snowball.SpreadStrikeAtMaturity1 = NewValue.trade_snowball.SpreadStrikeAtMaturity1; trade.trade_snowball.KOObservationDates = NewValue.trade_snowball.KOObservationDates; break; case "气囊结构": trade.trade_airbag.Barrier = NewValue.trade_airbag.Barrier; trade.trade_airbag.HighStrike = NewValue.trade_airbag.HighStrike; break; case "收益互换": if (trade.trade_swap != null) { trade.trade_swap.PaySpotPrice = NewValue.trade_swap.PaySpotPrice; trade.trade_swap.PayNotional = NewValue.trade_swap.PayNotional; trade.trade_swap.PayTradeAmount = NewValue.trade_swap.PayTradeAmount; if (trade.pay_trade_swap_details != null) { foreach (var item in trade.pay_trade_swap_details) { if (!ConsGlobal.IsValid(item.ValidState)) { continue; } var newDetail = NewValue.pay_trade_swap_details.Find(O => O.id == item.id); item.SpotPrice = newDetail.SpotPrice; item.OriginalNotional = newDetail.OriginalNotional; item.Notional = newDetail.Notional; } } trade.trade_swap.GetSpotPrice = NewValue.trade_swap.GetSpotPrice; trade.trade_swap.GetNotional = NewValue.trade_swap.GetNotional; trade.trade_swap.GetTradeAmount = NewValue.trade_swap.GetTradeAmount; if (trade.get_trade_swap_details != null) { foreach (var item in trade.get_trade_swap_details) { if (!ConsGlobal.IsValid(item.ValidState)) { continue; } var newDetail = NewValue.get_trade_swap_details.Find(O => O.id == item.id); item.SpotPrice = newDetail.SpotPrice; item.OriginalNotional = newDetail.OriginalNotional; item.Notional = newDetail.Notional; } } } break; case "累计期权": trade.trade_accumulator_option.KOBarrier = NewValue.trade_accumulator_option.KOBarrier; trade.trade_accumulator_option.AccumuTradeAmount = NewValue.trade_accumulator_option.AccumuTradeAmount; trade.trade_accumulator_option.OriginalAccumuTradeAmount = NewValue.trade_accumulator_option.OriginalAccumuTradeAmount; break; default: break; } } /// /// 获取除权价 /// /// 除权日收盘价 /// 除权除息配置 /// 除权除息系数 /// public double? GetPrice(double? closePrice, ex_dividend_info info, double? overrideDividendRatio = null) { if (!closePrice.HasValue) { return closePrice; } return GetPrice(closePrice.Value, info, overrideDividendRatio); } /// /// 获取除权价 /// /// 除权日收盘价 /// 除权除息配置 /// public double GetPrice(double price, ex_dividend_info info, double? overrideDividendRatio = null) { if (price == 0) { return 0; } var ratio = overrideDividendRatio != null ? overrideDividendRatio.Value : GetRatio(info); double? result = price / ratio; return Math.Round(result ?? 0, 4, MidpointRounding.AwayFromZero); } /// /// 获取除权除息系数 /// /// /// public double GetRatio(ex_dividend_info info) { var dividendRate = valuedateBLL.SystemDate.DividendRate / 100; var closePrice = new EodPriceProvider(info.ExDividendDate.Value).GetPrice(info.UnderlyingCode, SettlementTypeEnum.ClosePrice); var cDivdPrice = (closePrice * 10.0 - (info.GiveCashAmount * (1 - dividendRate)) + info.RationedSharesAmount * info.RationedSharesPrice) / (10 + info.GiveShareAmount + info.RationedSharesAmount); return closePrice / cDivdPrice; } /// /// 获取除权后持仓量 /// /// 持仓数量 /// 除权除息配置 /// public double? GetPositionAmount(double? amount, ex_dividend_info info) { if (!amount.HasValue) { return amount; } return GetPositionAmount(amount.Value, info); } /// /// 获取除权后持仓量 /// /// 持仓数量 /// 除权除息配置 /// public double GetPositionAmount(double amount, ex_dividend_info info) { double? result = amount * (1 + info.GiveShareAmount / 10.0); return Math.Round(result ?? 0, 12); } public IQueryable GetExDividendQuery(DateTime valueDate) { return DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate == valueDate); } public IQueryable GetExDividendQuery(DateTime dateStart, DateTime dateEnd) { return DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate >= dateStart && O.ExDividendDate <= dateEnd); } public IEnumerable GetExDividends(DateTime valueDate, params int[] underlyingIds) { var query = DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate == valueDate); if (underlyingIds != null && underlyingIds.Any()) { query = query.Where(n => underlyingIds.Contains(n.UnderlyingId)); } return query.ToArray(); } public IQueryable GetExDividendInfos(string underlyingCode) { if (string.IsNullOrWhiteSpace(underlyingCode)) { throw new ArgumentNullException(nameof(underlyingCode)); } return from di in DbContext.ex_dividend_info join un in DbContext.underlying_manager on di.UnderlyingId equals un.id where di.ValidStatus && un.UnderlyingCode == underlyingCode select di; } public void ImportDividendInfos(Stream stream) { var dt = new ExcelHelper().ExcelToDataTable(stream, null, true); if (!dt.Columns.Contains("股票代码") || !dt.Columns.Contains("股权登记日")) { throw new ServiceException("请使用正确的模板上传"); } var dict = new Dictionary(); for (var i = 0; i < dt.Rows.Count; i++) { var info = new ex_dividend_info { UnderlyingCode = dt.Rows[i]["股票代码"]?.ToString(), ExDividendDate = DateTime.TryParse(getColValueFromTable(dt.Rows[i], "股权登记日"), out var date) ? date : DateTime.MinValue, GiveCashAmount = double.TryParse(getColValueFromTable(dt.Rows[i], "派息金额"), out var value) ? value : 0, GiveShareAmount = double.TryParse(getColValueFromTable(dt.Rows[i], "送股股数"), out value) ? value : 0, RationedSharesAmount = double.TryParse(getColValueFromTable(dt.Rows[i], "配股股数"), out value) ? value : 0, RationedSharesPrice = double.TryParse(getColValueFromTable(dt.Rows[i], "配股股价"), out value) ? value : 0, OptId = OptUser.UserId, OptName = OptUser.UserName, OptDate = DateTime.Now }; if (string.IsNullOrWhiteSpace(info.UnderlyingCode) && info.ExDividendDate < DateTime.Now.AddYears(10)) { continue; } if (string.IsNullOrWhiteSpace(info.UnderlyingCode)) { throw new ServiceException($"第{i + 1}行股票代码不应为空"); } if (info.ExDividendDate < DateTime.Now.AddYears(-10)) { throw new ServiceException($"第{i + 1}行股权登记日不正确"); } dict[$"{info.ExDividendDate}{info.UnderlyingCode}"] = info; } if (!AddDividendInfos(dict.Values, out var errMsg)) { throw new ServiceException(errMsg); } } private string getColValueFromTable(DataRow dr, string colName) { if (dr.Table.Columns.Contains(colName)) { return dr[colName].ToString(); } return ""; } public bool AddDividendInfos(IEnumerable infos, out string errMsg) { try { var keys = infos.Select(O => $"{O.ExDividendDate?.ToString("yyyy-MM-dd")}{O.UnderlyingCode}"); var ids = infos.Select(O => O.id).ToHashSet(); var data = from dividendDb in DbContext.ex_dividend_info.Where(O => keys.Contains(O.ExDividendDate + O.UnderlyingCode) && O.ValidStatus) where !ids.Contains(dividendDb.id) select dividendDb; if (data.Any()) { var dd = data.Select(O => O.UnderlyingCode + "_" + O.ExDividendDate).ToArray(); errMsg = string.Join(",", dd) + "已存在除息信息,请修改原数据"; return false; } var basketList = DataCacheProvider.GetUnderlyingDataSource() .AsQueryable().Where(O => O.IsBasket() && O.SubData != null) .Select(O => new { O.UnderlyingCode, O.SubData }); IEnumerable priceList = null; foreach (var item in infos) { var underlying = underlying_managerBLL.GetByCode(item.UnderlyingCode); if (underlying == null) { errMsg = $"{item.UnderlyingCode} 标的信息不存在"; return false; } item.UnderlyingId = underlying.id; item.GiveCashAmount = item.GiveCashAmount.FormatValue(6); item.RationedSharesAmount = item.RationedSharesAmount.FormatValue(6); item.RationedSharesPrice = item.RationedSharesPrice.FormatValue(6); item.GiveShareAmount = item.GiveShareAmount.FormatValue(6); item.ValidStatus = true; item.OptId = OptUser.UserId; item.OptName = OptUser.UserName; item.OptDate = DateTime.Now; var dividend = item.id > 0 ? DbContext.ex_dividend_info.Where(O => O.id == item.id).FirstOrDefault() : null; if (dividend == null) { DbContext.ex_dividend_info.Add(item); } else { if (checkDividendInfoExecuteStatus(dividend)) { errMsg = $"{dividend.UnderlyingCode} {dividend.ExDividendDate?.ToString("yyyy-MM-dd")}除权信息保存失败,该信息已被执行,不允许修改!"; return false; } dividend.UnderlyingCode = item.UnderlyingCode; dividend.UnderlyingId = item.UnderlyingId; dividend.ExDividendDate = item.ExDividendDate; dividend.GiveCashAmount = item.GiveCashAmount; dividend.RationedSharesAmount = item.RationedSharesAmount; dividend.RationedSharesPrice = item.RationedSharesPrice; dividend.GiveShareAmount = item.GiveShareAmount; dividend.ValidStatus = item.ValidStatus; dividend.OptId = item.OptId; dividend.OptName = item.OptName; dividend.OptDate = item.OptDate; } if (!basketList.Any()) { continue; } var codes = basketList.Where(O => O.SubData.Contains(item.UnderlyingCode)).Select(O => O.UnderlyingCode); if (!codes.Any()) { continue; } var removePriceList = DbContext.eod_stock_price.Where(O => codes.Contains(O.UnderlyingCode) && O.ValueDate > item.ExDividendDate); if (!removePriceList.Any()) { continue; } DbContext.eod_stock_price.RemoveRange(removePriceList); } if (priceList != null) { DbContext.eod_stock_price.RemoveRange(priceList); } DbContext.SaveChanges(); errMsg = ""; return true; } catch (Exception ex) { errMsg = "保存失败"; LogFactory.GetLogger().Error(ex); } return false; } /// /// 检查除权除息记录有没有被执行 /// /// /// public bool checkDividendInfoExecuteStatus(ex_dividend_info info) { var eodStatus = DbContext.eodStatus.Where(O => O.ValueDate == info.ExDividendDate && O.OptDate > info.OptDate).Any(); if (eodStatus) { //查询标的对应交易是否执行过收盘操作; var tradeQuery = from t in DbContext.trade.Where(O => O.UnderlyingCode == info.UnderlyingCode && O.TradeDate <= info.ExDividendDate && O.ExerciseDate >= info.ExDividendDate && O.DividendDate >= O.TradeDate) join et in DbContext.eod_trade.Where(O => ConsTrade.LiveTradeStatusList.Contains(O.TradeStatus)) on new { t.id, ValueDate = t.TradeDate.Value } equals new { id = et.TradeId, et.ValueDate } select et.id; if (tradeQuery.Any()) { return true; } //查询篮子标的对应交易是否执行过收盘操作; var umList = DataCacheProvider.GetUnderlyingDataSource().AsQueryable(O => O.IsBasket() && O.SubData != null && O.SubData.Contains(info.UnderlyingCode)).Select(O => O.UnderlyingCode).ToArray(); tradeQuery = from t in DbContext.trade.Where(O => umList.Contains(O.UnderlyingCode) && O.TradeDate <= info.ExDividendDate && O.ExerciseDate >= info.ExDividendDate && O.DividendDate >= O.TradeDate) join et in DbContext.eod_trade.Where(O => ConsTrade.LiveTradeStatusList.Contains(O.TradeStatus)) on new { t.id, ValueDate = t.TradeDate.Value } equals new { id = et.TradeId, et.ValueDate } select et.id; if (tradeQuery.Any()) { return true; } //查询多标的对应交易是否执行过收盘操作; tradeQuery = from ts in DbContext.trade_swap_detail.Where(O => O.UnderlyingCode == info.UnderlyingCode) join t in DbContext.trade.Where(O => O.TradeDate <= info.ExDividendDate && O.ExerciseDate >= info.ExDividendDate && O.DividendDate >= O.TradeDate) on ts.TradeId equals t.id join et in DbContext.eod_trade.Where(O => ConsTrade.LiveTradeStatusList.Contains(O.TradeStatus)) on new { t.id, ValueDate = t.TradeDate.Value } equals new { id = et.TradeId, et.ValueDate } select et.id; if (tradeQuery.Any()) { return true; } } return false; } public List QueryDividendTrade(DividendTradeReq req) { TradeChanges changes = null; var result = new List(); var predicate = PredicateBuilder.Create(O => O.ValidState != "InValid" && ConsTrade.TradeStatusAfterConfirmed.Contains(O.TradeStatus) && O.TradeType != "结构化交易"); if (!string.IsNullOrWhiteSpace(req.TradeNumber)) { predicate = predicate.And(O => O.TradeNumber == req.TradeNumber); } if (req.ClientIds != null && req.ClientIds.Any(O => O > 0)) { predicate = predicate.And(O => req.ClientIds.Contains(O.ClientId)); } if (req.AssetUnitIds != null && req.AssetUnitIds.Any(O => O > 0)) { predicate = predicate.And(O => req.AssetUnitIds.Contains(O.AssetId)); } if (req.TradeTypes != null && req.TradeTypes.Any(O => !string.IsNullOrWhiteSpace(O))) { predicate = predicate.And(O => req.TradeTypes.Contains(O.TradeType) || req.TradeTypes.Contains(O.StructureType)); } if (req.UnderlyingIds != null && req.UnderlyingIds.Any(O => O > 0)) { predicate = predicate.And(O => req.UnderlyingIds.Contains(O.UnderlyingId)); } if (req.TraderIds != null && req.TraderIds.Any(O => O > 0)) { predicate = predicate.And(O => req.TraderIds.Contains(O.TraderId)); } if (req.TradeDateStart > DateTime.MinValue) { predicate = predicate.And(O => req.TradeDateStart <= O.TradeDate); } if (req.TradeDateEnd > DateTime.MinValue) { predicate = predicate.And(O => req.TradeDateEnd >= O.TradeDate); } if (req.ExerciseDateStart > DateTime.MinValue) { predicate = predicate.And(O => req.ExerciseDateStart <= O.ExerciseDate); } if (req.ExerciseDateEnd > DateTime.MinValue) { predicate = predicate.And(O => req.ExerciseDateEnd >= O.ExerciseDate); } var query = DbContext.trade.Where(predicate); var tradeInfos = (from diInfo in GetExDividendQuery(req.DividendDate, req.DividendDateEnd.Value) join t in query on diInfo.UnderlyingCode equals t.UnderlyingCode where t.TradeDate <= diInfo.ExDividendDate && t.ValidState != "InValid" && (ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) || (ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) && ((t.UnWindDate == null && t.ExerciseDate > diInfo.ExDividendDate) || (t.UnWindDate != null && t.UnWindDate > diInfo.ExDividendDate)))) select new { diInfo, t })//单标的 .Concat(from diInfo in GetExDividendQuery(req.DividendDate, req.DividendDateEnd.Value) join ts in DbContext.trade_swap_detail on diInfo.UnderlyingCode equals ts.UnderlyingCode join t in query on ts.TradeId equals t.id where t.TradeDate <= diInfo.ExDividendDate && t.ValidState != "InValid" && (ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) || (ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) && ((t.UnWindDate == null && t.ExerciseDate > diInfo.ExDividendDate) || (t.UnWindDate != null && t.UnWindDate > diInfo.ExDividendDate)))) select new { diInfo, t })//多标的 .ToList(); //篮子标的 var dividendDict = GetExDividendQuery(req.DividendDate, req.DividendDateEnd.Value).ToDictionary(K => K.UnderlyingCode, V => V); var umList = DbContext.underlying_manager.Where(O => O.CommodityCode == "篮子标的" && O.SubData != null).ToList(); var codeDict = new Dictionary(); foreach (var item in dividendDict) { var ums = umList.Where(O => O.SubData.Contains(item.Key)).ToList(); ums.ForEach(O => codeDict[O.UnderlyingCode.ToLower()] = item.Value); } var tempTrade = query.Where(O => codeDict.Keys.Contains(O.UnderlyingCode)); foreach (var t in tempTrade) { var code = t.UnderlyingCode.ToLower(); var diInfo = codeDict.ContainsKey(code) ? codeDict[code] : null; if (diInfo == null) { continue; } if (t.TradeDate <= diInfo.ExDividendDate && ((t.UnWindDate == null && t.ExerciseDate > diInfo.ExDividendDate) || (t.UnWindDate != null && t.UnWindDate > diInfo.ExDividendDate))) { tradeInfos.Add(new { diInfo, t }); } } var ids = tradeInfos.Select(O => O.t.id).ToArray(); var subTrades = tradeInfos.Select(O => O.t).ToList(); tradeBLL.SetFieldsByTradeType(subTrades); var changeService = new DbRecordChangesService(this); var tradeChangeDict = changeService.GetValue(ConsInfoChangeType.Dividend, ids, req.DividendDate).GroupBy(O => O.RecordId).ToDictionary(K => K.Key, V => V.ToList()); var ratioDict = changeService.GetValue( ConsInfoChangeType.UserChange, ids, nameof(trade.DividendRatio), req.DividendDate).ToDictionary(K => K.RecordId, V => { return double.TryParse(V.NewValue, out var temp) ? (double?)temp : null; }); foreach (var item in tradeInfos) { var info = new DividendTrade { TradeId = item.t.id, EncryptId = item.t.EncryptId, TradeNumber = item.t.TradeNumber, ExDividendDate = item.diInfo.ExDividendDate.Value, DividendStatus = tradeChangeDict.ContainsKey(item.t.id), TradeStatus = item.t.TradeStatus, ClientName = item.t.ClientName, TradeType = item.t.StructureType ?? item.t.TradeType, TradeDate = item.t.TradeDate.Value, ExerciseDate = item.t.ExerciseDate.Value, UnderlyingCode = item.t.UnderlyingCode, DividendRatio = ratioDict.ContainsKey(item.t.id) ? ratioDict[item.t.id].Value : double.NaN, trade = item.t }; var tradeFullInfo = subTrades.Where(O => O.id == item.t.id).FirstOrDefault(); if (info.DividendStatus) { changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == nameof(trade.OriginalStockEqvNotional)).FirstOrDefault(); info.StockEqvNotional = TryParseDouble(changes?.NewValue, item.t.OriginalStockEqvNotional ?? double.NaN); info.StockEqvNotional_After = TryParseDouble(changes?.FieldValue, double.NaN); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == nameof(trade.SpotPrice)).FirstOrDefault(); info.SpotPrice = TryParseDouble(changes?.NewValue, info.SpotPrice); info.SpotPrice_After = TryParseDouble(changes?.FieldValue, double.NaN); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == nameof(trade.TradeOriginalAmount)).FirstOrDefault(); info.TradeOriginalAmount = TryParseDouble(changes?.NewValue, info.TradeOriginalAmount); info.TradeOriginalAmount_After = TryParseDouble(changes?.FieldValue, double.NaN); if (item.t.IsMoneynessOptionData) { var spotPrice = info.SpotPrice_After; info.Strike = info.SpotPrice * (item.t.Strike ?? 1); info.Strike_After = spotPrice * (item.t.Strike ?? 1); switch (item.t.TradeType) { case "障碍期权": info.Barrier = info.SpotPrice * (tradeFullInfo.trade_barrier_option.BarrierPrice ?? 1); info.Strike = info.SpotPrice; //info.Strike_After = spotPrice * (tradeFullInfo.trade_barrier_option.BarrierPrice ?? 1); //info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_barrier_option.UpperBarrierPrice ?? 1); //info.StrikeHigh_After = spotPrice * (tradeFullInfo.trade_barrier_option.UpperBarrierPrice ?? 1); break; //case "彩虹期权": // trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1; // trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2; // trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike; // trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2; // break; case "凤凰期权": info.KIBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.KIBarrier; info.KIBarrier_After = spotPrice * tradeFullInfo.trade_autocall.KIBarrier; info.KOBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.KOBarrier; info.KOBarrier_After = spotPrice * tradeFullInfo.trade_autocall.KOBarrier; info.CouponBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.CouponBarrier; info.CouponBarrier_After = spotPrice * tradeFullInfo.trade_autocall.CouponBarrier; info.Strike = info.SpotPrice * (tradeFullInfo.trade_autocall.SpreadStrike ?? 1); info.Strike_After = spotPrice * (tradeFullInfo.trade_autocall.SpreadStrike ?? 1); info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_autocall.SpreadStrike1 ?? 1); info.StrikeHigh_After = spotPrice * (tradeFullInfo.trade_autocall.SpreadStrike1 ?? 1); break; case "双鲨期权": info.BarrierHigh = info.SpotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierHigh; info.BarrierHigh_After = spotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierHigh; info.Barrier = info.SpotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierLow; info.Barrier_After = spotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierLow; info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeHigh ?? 1); info.StrikeHigh_After = spotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeHigh ?? 1); info.Strike = info.SpotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeLow ?? 1); info.Strike_After = spotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeLow ?? 1); break; case "区间累积期权": info.LowerRange = info.SpotPrice * tradeFullInfo.trade_rangeaccrual.LowerRange; info.LowerRange_After = spotPrice * tradeFullInfo.trade_rangeaccrual.LowerRange; info.UpperRange = info.SpotPrice * tradeFullInfo.trade_rangeaccrual.UpperRange; info.UpperRange_After = spotPrice * tradeFullInfo.trade_rangeaccrual.UpperRange; break; case "雪球期权": info.KIBarrier = info.SpotPrice * tradeFullInfo.trade_snowball.KIBarrier; info.KIBarrier_After = spotPrice * tradeFullInfo.trade_snowball.KIBarrier; info.KOBarrier = info.SpotPrice * tradeFullInfo.trade_snowball.KOBarrier; info.KOBarrier_After = spotPrice * tradeFullInfo.trade_snowball.KOBarrier; info.SpreadStrikeAtKO = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO; info.SpreadStrikeAtKO_After = spotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO; info.SpreadStrikeAtKO1 = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO1; info.SpreadStrikeAtKO1_After = spotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO1; info.SpreadStrikeAtMaturity = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity; info.SpreadStrikeAtMaturity_After = spotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity; info.SpreadStrikeAtMaturity1 = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity1; info.SpreadStrikeAtMaturity1_After = spotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity1; break; case "气囊结构": info.Barrier = info.SpotPrice * tradeFullInfo.trade_airbag.Barrier; info.Barrier_After = spotPrice * tradeFullInfo.trade_airbag.Barrier; info.StrikeHigh = info.SpotPrice * tradeFullInfo.trade_airbag.HighStrike; info.StrikeHigh_After = spotPrice * tradeFullInfo.trade_airbag.HighStrike; break; case "收益互换": info.PayUnderlyingCode = tradeFullInfo.trade_swap.PayUnderlyingCode; info.GetUnderlyingCode = tradeFullInfo.trade_swap.GetUnderlyingCode; break; } } else { changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == nameof(trade.Strike)).FirstOrDefault(); info.Strike = TryParseDouble(changes?.NewValue, info.Strike); info.Strike_After = TryParseDouble(changes?.FieldValue, double.NaN); var fileName = ""; switch (item.t.TradeType) { case "障碍期权": fileName = nameof(trade.trade_barrier_option) + "." + nameof(trade_barrier_option.BarrierPrice); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.Strike = TryParseDouble(changes?.NewValue, info.Strike); info.Strike_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_barrier_option) + "." + nameof(trade_barrier_option.UpperBarrierPrice); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.StrikeHigh = TryParseDouble(changes?.NewValue, info.StrikeHigh); info.StrikeHigh_After = TryParseDouble(changes?.FieldValue, double.NaN); break; //case "彩虹期权": // trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1; // trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2; // trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike; // trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2; // break; case "凤凰期权": fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.KIBarrier); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.KIBarrier = TryParseDouble(changes?.NewValue, info.KIBarrier); info.KIBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.KOBarrier); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.KOBarrier = TryParseDouble(changes?.NewValue, info.KOBarrier); info.KOBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.CouponBarrier); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.CouponBarrier = TryParseDouble(changes?.NewValue, info.CouponBarrier); info.CouponBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.SpreadStrike); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.Strike = TryParseDouble(changes?.NewValue, info.Strike); info.Strike_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.SpreadStrike1); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.StrikeHigh = TryParseDouble(changes?.NewValue, info.StrikeHigh); info.StrikeHigh_After = TryParseDouble(changes?.FieldValue, double.NaN); break; case "双鲨期权": fileName = nameof(trade.trade_double_sharkfin_option) + "." + nameof(trade_double_sharkfin_option.BarrierHigh); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.BarrierHigh = TryParseDouble(changes?.NewValue, info.BarrierHigh); info.BarrierHigh_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_double_sharkfin_option) + "." + nameof(trade_double_sharkfin_option.BarrierLow); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.Barrier = TryParseDouble(changes?.NewValue, info.Barrier); info.Barrier_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_double_sharkfin_option) + "." + nameof(trade_double_sharkfin_option.StrikeHigh); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.StrikeHigh = TryParseDouble(changes?.NewValue, info.StrikeHigh); info.StrikeHigh_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_double_sharkfin_option) + "." + nameof(trade_double_sharkfin_option.StrikeLow); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.Strike = TryParseDouble(changes?.NewValue, info.Strike); info.Strike_After = TryParseDouble(changes?.FieldValue, double.NaN); break; case "区间累积期权": fileName = nameof(trade.trade_rangeaccrual) + "." + nameof(trade_rangeaccrual.LowerRange); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.LowerRange = TryParseDouble(changes?.NewValue, info.LowerRange); info.LowerRange_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_rangeaccrual) + "." + nameof(trade_rangeaccrual.UpperRange); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.UpperRange = TryParseDouble(changes?.NewValue, info.UpperRange); info.UpperRange_After = TryParseDouble(changes?.FieldValue, double.NaN); break; case "雪球期权": fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.KIBarrier); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.KIBarrier = TryParseDouble(changes?.NewValue, info.KIBarrier); info.KIBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.KOBarrier); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.KOBarrier = TryParseDouble(changes?.NewValue, info.KOBarrier); info.KOBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.SpreadStrikeAtKO); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.SpreadStrikeAtKO = TryParseDouble(changes?.NewValue, info.SpreadStrikeAtKO ?? double.NaN); info.SpreadStrikeAtKO_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.SpreadStrikeAtKO1); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.SpreadStrikeAtKO1 = TryParseDouble(changes?.NewValue, info.SpreadStrikeAtKO1 ?? double.NaN); info.SpreadStrikeAtKO1_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.SpreadStrikeAtMaturity); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.SpreadStrikeAtMaturity = TryParseDouble(changes?.NewValue, info.SpreadStrikeAtMaturity ?? double.NaN); info.SpreadStrikeAtMaturity_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.SpreadStrikeAtMaturity1); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.SpreadStrikeAtMaturity1 = TryParseDouble(changes?.NewValue, info.SpreadStrikeAtMaturity1 ?? double.NaN); info.SpreadStrikeAtMaturity1_After = TryParseDouble(changes?.FieldValue, double.NaN); break; case "气囊结构": fileName = nameof(trade.trade_airbag) + "." + nameof(trade_airbag.Barrier); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.Barrier = TryParseDouble(changes?.NewValue, info.Barrier); info.Barrier_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_airbag) + "." + nameof(trade_airbag.HighStrike); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.StrikeHigh = TryParseDouble(changes?.NewValue, info.StrikeHigh); info.StrikeHigh_After = TryParseDouble(changes?.FieldValue, double.NaN); break; case "收益互换": info.PayUnderlyingCode = tradeFullInfo.trade_swap.PayUnderlyingCode; info.GetUnderlyingCode = tradeFullInfo.trade_swap.GetUnderlyingCode; fileName = nameof(trade.trade_swap) + "." + nameof(trade_swap.PaySpotPrice); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.PaySpotPrice = TryParseDouble(changes?.NewValue, info.PaySpotPrice); info.PaySpotPrice_After = TryParseDouble(changes?.FieldValue, double.NaN); fileName = nameof(trade.trade_swap) + "." + nameof(trade_swap.GetSpotPrice); changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault(); info.GetSpotPrice = TryParseDouble(changes?.NewValue, info.GetSpotPrice); info.GetSpotPrice_After = TryParseDouble(changes?.FieldValue, double.NaN); break; case "累计期权": throw new NotImplementedException("QueryDividendTrade中未实现累计期权逻辑"); } } } else { info.StockEqvNotional = item.t.OriginalStockEqvNotional ?? double.NaN; info.StockEqvNotional_After = double.NaN; info.SpotPrice = item.t.SpotPrice ?? double.NaN; info.SpotPrice_After = double.NaN; info.TradeOriginalAmount = item.t.TradeOriginalAmount ?? item.t.OriginalNotional ?? 0; info.TradeOriginalAmount_After = double.NaN; if (item.t.IsMoneynessOptionData) { info.Strike = info.SpotPrice * (item.t.Strike ?? 1); info.Strike_After = double.NaN; switch (item.t.TradeType) { case "障碍期权": info.Strike = info.SpotPrice * (tradeFullInfo.trade_barrier_option.BarrierPrice ?? 1); info.Strike_After = double.NaN; info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_barrier_option.UpperBarrierPrice ?? 1); info.StrikeHigh_After = double.NaN; break; //case "彩虹期权": // trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1; // trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2; // trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike; // trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2; // break; case "凤凰期权": info.KIBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.KIBarrier; info.KIBarrier_After = double.NaN; info.KOBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.KOBarrier; info.KOBarrier_After = double.NaN; info.CouponBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.CouponBarrier; info.CouponBarrier_After = double.NaN; info.Strike = info.SpotPrice * (tradeFullInfo.trade_autocall.SpreadStrike ?? 1); info.Strike_After = double.NaN; info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_autocall.SpreadStrike1 ?? 1); info.StrikeHigh_After = double.NaN; break; case "双鲨期权": info.BarrierHigh = info.SpotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierHigh; info.BarrierHigh_After = double.NaN; info.Barrier = info.SpotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierLow; info.Barrier_After = double.NaN; info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeHigh ?? 1); info.StrikeHigh_After = double.NaN; info.Strike = info.SpotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeLow ?? 1); info.Strike_After = double.NaN; break; case "区间累积期权": info.LowerRange = info.SpotPrice * tradeFullInfo.trade_rangeaccrual.LowerRange; info.LowerRange_After = double.NaN; info.UpperRange = info.SpotPrice * tradeFullInfo.trade_rangeaccrual.UpperRange; info.UpperRange_After = double.NaN; break; case "雪球期权": info.KIBarrier = info.SpotPrice * tradeFullInfo.trade_snowball.KIBarrier; info.KIBarrier_After = double.NaN; info.KOBarrier = info.SpotPrice * tradeFullInfo.trade_snowball.KOBarrier; info.KOBarrier_After = double.NaN; info.SpreadStrikeAtKO = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO; info.SpreadStrikeAtKO_After = double.NaN; info.SpreadStrikeAtKO1 = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO1; info.SpreadStrikeAtKO1_After = double.NaN; info.SpreadStrikeAtMaturity = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity; info.SpreadStrikeAtMaturity_After = double.NaN; info.SpreadStrikeAtMaturity1 = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity1; info.SpreadStrikeAtMaturity1_After = double.NaN; break; case "气囊结构": info.Barrier = info.SpotPrice * tradeFullInfo.trade_airbag.Barrier; info.Barrier_After = double.NaN; info.StrikeHigh = info.SpotPrice * tradeFullInfo.trade_airbag.HighStrike; info.StrikeHigh_After = double.NaN; break; case "收益互换": info.PayUnderlyingCode = tradeFullInfo.trade_swap.PayUnderlyingCode; info.GetUnderlyingCode = tradeFullInfo.trade_swap.GetUnderlyingCode; break; } } else { info.Strike = item.t.Strike ?? double.NaN; info.Strike_After = double.NaN; switch (item.t.TradeType) { case "障碍期权": info.Barrier = item.t.trade_barrier_option.BarrierPrice ?? 1; info.Barrier_After = double.NaN; info.BarrierHigh = item.t.trade_barrier_option.UpperBarrierPrice ?? 1; info.BarrierHigh_After = double.NaN; break; //case "彩虹期权": // trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1; // trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2; // trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike; // trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2; // break; case "凤凰期权": info.KIBarrier = item.t.trade_autocall.KIBarrier; info.KIBarrier_After = double.NaN; info.KOBarrier = item.t.trade_autocall.KOBarrier; info.KOBarrier_After = double.NaN; info.CouponBarrier = item.t.trade_autocall.CouponBarrier; info.CouponBarrier_After = double.NaN; info.Strike = item.t.trade_autocall.SpreadStrike ?? 1; info.Strike_After = double.NaN; info.StrikeHigh = item.t.trade_autocall.SpreadStrike1 ?? 1; info.StrikeHigh_After = double.NaN; break; case "双鲨期权": info.BarrierHigh = item.t.trade_double_sharkfin_option.BarrierHigh; info.BarrierHigh_After = double.NaN; info.Barrier = item.t.trade_double_sharkfin_option.BarrierLow; info.Barrier_After = double.NaN; info.StrikeHigh = item.t.trade_double_sharkfin_option.StrikeHigh ?? 0; info.StrikeHigh_After = double.NaN; info.Strike = item.t.trade_double_sharkfin_option.StrikeLow ?? 0; info.Strike_After = double.NaN; break; case "区间累积期权": info.LowerRange = item.t.trade_rangeaccrual.LowerRange; info.LowerRange_After = double.NaN; info.UpperRange = item.t.trade_rangeaccrual.UpperRange; info.UpperRange_After = double.NaN; break; case "雪球期权": info.KIBarrier = item.t.trade_snowball.KIBarrier; info.KIBarrier_After = double.NaN; info.KOBarrier = item.t.trade_snowball.KOBarrier; info.KOBarrier_After = double.NaN; info.SpreadStrikeAtKO = info.SpotPrice * item.t.trade_snowball.SpreadStrikeAtKO; info.SpreadStrikeAtKO_After = double.NaN; info.SpreadStrikeAtKO1 = info.SpotPrice * item.t.trade_snowball.SpreadStrikeAtKO1; info.SpreadStrikeAtKO1_After = double.NaN; info.SpreadStrikeAtMaturity = info.SpotPrice * item.t.trade_snowball.SpreadStrikeAtMaturity; info.SpreadStrikeAtMaturity_After = double.NaN; info.SpreadStrikeAtMaturity1 = info.SpotPrice * item.t.trade_snowball.SpreadStrikeAtMaturity1; info.SpreadStrikeAtMaturity1_After = double.NaN; break; case "气囊结构": info.Barrier = item.t.trade_airbag.Barrier; info.Barrier_After = double.NaN; info.StrikeHigh = item.t.trade_airbag.HighStrike; info.StrikeHigh_After = double.NaN; break; case "收益互换": info.PayUnderlyingCode = tradeFullInfo.trade_swap.PayUnderlyingCode; info.GetUnderlyingCode = tradeFullInfo.trade_swap.GetUnderlyingCode; info.PaySpotPrice = item.t.trade_swap.PaySpotPrice ?? double.NaN; info.PaySpotPrice_After = double.NaN; info.GetSpotPrice = item.t.trade_swap.GetSpotPrice ?? double.NaN; info.GetSpotPrice_After = double.NaN; break; } } } info.TradeOriginalAmountV = CalculationModule.TradeCalcHelper.GetTradeAmountV(item.t, info.TradeOriginalAmount, 1); info.TradeOriginalAmountV_After = CalculationModule.TradeCalcHelper.GetTradeAmountV(item.t, info.TradeOriginalAmount_After, 1); result.Add(info); } if (req.DividendStatus != null) { result = result.Where(O => O.DividendStatus == req.DividendStatus.Value).ToList(); } return result; } private double TryParseDouble(string str, double defaultValue) { return double.TryParse(str, out var result) ? result : defaultValue; } public byte[] ExportDividendTrade(DividendTradeReq req) { var ret = QueryDividendTrade(req); var dc = new List { new ExcelHelper.DataColumnModel("交易编号", "TradeNumber"), new ExcelHelper.DataColumnModel("股权登记日", "ExDividendDate", dateFormatter), new ExcelHelper.DataColumnModel("除权除息状态", "DividendStatus", (cv, obj) => { var status = (bool)cv; return status ? "已除权" : "未除权"; }), new ExcelHelper.DataColumnModel("交易状态", "TradeStatus"), new ExcelHelper.DataColumnModel("交易对手方", "ClientName"), new ExcelHelper.DataColumnModel("结构类型", "TradeType"), new ExcelHelper.DataColumnModel("名义本金", "StockEqvNotional", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.StockEqvNotional, trade.StockEqvNotional_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("成交日期", "TradeDate", dateFormatter), new ExcelHelper.DataColumnModel("到期日期", "ExerciseDate", dateFormatter), new ExcelHelper.DataColumnModel("标的代码", "UnderlyingCode"), new ExcelHelper.DataColumnModel("除权除息系数", "DividendRatio", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.DividendRatio, double.NaN, 6); } return result; }), new ExcelHelper.DataColumnModel("期初标的价格", "SpotPrice", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.SpotPrice, trade.SpotPrice_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("执行价格", "Strike", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.Strike, trade.Strike_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("成交数量", "TradeOriginalAmount", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { var amountv = CalculationModule.TradeCalcHelper.GetTradeAmountV(trade.trade,trade.TradeOriginalAmount,1); var amountv_after = CalculationModule.TradeCalcHelper.GetTradeAmountV(trade.trade,trade.TradeOriginalAmount_After,1); result = priceFormatter(amountv, amountv_after, OtcFormatFlag.notional); } return result; }), new ExcelHelper.DataColumnModel("有效成交数量", "TradeOriginalAmount", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.TradeOriginalAmount, trade.TradeOriginalAmount_After, OtcFormatFlag.notional); } return result; }), new ExcelHelper.DataColumnModel("高行权价", "StrikeHigh", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.StrikeHigh, trade.StrikeHigh_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("障碍价格", "Barrier", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.Barrier, trade.Barrier_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("高障碍价格", "BarrierHigh", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.BarrierHigh, trade.BarrierHigh_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("敲入障碍价格", "KIBarrier", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.KIBarrier, trade.KIBarrier_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("敲出障碍价格", "KOBarrier", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.KOBarrier, trade.KOBarrier_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("票息障碍价格", "CouponBarrier", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.CouponBarrier, trade.CouponBarrier_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("互换标的代码(收取方)", "GetUnderlyingCode"), new ExcelHelper.DataColumnModel("互换标的价格(收取方)", "GetSpotPrice", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.GetSpotPrice, trade.GetSpotPrice_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("互换标的代码(支付方)", "PayUnderlyingCode"), new ExcelHelper.DataColumnModel("互换标的价格(支付方)", "PaySpotPrice", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.PaySpotPrice, trade.PaySpotPrice_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("区间下限", "LowerRange", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.LowerRange, trade.LowerRange_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("区间上限", "UpperRange", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.UpperRange, trade.UpperRange_After, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("敲出期权行权价1", "SpreadStrikeAtKO1", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.SpreadStrikeAtKO1 ?? double.NaN, trade.SpreadStrikeAtKO1_After ?? double.NaN, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("敲出期权行权价2", "SpreadStrikeAtKO", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.SpreadStrikeAtKO ?? double.NaN, trade.SpreadStrikeAtKO_After ?? double.NaN, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("敲入期权行权价1", "SpreadStrikeAtMaturity1", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.SpreadStrikeAtMaturity1 ?? double.NaN, trade.SpreadStrikeAtMaturity1_After ?? double.NaN, OtcFormatFlag.umprice); } return result; }), new ExcelHelper.DataColumnModel("封顶/封底行权价", "SpreadStrikeAtMaturity", (cv, obj) => { var result = ""; if (obj is DividendTrade trade) { result = priceFormatter(trade.SpreadStrikeAtMaturity ?? double.NaN, trade.SpreadStrikeAtMaturity_After ?? double.NaN, OtcFormatFlag.umprice); } return result; }) }; new ExcelHelper().ListToExcel(dc.ToArray(), ret, "Sheet1", true, out var buffer); return buffer; } private string dateFormatter(dynamic cv, object obj) { var result = ""; if (cv is DateTime dt) { result = dt.ToString("yyyy-MM-dd"); } return result; } private string priceFormatter(double p1, double p2, int precision) { var result = ""; if (!double.IsNaN(p1) && p1 != 0) { result = OtcFormatExtensions.OtcFormatFlex(p1, minDecimals: precision, maxDecimals: precision); } if (!double.IsNaN(p2) && p2 != 0) { result += $"({OtcFormatExtensions.OtcFormatFlex(p2, minDecimals: precision, maxDecimals: precision)})"; } return result; } private string priceFormatter(double p1, double p2, OtcFormatFlag formatFlag) { var result = ""; if (!double.IsNaN(p1) && p1 != 0) { result = OtcFormatExtensions.OtcFormat(p1, formatFlag); } if (!double.IsNaN(p2) && p2 != 0) { result += $"({OtcFormatExtensions.OtcFormat(p2, formatFlag)})"; } return result; } } }