using System.Data; using System.Linq.Expressions; using YLErp.BLL; using YLErp.Commons; using YLErp.DBModels.Consts; using YLErp.DBModels.Helpers; using YLErp.Models.Tag; using YLErp.Modules.CalculationModule; using YLErp.Modules.TagModule; using YLErp.Office.ExcelModule; using static YLErp.ConsGlobal; namespace YLErp.Modules.TradeModule.QueryModule { /// /// 场外期权多次了结查询服务 /// public class OtcOptionMultiCloseService : YLBaseService { public OtcOptionMultiCloseService(OptUserInfo userInfo) : base(userInfo) { } /// /// 获取分页数据 /// public IPagedList GetPagedDatas(TradeMultiCloseQueryModel queryModel) { var query = CreateQuery(queryModel); if (string.IsNullOrEmpty(queryModel.SortExpression)) { queryModel.SortExpression = "id desc, TcValueDate asc, TcId asc"; } var pagedList = query.ToPagedList(queryModel); OtcTradeDetail preData = null; Dictionary> tradeTagList = null; if (pagedList != null) { using (var service = new TagService(OptUser)) { tradeTagList = service.GetTagByTradeIds(pagedList.Select(p => p.id).Distinct().ToList()); } } if (tradeTagList == null) { tradeTagList = new Dictionary>(); } List childTradeCashList = null; var parentTradeCashIdList = pagedList.Where(p => p.IsGroup == 1).Select(p => p.TcId).Distinct().ToList(); if (parentTradeCashIdList != null && parentTradeCashIdList.Count > 0) { childTradeCashList = DbContext.trade_cash.AsNoTracking().Where(p => parentTradeCashIdList.Contains(p.ParentTradeCashId)).ToList(); } if (childTradeCashList == null) { childTradeCashList = new List(); } List childTradeList = null; if (childTradeCashList != null && childTradeCashList.Count > 0) { var childTradeIds = childTradeCashList.Select(x => x.TradeId).Distinct().ToList(); childTradeList = DbContext.trade.Where(p => childTradeIds.Contains(p.id)).ToList(); } if (childTradeList == null) { childTradeList = new List(); } List tradeBarrierOptionList = null; if (pagedList.Any(p => "障碍期权".Equals(p.TradeType))) { var barrierTradeIds = pagedList.Where(p => "障碍期权".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList(); if (barrierTradeIds != null && barrierTradeIds.Any()) { tradeBarrierOptionList = DbContext.trade_barrier_option.AsNoTracking().Where(p => barrierTradeIds.Contains(p.TradeId)).ToList(); } } if (tradeBarrierOptionList == null) { tradeBarrierOptionList = new List(); } List tradeDoublesharkfinOptionList = null; if (pagedList.Any(p => "双鲨期权".Equals(p.TradeType))) { var doubleSharkfinTradeIds = pagedList.Where(p => "双鲨期权".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList(); if (doubleSharkfinTradeIds != null && doubleSharkfinTradeIds.Any()) { tradeDoublesharkfinOptionList = DbContext.trade_double_sharkfin_option.AsNoTracking().Where(p => doubleSharkfinTradeIds.Contains(p.TradeId)).ToList(); } } if (tradeDoublesharkfinOptionList == null) { tradeDoublesharkfinOptionList = new List(); } List tradeAutocallList = null; if (pagedList.Any(p => "凤凰期权".Equals(p.TradeType))) { var autocallTradeIds = pagedList.Where(p => "凤凰期权".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList(); if (autocallTradeIds != null && autocallTradeIds.Any()) { tradeAutocallList = DbContext.trade_autocall.AsNoTracking().Where(p => autocallTradeIds.Contains(p.TradeId)).ToList(); } } if (tradeAutocallList == null) { tradeAutocallList = new List(); } List tradeSnowballList = null; if (pagedList.Any(p => "雪球期权".Equals(p.TradeType))) { var snowballTradeIds = pagedList.Where(p => "雪球期权".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList(); if (snowballTradeIds != null && snowballTradeIds.Any()) { tradeSnowballList = DbContext.trade_snowball.AsNoTracking().Where(p => snowballTradeIds.Contains(p.TradeId)).ToList(); } } if (tradeSnowballList == null) { tradeSnowballList = new List(); } List tradeAirbagList = null; if (pagedList.Any(p => "气囊结构".Equals(p.TradeType) || "气囊结构".Equals(p.StructureType))) { var airbagTradeIds = pagedList.Where(p => "气囊结构".Equals(p.TradeType) || "气囊结构".Equals(p.StructureType)).Select(p => p.id).Distinct().ToList(); if (airbagTradeIds != null && airbagTradeIds.Any()) { tradeAirbagList = DbContext.trade_airbag.AsNoTracking().Where(p => airbagTradeIds.Contains(p.TradeId)).ToList(); } } if (tradeAirbagList == null) { tradeAirbagList = new List(); } //List tradeAccumulatorOptionList = null; List autocallObservationList = null; if (pagedList.Any(p => "累计期权".Equals(p.TradeType))) { var accumulatorOptionTradeIds = pagedList.Where(p => "累计期权".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList(); if (accumulatorOptionTradeIds != null && accumulatorOptionTradeIds.Any()) { //tradeAccumulatorOptionList = DbContext.trade_accumulator_option.AsNoTracking().Where(p => accumulatorOptionTradeIds.Contains(p.TradeId)).ToList(); autocallObservationList = DbContext.autocall_observation.AsNoTracking().Where(p => accumulatorOptionTradeIds.Contains(p.TradeId)).ToList(); } } //if (tradeAccumulatorOptionList == null) //{ // tradeAccumulatorOptionList = new List(); //} if (autocallObservationList == null) { autocallObservationList = new List(); } foreach (var data in pagedList) { preData = ProcessData(data, preData); if (data.IsGroup == 1) { //var childTradeCashs = DbContext.trade_cash.Where(x => x.ParentTradeCashId == data.TcId).ToList(); var childTradeCashs = childTradeCashList.Where(x => x.ParentTradeCashId == data.TcId).ToList(); var childTradeIds = childTradeCashs.Select(x => x.TradeId).Distinct().ToList(); //var childTrades = DbContext.trade.Where(x => childTradeIds.Contains(x.id)).ToList(); var childTrades = childTradeList.Where(x => childTradeIds.Contains(x.id)).ToList(); data.TcTradePrice = 0; childTradeCashs.ForEach(x => { var trade = childTrades.FirstOrDefault(y => y.id == x.TradeId); data.TcTradePrice += (x.UnwindPercentRate * trade?.TradePrice * (trade?.BuySell == "买入" ? -1 : 1)) ?? 0; }); } if (data.TradeType == "障碍期权") { //var option = DbContext.trade_barrier_option.FirstOrDefault(x => x.TradeId == data.id); var option = tradeBarrierOptionList.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "双鲨期权") { //var option = DbContext.trade_double_sharkfin_option.FirstOrDefault(x => x.TradeId == data.id); var option = tradeDoublesharkfinOptionList.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "凤凰期权") { //var option = DbContext.trade_autocall.FirstOrDefault(x => x.TradeId == data.id); var option = tradeAutocallList.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "雪球期权") { //var option = DbContext.trade_snowball.FirstOrDefault(x => x.TradeId == data.id); var option = tradeSnowballList.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "气囊结构" || data.StructureType == "气囊结构") { //var option = DbContext.trade_airbag.FirstOrDefault(x => x.TradeId == data.id); var option = tradeAirbagList.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "累计期权") { new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay2(data, Convert.ToDateTime(data.TcValueDate)); //var option = DbContext.trade_accumulator_option.FirstOrDefault(x => x.TradeId == data.id); //var option = tradeAccumulatorOptionList.FirstOrDefault(x => x.TradeId == data.id); //data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; var obser = autocallObservationList.FirstOrDefault(x => x.TradeId == data.id && x.EndDate == data.TcValueDate); if (obser != null) { data.KnockInOutStatusObservation = "敲出".Equals(obser.SettlementMode) ? "敲出" : "观察中"; } } if (data.CountRatio == null) { data.CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(data.UnderlyingCode)?.CountRatio ?? 1; } //拼装标签值 if (tradeTagList.ContainsKey(data.id)) { data.Tags = tradeTagList[data.id]; data.OutputTags = TagService.GetOutputTagsStr(data.Tags); } } return pagedList; } /// /// 获取了结记录 /// 主要用于批量生成了结简讯用 /// /// /// public List> GetSettlementList(TradeMultiCloseQueryModel queryModel) { if (queryModel is null) { throw new ArgumentNullException(nameof(queryModel)); } BuildPredicate(queryModel, out var tdPredicate, out var tcPredicate); var query = from t in DbContext.trade.Where(tdPredicate) join tc in DbContext.trade_cash.Where(tcPredicate) on t.id equals tc.TradeId select new { t, tc }; if (queryModel.UnWindTimes != null && queryModel.UnWindTimes >= 0) { var qgp = from f in query group f by f.t.id into fgp where fgp.Count() == queryModel.UnWindTimes select fgp.Key; query = query.Where(q => qgp.Contains(q.t.id)); } if (queryModel.TradeCashIdList != null && queryModel.TradeCashIdList.Count > 0) { var tcIds = query.Select(O => O.tc.id).ToList(); tcIds = queryModel.TradeCashIdList.Where(O => !tcIds.Contains(O)).ToList(); if (tcIds.Any()) { query = query.Union( from tc in DbContext.trade_cash join t in DbContext.trade on tc.TradeId equals t.id where tcIds.Contains(tc.id) select new { t, tc } ); } } query = query.OrderByDescending(x => x.t.id).ThenBy(x => x.tc.ValueDate).ThenBy(x => x.tc.id); return query.ToList().Select(O => new KeyValuePair(O.t, O.tc)).ToList(); } public List GetGroupChildrenDatas(int TcId) { var query = from t in DbContext.trade.AsNoTracking().Where(x => x.ValidState != "InValid" && x.IsGroup == 2) join tc in DbContext.trade_cash.AsNoTracking().Where(x => x.ValidState != "InValid" && x.ParentTradeCashId == TcId && (x.Amount != 0 || x.UnwindPercentRate > 0)) on t.id equals tc.TradeId select new OtcTradeDetail { id = t.id, TcId = tc.id, UnderlyingId = t.UnderlyingId, TradeNumber = t.TradeNumber, ClientId = t.ClientId, ClientName = t.ClientName, TradeDate = t.TradeDate, ExerciseDate = t.ExerciseDate, BuySell = t.BuySell, TradeType = t.TradeType, OptionType = t.OptionType, UnderlyingAssetName = t.UnderlyingAssetName, UnderlyingCode = t.UnderlyingCode, SpotPrice = t.SpotPrice, Strike = t.Strike, IsMoneynessOption = t.IsMoneynessOption, TradeSinglePrice = t.TradeSinglePrice ?? 0, TradePrice = t.TradePrice ?? 0, IsUsePremiumRate = t.IsUsePremiumRate, PremiumRate = t.PremiumRate, TradeAmount = t.TradeAmount, ExerciseMode = t.ExerciseMode, OriginalNotional = t.OriginalNotional ?? 0, OriginalStockEqvNotional = t.OriginalStockEqvNotional, ParticipationRate = t.ParticipationRate, AnnualizeFactor = t.AnnualizeFactor, PrincipalRate = t.PrincipalRate ?? 0, AssetBookName = t.AssetBookName, TraderName = t.TraderName, TcValueDate = tc.HappenedDate != null ? tc.HappenedDate : tc.ValueDate, TcFinalPrice = tc.FinalPrice, TcUnwindPrice = tc.UnwindPrice, TcUnwindPricePercent = tc.UnwindPricePercentRate, TcAmount = tc.Amount, UnWindNotional = tc.UnwindNotional ?? tc.Notional, TcUnwindTradeAmount = tc.UnwindTradeAmount, TcUnwindPercent = tc.UnwindPercentRate, TcAction = tc.Action, TcExerciseWay = tc.ExerciseWay, StructureType = t.StructureType, IsGroup = t.IsGroup, UnderlyingInstrumentType = t.UnderlyingInstrumentType }; var result = query.ToList(); OtcTradeDetail preData = null; Dictionary> tradeTagList = null; if (result != null && result.Any()) { using (var service = new TagService(OptUser)) { tradeTagList = service.GetTagByTradeIds(result.Select(p=>p.id).Distinct().ToList()); } } if (tradeTagList == null) { tradeTagList = new Dictionary>(); } foreach (var data in result) { preData = ProcessData(data, preData); if (data.TradeType == "亚式期权") { var baseReq = FixingService.GetRequestBase(valuedateBLL.ValueDate, data); var strikeReq = new AsianOptionStrikeRequest(baseReq) { IsMoneynessOption = data.IsMoneynessOption == "是", SpotPrice = data.SpotPrice, Strike = data.Strike, }; data.ActualStrike = trade_asian_optionBLL.GetAsianStrikePrice(strikeReq, null); } else { data.ActualStrike = data.IsMoneynessOption == "是" ? (data.SpotPrice * data.Strike) : data.Strike; } if (data.TradeType == "障碍期权") { var option = DbContext.trade_barrier_option.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "双鲨期权") { var option = DbContext.trade_double_sharkfin_option.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "凤凰期权") { var option = DbContext.trade_autocall.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "雪球期权") { var option = DbContext.trade_snowball.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "气囊结构") { var option = DbContext.trade_airbag.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } //拼装标签值 if (tradeTagList.ContainsKey(data.id)) { data.Tags = tradeTagList[data.id]; data.OutputTags = TagService.GetOutputTagsStr(data.Tags); } } return result; } /// /// 根据交易编号获取交易了结信息(需要重构,否则不要用于其它查询场景) /// 用于api/v1/tradeCloseInfos /// public IEnumerable GetTradeCloseInfos(string tradeNumber, string unWindType, DateTime? valueDate = null) { var queryModel = new TradeMultiCloseQueryModel { TradeNumber = tradeNumber, UseForwardASwap = true }; if (!string.IsNullOrEmpty(unWindType)) { queryModel.UnWindType = unWindType; } if (valueDate != null && valueDate != DateTime.MinValue) { queryModel.UnwindDateStart = valueDate; queryModel.UnwindDateEnd = valueDate; } var query = CreateQuery(queryModel); var datas = query.ToArray(); var list = new List(); OtcTradeDetail preData = null; foreach (var data in datas) { preData = ProcessData(data, preData); var info = new TradeCloseInfo { TradeNumber = data.TradeNumber, TcValueDate = data.TcValueDate, TcAction = data.TcAction, TcAmount = data.TcAmount, TcFinalPrice = data.TcFinalPrice, TcNotional = data.TcNotional, TcTradeAmount = data.TcTradeAmount, TcUnwindNotional = data.TcUnwindNotional, TcUnwindPercent = data.TcUnwindPercent, TcUnwindPrice = data.TcUnwindPrice, TcUnwindPricePercent = data.TcUnwindPricePercent, TcUnwindTradeAmount = data.TcUnwindTradeAmount, TcTradePrice = (data.TradePrice ?? 0) * (data.TcUnwindPercent ?? 0) * ((data.BuySell == "卖出" || data.TradeType == "远期") ? 1 : -1), }; if (data.IsGroup == 1) { var childTradeCashs = DbContext.trade_cash.Where(x => x.ParentTradeCashId == data.TcId).ToList(); var childTradeIds = childTradeCashs.Select(x => x.TradeId).Distinct().ToList(); var childTrades = DbContext.trade.Where(x => childTradeIds.Contains(x.id)).ToList(); info.TcTradePrice = 0; childTradeCashs.ForEach(x => { var trade = childTrades.FirstOrDefault(y => y.id == x.TradeId); info.TcTradePrice += (x.UnwindPercentRate * trade?.TradePrice * (trade?.BuySell == "买入" ? -1 : 1)) ?? 0; }); } info.WinLoss = (info.TcAmount ?? 0) + info.TcTradePrice; list.Add(info); } return list; } /// /// 导出所有字段 /// public byte[] ExportAllFieldsToExcel(TradeMultiCloseQueryModel queryModel) { var list = HandleExportDataToList(queryModel); var list2 = list.Select(n => new ExpandoDictionary(n.MetaDic)).ToArray(); var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/场外期权交易多次了结导出模板.xlsx"); return ExcelGenerator.UseTemplateGenerator(templateFile).AddVariable(new { list = list2 }).GenerateBytes(); } public List HandleExportDataToList(TradeMultiCloseQueryModel queryModel) { if (queryModel is null) { throw new ArgumentNullException(nameof(queryModel)); } var query = CreateQuery(queryModel); var list = query.ToList(); OtcTradeDetail preData = null; foreach (var data in list) { data.CountRatio = DataCacheModule.DataCacheManager.GetUnderlyingDataSource().GetData(data.UnderlyingCode)?.CountRatio; preData = ProcessData(data, preData); HandleExportData(data); } new TradeExtendService(this).SetTradeExtendWithCnKey(list); var groupTradeCashIds = list.Where(x => x.IsGroup == 1).Select(x => x.TcId).ToArray(); var childList = CreateGroupChildrenQuery(groupTradeCashIds); groupTradeCashIds.ToList().ForEach(x => { var children = childList.Where(y => y.ParentTcId == x).ToList(); var item = list.FirstOrDefault(y => y.TcId == x); list.InsertRange(list.IndexOf(item) + 1, children.OrderBy(y => y.id)); }); return list; } //数据加工处理 private OtcTradeDetail ProcessData(OtcTradeDetail data, OtcTradeDetail preData) { if (preData?.id == data.id) { data.TcSequence = preData.TcSequence + 1; data.TradeOriginalAmount = preData.OriginalNotional; data.SyntheticUnderlyingTipsInfo = preData.SyntheticUnderlyingTipsInfo; data.ExerciseMode = preData.ExerciseMode; } else { data.ExerciseMode = TradeHelper.GetExerciseModeCn(data.ExerciseMode); var CountRatio = UnderlyingDataProvider.GetCountRatio(data.UnderlyingCode); data.TradeOriginalAmount = data.OriginalNotional / CountRatio; if (data.TradeType == "合成价差期权") { data.SyntheticUnderlyingTipsInfo = synthetic_underlyingBLL.GetUnderlyingTipsInfo(data.UnderlyingCode); } } data.TcUnwindNotional = data.OriginalNotional * data.TcUnwindPercent; if (data.TcAction == "系统操作-行权费" && !data.TcUnwindTradeAmount.HasValue) { var CountRatio = UnderlyingDataProvider.GetCountRatio(data.UnderlyingCode); data.TcUnwindTradeAmount = data.OriginalNotional * data.TcUnwindPercent / CountRatio; } if (data.TcAction == "系统操作-票息") { data.TcAction = "票息"; } else if (data.TcAction == "系统操作-互换") { data.TcAction = "互换"; } else if (data.TcExerciseWay == TradeCashExerciseWayEnum.到期行权) { data.TcAction = "到期"; } else { data.TcAction = "终止"; } if (data.TradeType == "结构化交易" && data.IsGroup == 1) { data.TradeType = data.StructureType; } if (PS.Config.IsGuoJun) { data.UnderlyingVariety = YLErp.Modules.UnderlyingModule.UnderlyingHelper.GetUnderlyingVarietyCode(data.UnderlyingCode); } return data; } private void HandleExportData(OtcTradeDetail data) { var dic = data.MetaDic; var isMoneyness = data.IsMoneynessOption == "是"; var isPremiumRate = data.IsUsePremiumRate == true; var multiply = TradeHelper.GetStockEqvNotionalMultiply(data.OriginalStockEqvNotional, data.ParticipationRate, data.AnnualizeFactor); if (data.IsGroup == 1) { var childTradeCashs = DbContext.trade_cash.Where(x => x.ParentTradeCashId == data.TcId).ToList(); var childTradeIds = childTradeCashs.Select(x => x.TradeId).Distinct().ToList(); var childTrades = DbContext.trade.Where(x => childTradeIds.Contains(x.id)).ToList(); data.TcTradePrice = 0; childTradeCashs.ForEach(x => { var trade = childTrades.FirstOrDefault(y => y.id == x.TradeId); data.TcTradePrice += (x.UnwindPercentRate * trade?.TradePrice * (trade?.BuySell == "买入" ? -1 : 1)) ?? 0; }); } if (data.TradeType == "障碍期权") { var option = DbContext.trade_barrier_option.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "双鲨期权") { var option = DbContext.trade_double_sharkfin_option.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "凤凰期权") { var option = DbContext.trade_autocall.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "雪球期权") { var option = DbContext.trade_snowball.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "气囊结构" || data.StructureType == "气囊结构") { var option = DbContext.trade_airbag.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } else if (data.TradeType == "累计期权") { new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay2(data, Convert.ToDateTime(data.TcValueDate)); var option = DbContext.trade_accumulator_option.FirstOrDefault(x => x.TradeId == data.id); data.KnockInOutStatusObservation = option?.KnockInOutStatusCn; } dic["交易编号"] = data.TradeNumber; dic["分组交易类型"] = data.GroupTradeType; dic["交易状态"] = data.TradeStatus; dic["簿记账户"] = data.AssetBookName; dic["交易员"] = data.TraderName; dic["交易对手方"] = data.ClientName; dic["交易对手编号"] = DataCacheProvider.GetClientDataSource().GetData(data.ClientId)?.Number; dic["结构类型"] = data.TradeMultipleType; dic["成交日期"] = data.TradeDate.OtcFormatDate(); dic["到期日期"] = data.ExerciseDate.OtcFormatDate(); dic["结算日期"] = data.SettlementDate.OtcFormatDate(); dic["交易方向"] = data.BuySell; dic["标的代码"] = data.UnderlyingCode; dic["期初标的价格"] = data.SpotPrice.OtcFormatUmPrice(); dic["执行价格"] = data.Strike.OtcFormatUmPrice(isMoneyness); dic["权利金成交"] = OtcFormatHelper.FormatPremium(data.IsUsePremiumRate, data.PremiumRate, data.TradeSinglePrice); dic["有效成交数量"] = PS.Config.IsUseDisplayNotional ? (data.TradeOriginalAmount * data.CountRatio).OtcFormatNotional() : data.TradeOriginalAmount.OtcFormatNotional(); dic["成交数量"] = PS.Config.IsUseDisplayNotional ? (TradeCalcHelper.GetTradeAmountV(data) * data.CountRatio).OtcFormatNotional() : TradeCalcHelper.GetTradeAmountV(data).OtcFormatNotional(); dic["成交金额"] = data.TradePrice.OtcFormatMoney(); dic["名义本金"] = data.OriginalStockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional); dic["实际名义本金"] = dic["有效名义本金"] = data.StockEqvNotionalReal.OtcFormat(OtcFormatFlag.StockEqvNotional); dic["期权年化"] = data.IsAnnualized ? "是" : "否"; dic["年化系数"] = data.AnnualizeFactor.OtcFormatFlex(2, 6); dic["保底收益率"] = data.PrincipalRate.OtcFormatPercent(2); dic["参与率"] = data.ParticipationRate.OtcFormatPercent(2); dic["无风险利率"] = data.NoRiskRate.OtcFormatPercent(2); dic["分红率"] = data.DividendRate.OtcFormatPercent(2); dic["成交波动率"] = data.TradeOpenVolatility.OtcFormat(OtcFormatFlag.volatilityP); dic["目标波动率"] = data.TradeCloseVolatility.OtcFormat(OtcFormatFlag.volatilityP); dic["平滑过渡天数"] = data.NumOfSmoothingDays?.ToString(); dic["备注"] = data.Comments; dic["敲入敲出状态"] = data.KnockInOutStatusObservation; dic["了结序号"] = data.TcSequence.ToString(); dic["了结方式"] = data.TcAction; dic["了结日期"] = data.TcValueDate.OtcFormatDate(); dic["了结标的价格"] = data.TcFinalPrice?.OtcFormatUmPrice(); dic["权利金了结"] = OtcFormatHelper.FormatPremium(data.IsUsePremiumRate, data.TcUnwindPricePercent, data.TcUnwindPrice)?.TrimStart('-'); dic["了结数量"] = PS.Config.IsUseDisplayNotional ? (data.TcUnwindTradeAmount * data.CountRatio).OtcFormatNotional() : data.TcUnwindTradeAmount.OtcFormatNotional(); dic["终止名义数量"] = PS.Config.IsUseDisplayNotional ? (data.TcUnwindTradeAmount * multiply * data.CountRatio).OtcFormatNotional() : (data.TcUnwindTradeAmount * multiply).OtcFormatNotional(); if (true) { } var stopEqvNotional = isPremiumRate || data.TradeType == "累计期权" ? TradeHelper.GetStockEqvNotionalReal(data.OriginalStockEqvNotional, data.ParticipationRate, data.AnnualizeFactor) * data.TcUnwindPercent : data.TcUnwindNotional * data.SpotPrice; if (data.TradeType == "雪球期权" || data.TradeType == "凤凰期权") { var part = data.OriginalStockEqvNotional * (data.ParticipationRate ?? 1); var annual = part != 0 ? data.StockEqvNotionalReal / part : 0; stopEqvNotional *= annual; } dic["终止实际名义金额"] = stopEqvNotional.HasValue ? Math.Abs(stopEqvNotional.Value).OtcFormat(OtcFormatFlag.StockEqvNotional) : ""; dic["了结金额"] = data.TcAmount.OtcFormatMoney(); dic["成交金额"] = data.TcTradePrice.OtcFormatMoney(); dic["实现盈亏"] = data.WinLoss.OtcFormatMoney(); dic["相对行权价"] = data.IsMoneynessOption == "是" ? "是" : ""; dic["期权费率方式"] = data.IsUsePremiumRate == true ? "是" : ""; dic["保底收益总额"] = data.OriginalPrincipalSum.OtcFormatUmPrice(); } //创建查询 private IQueryable CreateQuery(TradeMultiCloseQueryModel queryModel) { if (queryModel is null) { throw new ArgumentNullException(nameof(queryModel)); } BuildPredicate(queryModel, out var tdPredicate, out var tcPredicate); var query = from t in DbContext.trade.Where(tdPredicate) join tc in DbContext.trade_cash.Where(tcPredicate) on t.id equals tc.TradeId select new OtcTradeDetail { id = t.id, TcId = tc.id, UnderlyingId = t.UnderlyingId, TradeNumber = t.TradeNumber, ClientId = t.ClientId, ClientName = t.ClientName, TradeDate = t.TradeDate, ExerciseDate = t.ExerciseDate, BuySell = t.BuySell, TradeType = t.TradeType, OptionType = t.OptionType, UnderlyingAssetName = t.UnderlyingAssetName, UnderlyingCode = t.UnderlyingCode, SpotPrice = t.SpotPrice, Strike = t.Strike, IsMoneynessOption = t.IsMoneynessOption, TradeSinglePrice = t.TradeSinglePrice ?? 0, TradePrice = t.TradePrice ?? 0, IsUsePremiumRate = t.IsUsePremiumRate, PremiumRate = t.PremiumRate, TradeAmount = t.TradeAmount, ExerciseMode = t.ExerciseMode, OriginalNotional = t.OriginalNotional ?? 0, StockEqvNotionalReal = t.StockEqvNotionalReal, OriginalStockEqvNotional = t.OriginalStockEqvNotional, ParticipationRate = t.ParticipationRate, AnnualizeFactor = t.AnnualizeFactor, PrincipalRate = t.PrincipalRate ?? 0, OriginalPrincipalSum = t.OriginalPrincipalSum, TcValueDate = tc.HappenedDate != null ? tc.HappenedDate : tc.ValueDate, TcFinalPrice = tc.FinalPrice, TcUnwindPrice = tc.UnwindPrice, TcUnwindPricePercent = tc.UnwindPricePercentRate, TcAmount = tc.Amount, UnWindNotional = tc.UnwindNotional ?? (tc.IsLastAction ? tc.Notional : 0), TcUnwindTradeAmount = tc.UnwindTradeAmount ?? (tc.IsLastAction ? tc.TradeAmount : 0), TcUnwindPercent = tc.UnwindPercentRate, TcAction = tc.Action, TcExerciseWay = tc.ExerciseWay, StructureType = t.StructureType, IsGroup = t.IsGroup, IsLastAction = tc.IsLastAction, GroupTradeType = t.IsGroup == 0 ? "正常交易" : (t.IsGroup == 1 ? "分组主交易" : "分组子交易"), ExtendInfo = t.ExtendInfo, TraderName = t.TraderName, AssetBookName = t.AssetBookName }; if (queryModel.UnWindTimes != null && queryModel.UnWindTimes >= 0) { var qgp = from f in query group f by f.id into fgp where fgp.Count() == queryModel.UnWindTimes select fgp.Key; query = query.Where(q => qgp.Contains(q.id)); } return query = query.OrderByDescending(x => x.id).ThenBy(x => x.TcValueDate).ThenBy(x => x.TcId); } private List CreateGroupChildrenQuery(int[] parentTradeCashIds) { var query = from t in DbContext.trade join tc in DbContext.trade_cash.Where(x => parentTradeCashIds.Contains(x.ParentTradeCashId)) on t.id equals tc.TradeId select new OtcTradeDetail { id = t.id, TcId = tc.id, ParentTcId = tc.ParentTradeCashId, UnderlyingId = t.UnderlyingId, TradeNumber = t.TradeNumber, ClientId = t.ClientId, ClientName = t.ClientName, TradeDate = t.TradeDate, ExerciseDate = t.ExerciseDate, BuySell = t.BuySell, TradeType = t.TradeType, OptionType = t.OptionType, UnderlyingAssetName = t.UnderlyingAssetName, UnderlyingCode = t.UnderlyingCode, SpotPrice = t.SpotPrice, Strike = t.Strike, IsMoneynessOption = t.IsMoneynessOption, TradeSinglePrice = t.TradeSinglePrice ?? 0, TradePrice = t.TradePrice ?? 0, IsUsePremiumRate = t.IsUsePremiumRate, PremiumRate = t.PremiumRate, TradeAmount = t.TradeAmount, ExerciseMode = t.ExerciseMode, OriginalNotional = t.OriginalNotional ?? 0, StockEqvNotionalReal = t.StockEqvNotionalReal, OriginalStockEqvNotional = t.OriginalStockEqvNotional, ParticipationRate = t.ParticipationRate, AnnualizeFactor = t.AnnualizeFactor, PrincipalRate = t.PrincipalRate ?? 0, TcValueDate = tc.HappenedDate != null ? tc.HappenedDate : tc.ValueDate, TcFinalPrice = tc.FinalPrice, TcUnwindPrice = tc.UnwindPrice, TcUnwindPricePercent = tc.UnwindPricePercentRate, TcAmount = tc.Amount, UnWindNotional = tc.UnwindNotional ?? tc.Notional, TcUnwindTradeAmount = tc.UnwindTradeAmount, TcUnwindPercent = tc.UnwindPercentRate, TcAction = tc.Action, TcExerciseWay = tc.ExerciseWay, StructureType = t.StructureType, IsGroup = t.IsGroup, GroupTradeType = t.IsGroup == 0 ? "正常交易" : (t.IsGroup == 1 ? "分组主交易" : "分组子交易") }; var list = query.OrderByDescending(x => x.id).ThenBy(x => x.TcValueDate).ThenBy(x => x.id).ToList(); OtcTradeDetail preData = null; foreach (var data in list) { data.CountRatio = DataCacheModule.DataCacheManager.GetUnderlyingDataSource().GetData(data.UnderlyingCode)?.CountRatio; preData = ProcessData(data, preData); HandleExportData(data); } new TradeExtendService(this).SetTradeExtendWithCnKey(list); return list; } //构建查询条件 private void BuildPredicate(TradeMultiCloseQueryModel queryModel, out Expression> tdPredicate , out Expression> tcPredicate) { tdPredicate = PredicateBuilder.Create(t => t.ClientId > 0); if (string.IsNullOrEmpty(queryModel.TradeNumber) || (queryModel.UnWindType != "全部" && queryModel.UnWindType != "了结")) //todo:需要重构 { tdPredicate = tdPredicate.And(t => t.IsGroup != 2); } if (queryModel.UserAssets != null || queryModel.UserClients != null) { tdPredicate = tdPredicate.And(n => queryModel.UserAssets.Contains(n.AssetId) || queryModel.UserClients.Contains(n.ClientId)); } if (!queryModel.UseForwardASwap) { tdPredicate = tdPredicate.And(n => n.TradeType != "收益互换" && n.TradeType != "远期"); } if (!string.IsNullOrWhiteSpace(queryModel.TradeStatus)) { tdPredicate = tdPredicate.And(n => queryModel.TradeStatus.Contains(n.TradeStatus)); } if (queryModel.TradeDateStart != null) { tdPredicate = tdPredicate.And(n => n.TradeDate >= queryModel.TradeDateStart.Value); } if (queryModel.TradeDateEnd != null) { tdPredicate = tdPredicate.And(n => n.TradeDate <= queryModel.TradeDateEnd.Value); } if (queryModel.ExerciseDateStart != null) { tdPredicate = tdPredicate.And(n => n.ExerciseDate >= queryModel.ExerciseDateStart.Value); } if (queryModel.ExerciseDateEnd != null) { tdPredicate = tdPredicate.And(n => n.ExerciseDate <= queryModel.ExerciseDateEnd.Value); } if (queryModel.TagIds != null && queryModel.TagIds.Count > 0) { var tradeTagIdQuery = from tt in DbContext.trade_tag where queryModel.TagIds.Contains(tt.TagId) select tt.TradeId; tdPredicate = tdPredicate.And(p => tradeTagIdQuery.Contains(p.id)); } if (!string.IsNullOrWhiteSpace(queryModel.TradeNumber)) { var TradeNumber = queryModel.TradeNumber.Trim(); if (queryModel.UnWindType == "全部" || queryModel.UnWindType == "了结") { tdPredicate = tdPredicate.And(n => n.TradeNumber.Equals(TradeNumber)); } else { tdPredicate = tdPredicate.And(n => n.TradeNumber.Contains(TradeNumber)); } } if (!string.IsNullOrWhiteSpace(queryModel.BuySell)) { var BuySell = queryModel.BuySell.Trim(); tdPredicate = tdPredicate.And(n => n.BuySell == BuySell); } if (queryModel.ClientIdList.Any()) { tdPredicate = tdPredicate.And(n => queryModel.ClientIdList.Contains(n.ClientId)); } if (!string.IsNullOrWhiteSpace(queryModel.StructureType)) { tdPredicate = tdPredicate.And(n => n.StructureType.Contains(queryModel.StructureType)); } if (!string.IsNullOrWhiteSpace(queryModel.TradeTypes)) { var typeList = queryModel.TradeTypes.Split(',').ToList(); tdPredicate = tdPredicate.And(n => typeList.Contains(n.TradeType) || typeList.Contains(n.StructureType) || (typeList.Contains("黑箱结构") && n.IsGroup == 1)); } if (queryModel.UnderlyingIdList != null && queryModel.UnderlyingIdList.Any(n => n > 0)) { tdPredicate = tdPredicate.And(n => queryModel.UnderlyingIdList.Contains(n.UnderlyingId)); } if (!string.IsNullOrWhiteSpace(queryModel.ExerciseMode)) { tdPredicate = tdPredicate.And(n => n.ExerciseMode == queryModel.ExerciseMode); } //-------------------------------------------------------- tcPredicate = PredicateBuilder.Create(tc => tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted && (tc.Action == "系统操作-行权费" || tc.Action == "系统操作-平仓费" || tc.Action == "系统操作-票息" || tc.Action == "系统操作-互换")); //了结方式过滤 if (!string.IsNullOrWhiteSpace(queryModel.UnWindType) && queryModel.UnWindType != "全部") { if (queryModel.UnWindType == "票息") { tcPredicate = tcPredicate.And(x => x.Action == "系统操作-票息"); } else if (queryModel.UnWindType == "到期") { tcPredicate = tcPredicate.And(x => x.ExerciseWay == TradeCashExerciseWayEnum.到期行权 && x.Action != "系统操作-票息"); } else if (queryModel.UnWindType == "了结") { tcPredicate = tcPredicate.And(x => x.Action != "系统操作-票息"); } else { tcPredicate = tcPredicate.And(x => x.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权 && x.Action != "系统操作-票息"); } } if (queryModel.TradeCashIdList != null && queryModel.TradeCashIdList.Any(x => x > 0)) { tcPredicate = tcPredicate.And(tc => queryModel.TradeCashIdList.Contains(tc.id)); } if (queryModel.UnwindDateStart != null) { var UnwindDateStart = queryModel.UnwindDateStart.Value; tcPredicate = tcPredicate.And(tc => tc.HappenedDate.Value >= UnwindDateStart || tc.ValueDate >= UnwindDateStart); } if (queryModel.UnwindDateEnd != null) { var UnwindDateEnd = queryModel.UnwindDateEnd.Value; tcPredicate = tcPredicate.And(tc => tc.ValueDate <= UnwindDateEnd); } } } }