using Microsoft.EntityFrameworkCore.Storage; using YLErp.BLL; using YLErp.BLL.MarginCalculation; using YLErp.Configuration; using YLErp.CustomizedBizLogic; using YLErp.DBModels.Consts; using YLErp.DBModels.Helpers; using YLErp.Enums; using YLErp.Helpers; using YLErp.Model.Enum; using YLErp.Modules.SalesModule; using YLErp.Modules.TagModule; using YLErp.Modules.TradeModule.DealModule; namespace YLErp.Modules.TradeModule.OrderModule { /// /// 交易保存服务 /// public class TradeSaveService : TradeServiceBase { TradeSourceEnum _source; public TradeSaveService(OptUserInfo userInfo) : base(userInfo) { } public TradeSaveService(YLBaseService baseService) : base(baseService) { } /// /// /// public trade SaveTrade(trade req, TradeSourceEnum source, IDbContextTransaction trans = null) { if (req is null) { throw new ArgumentNullException(nameof(req)); } _source = source; var noTrans = trans == null; try { if (noTrans) { trans = DbContext.Database.BeginTransaction(); } //交易保存处理 var preHandler = new TradeSavePreHandler(this); req = preHandler.Prepare(req, _source); var dbTrade = preHandler.isAddNew ? InnerSaveNewTrade(req, preHandler.TradeNumberGenerated) : (req.IsGroup == 1 && req.TradeType == "收益互换" ? InnerSaveEditSwapGroupTrade(req) : InnerSaveEditTrade(req, out var changeConfirmStatus)); //销售佣金数据处理 if (dbTrade.TradeType == "结构化交易") { foreach (var subTrade in req.SubTrades) { if (subTrade.SalesCommission != null) { subTrade.SalesCommission.ClientId = subTrade.ClientId; if (PS.Config.ErpElement.SalesCommissionCalculation == "默认" || PS.Config.ErpElement.SalesCommissionCalculation == "" || PS.Config.ErpElement.SalesCommissionCalculation == null) { new SalesCommissionDataService(this).SaveTradeCommission(subTrade.id, subTrade.SalesCommission, false); } else if (PS.Config.ErpElement.SalesCommissionCalculation == "公式1") { if (req.SalesCommission?.SalesIds != null && req.SalesCommission.SalesIds.Any()) { new SalesCommissionDetailDataService(this).SaveTradeCommissionDetail(subTrade.id, subTrade.SalesCommission.ClientId, subTrade.SalesCommission.Commission, subTrade.SalesCommission.CommissionFixed, subTrade.SalesCommission.SalesIds, false); } else { new SalesCommissionDetailDataService(this).RemoveTradeCommissionDetail(subTrade.id); } } else { } //todo } if (dbTrade.StructureType == "折价" && PS.Config.Is国泰君安) { saveZheJiaTradeMarginTemplate(subTrade, dbTrade); } } } else { if (req.SalesCommission != null) { req.SalesCommission.ClientId = dbTrade.ClientId; } if (PS.Config.ErpElement.SalesCommissionCalculation == "默认" || PS.Config.ErpElement.SalesCommissionCalculation == "" || PS.Config.ErpElement.SalesCommissionCalculation == null) { new SalesCommissionDataService(this).SaveTradeCommission(dbTrade.id, req.SalesCommission, false); } else if (PS.Config.ErpElement.SalesCommissionCalculation == "公式1") { if (req.SalesCommission?.SalesIds != null && req.SalesCommission.SalesIds.Any()) { new SalesCommissionDetailDataService(this).SaveTradeCommissionDetail(dbTrade.id, req.SalesCommission.ClientId, req.SalesCommission.Commission, req.SalesCommission.CommissionFixed, req.SalesCommission.SalesIds, false); } else { new SalesCommissionDetailDataService(this).RemoveTradeCommissionDetail(dbTrade.id); } } else { } //todo } //执行事务 if (noTrans) { trans.Commit(); } return dbTrade; } finally { if (noTrans) { trans?.Dispose(); } } } public trade SaveGroupTrade(OtcOptionTradeFull req, int[] tradeIds) { if (req.id > 0 && ConsTrade.TradeStatusAfterConfirmed.Contains(req.TradeStatus)) { new TradeBackService(UserInfo).BackGroup(req.id, true, TradeBackActionEnum.EditMaturityDate); } var countRatio = (DataCacheProvider.GetUnderlyingDataSource().GetData(req.UnderlyingId)?.CountRatio) ?? 1; if (req.IsUsePremiumRate == true) { req.Notional = req.SpotPrice != null && req.SpotPrice != 0 ? req.StockEqvNotional / req.SpotPrice.Value : 0; req.TradeAmount = req.Notional / countRatio; } else { req.Notional = req.TradeAmount * countRatio; req.StockEqvNotional = req.Notional * req.SpotPrice ?? 0; } req.PremiumRate = req.StockEqvNotional != 0 ? (req.TradePrice ?? 0) / req.StockEqvNotional : 0; req.TradeSinglePrice = req.Notional != 0 ? (req.TradePrice ?? 0) / req.Notional : 0; var dbTrade = TradeConverter.ConvertOptionTrade(req); dbTrade.StartDate = dbTrade.TradeDate; dbTrade.SettlementDate = dbTrade.ExerciseDate; dbTrade.OriginalNotional = dbTrade.Notional; dbTrade.OriginalStockEqvNotional = dbTrade.StockEqvNotional; dbTrade.StockEqvNotionalMax = dbTrade.StockEqvNotional; dbTrade.StockEqvNotionalReal = TradeHelper.GetStockEqvNotionalReal(dbTrade.StockEqvNotional, dbTrade.ParticipationRate, dbTrade.AnnualizeFactor); if (req.id > 0) { var trade = DbContext.trade.AsNoTracking().FirstOrDefault(x => x.id == req.id); if (trade == null) { throw new ServiceException($"该交易不存在"); } var isDiffStructureType = trade.StructureType != req.StructureType; trade.SpotPrice = req.SpotPrice; trade.ExerciseDate = dbTrade.ExerciseDate; trade.SettlementDate = dbTrade.ExerciseDate; trade.BuySell = dbTrade.BuySell; trade.IsUsePremiumRate = dbTrade.IsUsePremiumRate; trade.TradeAmount = dbTrade.TradeAmount; trade.Notional = dbTrade.Notional; trade.OriginalNotional = dbTrade.OriginalNotional; trade.StockEqvNotional = dbTrade.StockEqvNotional; trade.OriginalStockEqvNotional = dbTrade.OriginalStockEqvNotional; trade.StockEqvNotionalReal = dbTrade.StockEqvNotionalReal; trade.TradeSinglePrice = dbTrade.TradeSinglePrice; trade.PremiumRate = dbTrade.PremiumRate; trade.TradePrice = dbTrade.TradePrice; trade.IsMoneynessOption = dbTrade.IsMoneynessOption; trade.StructureType = dbTrade.StructureType; trade.Strike = dbTrade.Strike; trade.AssetId = dbTrade.AssetId; trade.AssetBookName = dbTrade.AssetBookName; trade.TraderId = dbTrade.TraderId; trade.TraderName = dbTrade.TraderName; trade.Comments = dbTrade.Comments; trade.StockEqvNotionalMax = dbTrade.StockEqvNotionalMax; if (trade.StructureType == "气囊结构") { trade.ExtendInfo = null; trade.trade_airbag = dbTrade.trade_airbag; trade.OptionType = dbTrade.OptionType; } else { trade.ExtendInfo = dbTrade.ExtendInfo; } if (DbContext.trade.Any(n => n.TradeNumber == req.TradeNumber && n.id != req.id)) { throw new ServiceException($"交易编号'{req.TradeNumber}'已经存在"); } else if (PS.Config.ErpElement.UpperTradeNumber) { trade.TradeNumber = req.TradeNumber.ToUpperInvariant(); } trade.MetaDic = dbTrade.MetaDic; InnerSaveEditTrade(trade, out var changeConfirmStatus); var subTrades = DbContext.trade.Where(x => x.ParentTradeId == trade.id).ToList(); subTrades.ForEach(x => { x.StructureType = trade.StructureType; if (dbTrade.StructureType == "折价" && isDiffStructureType && PS.Config.Is国泰君安) { saveZheJiaTradeMarginTemplate(x, dbTrade); } }); DbContext.SaveChanges(); SaveTradeOperationHistory(trade, "修改组合交易"); using (var tagService = new TagService(OptUser)) { tagService.SetTradeTagForTradeEdit(new TagModule.Dto.SetTradeTagForTradeEditRequest { TradeId = trade.id, Tags = req.Tags }); } return trade; } else if (tradeIds == null || !tradeIds.Any()) { throw new ServiceException("缺少子交易"); } else { SetDBModelCreator(dbTrade); DbContext.trade.Add(dbTrade); dbTrade.TradeStatus = ConsTrade.新增待确认; dbTrade.TradeSource = _source.ToString(); dbTrade.TradeType = "结构化交易"; dbTrade.IsGroup = 1; var copyLeg = DbContext.trade.Where(x => tradeIds.Contains(x.id) && x.UnderlyingId > 0).First(); //dbTrade.MetaDic = new TradeMetaService(this).GetTradeMeta(copyLeg.id); dbTrade.UnderlyingCode = copyLeg.UnderlyingCode; if (!string.IsNullOrEmpty(dbTrade.UnderlyingCode)) { var preHandler = new TradeSavePreHandler(this); preHandler.PrepareUnderlying(dbTrade, false); } dbTrade.SpotPrice = copyLeg.SpotPrice; dbTrade.ParticipationRate = 1; dbTrade.CreateDate = DateTime.Now; if (string.IsNullOrWhiteSpace(req.TradeNumber) && req.id == 0) { dbTrade.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(dbTrade, DbContext); //没有期货报送成交编号添加到dictionary,有则修改该key的值 if (PS.Config.Is招证) { if (req.MetaDic == null) { req.MetaDic = new Dictionary(); } if (dbTrade.MetaDic == null) { dbTrade.MetaDic = new Dictionary(); } req.MetaDic["期货报送成交编号"] = dbTrade.TradeNumber; dbTrade.MetaDic["期货报送成交编号"] = dbTrade.TradeNumber; } } else if (DbContext.trade.Any(n => n.TradeNumber == req.TradeNumber && n.id != req.id)) { throw new ServiceException($"交易编号'{req.TradeNumber}'已经存在"); } else if (PS.Config.ErpElement.UpperTradeNumber) { dbTrade.TradeNumber = req.TradeNumber.ToUpperInvariant(); } DbContext.SaveChanges(); //交易元数据 if (req.MetaDic.Any()) { foreach (var kv in req.MetaDic) { if (!string.IsNullOrEmpty(kv.Value)) { AddTradeMeta(true, dbTrade.id, kv.Key, kv.Value); } } } new TradeSaveExtend(this, true).Save(dbTrade, dbTrade); var subTrades = DbContext.trade.Where(x => tradeIds.Contains(x.id)).ToList(); subTrades.ForEach(x => { x.IsGroup = 2; x.ParentTradeId = dbTrade.id; x.StructureType = dbTrade.StructureType; if (dbTrade.StructureType == "折价" && PS.Config.Is国泰君安) { saveZheJiaTradeMarginTemplate(x, dbTrade); } }); using (var tagService = new TagService(OptUser)) { tagService.SetTradeTagForTradeEdit(new TagModule.Dto.SetTradeTagForTradeEditRequest { TradeId = dbTrade.id, Tags = req.Tags }); //subTrades.ForEach(d => //{ // tagService.SetTradeTagForTradeEdit(new TagModule.Dto.SetTradeTagForTradeEditRequest // { // TradeId = d.id, // Tags = req.Tags // }); //}); } var subCashs = DbContext.ClientCashInCashOut.Where(x => x.TradeId != null && tradeIds.Contains(x.TradeId.Value)).ToList(); subCashs.ForEach(x => { x.IsGroup = 2; x.ParentTradeNumber = dbTrade.TradeNumber; }); DbContext.SaveChanges(); SaveTradeOperationHistory(dbTrade, "新增组合交易"); var eodTrades = DbContext.eod_trade.Where(x => tradeIds.Contains(x.TradeId)); DbContext.eod_trade.RemoveRange(eodTrades); DbContext.SaveChanges(); return dbTrade; } } //新增交易保存 private trade InnerSaveNewTrade(trade req, bool tradeNumberGenerated) { if (req.ParentTradeId > 0 && req.TradeType == "收益互换") { var parentTrade = DbContext.trade.Find(req.ParentTradeId); if (parentTrade != null && parentTrade.TradeType == "收益互换") { parentTrade.OriginalStockEqvNotional += req.StockEqvNotional; parentTrade.StockEqvNotional += req.StockEqvNotional; parentTrade.StockEqvNotionalReal += req.StockEqvNotional; var tradePrice = (parentTrade.TradePrice ?? 0) * (parentTrade.BuySell == "买入" ? -1 : 1) + (req.TradePrice ?? 0) * (req.BuySell == "买入" ? -1 : 1); parentTrade.TradePrice = Math.Abs(tradePrice); parentTrade.BuySell = tradePrice >= 0 ? "卖出" : "买入"; } } var dbTrade = req.Clone(); dbTrade.trade_swap = req.trade_swap.Clone(); //if (double.IsNaN(dbTrade.TradeSinglePrice.Value)) dbTrade.TradeSinglePrice = 0; //if (double.IsNaN(dbTrade.PremiumRate.Value)) dbTrade.PremiumRate = 0; SetDBModelCreator(dbTrade); DbContext.trade.Add(dbTrade); //申万交易编号特殊处理(如果交易编号是用户手动输入时) if (!tradeNumberGenerated && PS.Config.Is申万) { var client = DataCacheProvider.GetClientDataSource().GetData(dbTrade.ClientId); if (client?.Code != null && dbTrade.TradeNumber.StartsWith(client.Code)) { var canParseInt = int.TryParse(dbTrade.TradeNumber.Substring(client.Code.Length), out var contractNo); if (canParseInt && contractNo > (client.CurrentContractNo ?? 0)) { client.CurrentContractNo = contractNo; } } } if (req.TradeType == "收益互换" && req.IsGroup == 1) { InnerSaveTrade2(true, dbTrade, dbTrade, true); if (req.get_trade_swap_details.Any()) { var index = 1; foreach (var detail in dbTrade.get_trade_swap_details) { var trade = req.Clone(); trade.get_trade_swap_details = new List(); trade.trade_swap = req.trade_swap.Clone(); if (!string.IsNullOrEmpty(detail.UnderlyingCode)) { var preHandler = new TradeSavePreHandler(this); trade.UnderlyingCode = detail.UnderlyingCode; var underlying = preHandler.PrepareUnderlying(trade, false); trade.trade_swap.SwapType = "普通"; trade.trade_swap.OriginalTradeId = dbTrade.id; if (trade.trade_swap.IsPayFloatingProfit) { trade.trade_swap.GetTradePrice = detail.TradePrice; } else { trade.trade_swap.PayTradePrice = detail.TradePrice; } trade.trade_swap.GetLongShort = detail.LongShort; trade.trade_swap.GetUnderlyingCode = detail.UnderlyingCode; trade.trade_swap.GetUnderlyingId = trade.UnderlyingId; trade.trade_swap.GetSpotPrice = detail.SpotPrice; trade.trade_swap.GetNotional = detail.Notional; trade.trade_swap.GetTradeAmount = trade.trade_swap.GetNotional / underlying.CountRatio; trade.BuySell = (trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) == 0 ? (trade.trade_swap.IsPayFloatingProfit ? "卖出" : "买入") : ((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) > 0 ? "卖出" : "买入"); trade.TradePrice = Math.Abs((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0)); trade.OriginalNotional = detail.Notional; trade.Notional = detail.Notional ?? 0; trade.TradeAmount = trade.trade_swap.GetTradeAmount ?? 0; trade.SpotPrice = detail.SpotPrice; trade.StockEqvNotionalReal = trade.Notional * trade.SpotPrice ?? 0; trade.OriginalStockEqvNotional = trade.StockEqvNotionalReal; trade.StockEqvNotional = trade.StockEqvNotionalReal; trade.ParentTradeId = dbTrade.id; trade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(trade, dbTrade, index, DbContext); index++; trade.IsGroup = 2; trade.TradeStatus = ConsTrade.新增待确认; trade.TradeSource = req.TradeSource; trade.Comments = null; SetDBModelCreator(trade); DbContext.trade.Add(trade); DbContext.SaveChanges(); detail.ChildTradeId = trade.id; InnerSaveTrade2(true, trade, trade, true); } } } else if (req.pay_trade_swap_details.Any()) { var index = 1; foreach (var detail in req.pay_trade_swap_details) { var trade = req.Clone(); trade.pay_trade_swap_details = new List(); trade.trade_swap = req.trade_swap.Clone(); if (!string.IsNullOrEmpty(detail.UnderlyingCode)) { var preHandler = new TradeSavePreHandler(this); trade.UnderlyingCode = detail.UnderlyingCode; var underlying = preHandler.PrepareUnderlying(trade, false); trade.trade_swap.SwapType = "普通"; trade.trade_swap.OriginalTradeId = dbTrade.id; if (trade.trade_swap.IsPayFloatingProfit) { trade.trade_swap.GetTradePrice = detail.TradePrice; } else { trade.trade_swap.PayTradePrice = detail.TradePrice; } trade.trade_swap.PayLongShort = detail.LongShort; trade.trade_swap.PayUnderlyingCode = detail.UnderlyingCode; trade.trade_swap.PayUnderlyingId = trade.UnderlyingId; trade.trade_swap.PaySpotPrice = detail.SpotPrice; trade.trade_swap.PayNotional = detail.Notional; trade.trade_swap.PayTradeAmount = trade.trade_swap.PayNotional / underlying.CountRatio; trade.BuySell = (trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) == 0 ? (trade.trade_swap.IsPayFloatingProfit ? "卖出" : "买入") : ((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) > 0 ? "卖出" : "买入"); trade.TradePrice = Math.Abs((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0)); trade.OriginalNotional = detail.Notional; trade.Notional = detail.Notional ?? 0; trade.TradeAmount = trade.trade_swap.PayTradeAmount ?? 0; trade.SpotPrice = detail.SpotPrice; trade.StockEqvNotionalReal = trade.Notional * trade.SpotPrice ?? 0; trade.OriginalStockEqvNotional = trade.StockEqvNotionalReal; trade.StockEqvNotional = trade.StockEqvNotionalReal; trade.ParentTradeId = dbTrade.id; trade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(trade, dbTrade, index, DbContext); index++; trade.IsGroup = 2; trade.TradeStatus = ConsTrade.新增待确认; trade.TradeSource = req.TradeSource; SetDBModelCreator(trade); DbContext.trade.Add(trade); DbContext.SaveChanges(); detail.ChildTradeId = trade.id; InnerSaveTrade2(true, trade, trade, true); } } } } else if (req.TradeType == "结构化交易" && req.IsGroup == 1) { var copyLeg = dbTrade.SubTrades.Where(x => x.UnderlyingId > 0).First(); dbTrade.MetaDic = copyLeg.MetaDic; dbTrade.UnderlyingCode = copyLeg.UnderlyingCode; if (!string.IsNullOrEmpty(dbTrade.UnderlyingCode)) { var preHandler = new TradeSavePreHandler(this); preHandler.PrepareUnderlying(dbTrade, false); } dbTrade.SpotPrice = copyLeg.SpotPrice; dbTrade.StartDate = dbTrade.TradeDate; dbTrade.SettlementDate = dbTrade.ExerciseDate; var countRatio = (DataCacheProvider.GetUnderlyingDataSource().GetData(copyLeg.UnderlyingId)?.CountRatio) ?? 1; if (dbTrade.IsUsePremiumRate == true) { dbTrade.OriginalStockEqvNotional = dbTrade.StockEqvNotional; dbTrade.StockEqvNotionalReal = dbTrade.StockEqvNotional; dbTrade.Notional = dbTrade.SpotPrice != 0 ? dbTrade.StockEqvNotionalReal / dbTrade.SpotPrice.Value : 0; dbTrade.OriginalNotional = dbTrade.Notional; dbTrade.TradeAmount = dbTrade.Notional / countRatio; dbTrade.TradeSinglePrice = dbTrade.Notional != 0 ? dbTrade.TradePrice / dbTrade.Notional : 0; dbTrade.PremiumRate = dbTrade.StockEqvNotional > 0 ? dbTrade.TradePrice / dbTrade.StockEqvNotional : 0; } else { if (dbTrade.TradeAmount > 0) { dbTrade.Notional = dbTrade.TradeAmount * countRatio; } else { dbTrade.TradeAmount = dbTrade.Notional / countRatio; } dbTrade.OriginalNotional = dbTrade.Notional; dbTrade.StockEqvNotionalReal = dbTrade.Notional * dbTrade.SpotPrice.Value; dbTrade.StockEqvNotional = dbTrade.StockEqvNotionalReal; dbTrade.OriginalStockEqvNotional = dbTrade.StockEqvNotional; } dbTrade.Notional = dbTrade.TradeAmount * countRatio; dbTrade.OriginalNotional = dbTrade.Notional; dbTrade.ParticipationRate = 1; dbTrade.CreateDate = DateTime.Now; DbContext.SaveChanges(); //交易元数据 if (dbTrade.MetaDic.Any()) { foreach (var kv in dbTrade.MetaDic) { if (!string.IsNullOrEmpty(kv.Value)) { AddTradeMeta(true, dbTrade.id, kv.Key, kv.Value); } } } new TradeSaveExtend(this, true).Save(dbTrade, dbTrade); foreach (var subTrade in req.SubTrades) { if (!string.IsNullOrEmpty(subTrade.UnderlyingCode)) { var preHandler = new TradeSavePreHandler(this); preHandler.PrepareUnderlying(subTrade, false); } subTrade.ParentTradeId = dbTrade.id; subTrade.IsGroup = 2; subTrade.TradeStatus = ConsTrade.新增待确认; subTrade.TradeSource = dbTrade.TradeSource; subTrade.StructureType = dbTrade.StructureType; SetDBModelCreator(subTrade); DbContext.trade.Add(subTrade); InnerSaveTrade2(true, subTrade, subTrade, true); } DbContext.TradeAuditLog.Add(new TradeAuditLog { TradeId = dbTrade.id, Changes = string.Empty, DataType = "00", OptType = _source == TradeSourceEnum.导入交易 ? "导入交易" : "新增交易", OptId = UserId, OptName = UserName, OptDate = OptDate, AuditFlag = TradeAuditFlag.operation }); DbContext.SaveChanges(); } else if (req.TradeType == "结构化交易") { var tradeNumber = dbTrade.TradeNumber; //将子交易复制到主交易 var copyLeg = dbTrade.SubTrades.First(); if (copyLeg.StructureType == "三领口组合") { copyLeg = dbTrade.SubTrades.Skip(1).First(); } UpdateEntity(dbTrade, copyLeg); dbTrade.TradeNumber = tradeNumber; dbTrade.TradeType = "结构化交易"; dbTrade.ExerciseDate = req.SubTrades.Max(n => n.ExerciseDate ?? DateTime.MinValue); DbContext.SaveChanges(); if (copyLeg.MetaDic.ContainsKey("合约编号")) { AddTradeMeta(false, dbTrade.id, "合约编号", copyLeg.MetaDic["合约编号"]); } foreach (var subTrade in dbTrade.SubTrades) { subTrade.ParentTradeId = dbTrade.id; subTrade.IsGroup = 0; SetDBModelCreator(subTrade); DbContext.trade.Add(subTrade); InnerSaveTrade2(true, subTrade, subTrade, true); } } else { InnerSaveTrade2(true, dbTrade, dbTrade, true); } return dbTrade; } private void saveZheJiaTradeMarginTemplate(trade subTrade, trade trade) { subTrade.InitialMargin = 0; trade.InitialMargin = 0; var marginTemplate = DbContext.margin_template_v2 .Where(x => x.Name == "无预付金") .ToList() .FirstOrDefault(x => x.IsApplicableToBook(subTrade.AssetId)); if (marginTemplate == null) { marginTemplate = new margin_template_v2() { Name = "无预付金", MarginType = (int)MarginTypeV2Enum.单腿, RuleType = (int)MarginRuleTypeEnum.无预付金, TradeTypes = "香草期权,障碍期权,二元期权,亚式期权,彩虹期权,远期,双鲨期权,凤凰期权,雪球期权,气囊结构,收益互换,区间累积期权,合成价差期权,累计期权,自定义交易", Comments = "预付金占用为零。", IsDefault = false, IsForClient = false, IsValid = true, BuySellType = BuySellEnum.All, MarginScenarios = MarginScenarioEnum.All, OptDate = DateTime.Now, OptId = UserId, OptName = UserName }; DbContext.margin_template_v2.Add(marginTemplate); DbContext.SaveChanges(); } var tradeMarginTemplates = DbContext.trade_margin_template.Where(x => x.TradeId == subTrade.id); DbContext.trade_margin_template.RemoveRange(tradeMarginTemplates); var tradeMarginTemplate = new trade_margin_template() { TradeId = subTrade.id, ValueDate = new DateTime(2000, 1, 1), MarginTemplateId = marginTemplate.id, IsLatest = true, OptId = UserId, OptName = UserName, OptDate = DateTime.Now }; DbContext.trade_margin_template.Add(tradeMarginTemplate); DbContext.SaveChanges(); } private trade InnerSaveEditSwapGroupTrade(trade req) { var details = req.get_trade_swap_details.Union(req.pay_trade_swap_details); if (req.get_trade_swap_details.Any()) { req.trade_swap.PayTradePrice = req.get_trade_swap_details.Sum(x => x.TradePrice ?? 0); } else if (req.pay_trade_swap_details.Any()) { req.trade_swap.GetTradePrice = req.pay_trade_swap_details.Sum(x => x.TradePrice ?? 0); } var changeSwapDetails = false; var tradeSwapDetails = DbContext.trade_swap_detail.Where(x => x.TradeId == req.id).ToList(); tradeSwapDetails.ForEach(x => { var detail = details.FirstOrDefault(y => y.ChildTradeId == x.ChildTradeId); if (detail == null) { changeSwapDetails = true; } else if (detail.UnderlyingCode != x.UnderlyingCode || detail.Notional != x.Notional || detail.SpotPrice != x.SpotPrice || detail.LongShort != x.LongShort || detail.TradePrice != x.TradePrice) { changeSwapDetails = true; } }); if (tradeSwapDetails.Count != details.Count()) { changeSwapDetails = true; } //修改主交易信息 var dbTrade = InnerSaveEditTrade(req, out var changeConfirmStatus); if (changeConfirmStatus) { changeSwapDetails = true; } if (changeSwapDetails) { //先删除子交易 var service = new TradeInvalidService(UserInfo); var ids = new HashSet { dbTrade.id }; var subTrades = DbContext.trade.Where(x => x.ParentTradeId == req.id && x.ValidState != "InValid").ToList(); var subTradeIds = subTrades.Select(x => x.id).ToList(); var swaps = DbContext.trade_swap.Where(x => subTradeIds.Contains(x.TradeId)).ToList(); int? originalTradeId = null; foreach (var subTrade in subTrades) { var swap = swaps.FirstOrDefault(x => x.TradeId == subTrade.id); if (swap != null && swap.OriginalTradeId > 0) { originalTradeId = swap.OriginalTradeId; } ids.Add(subTrade.id); service.InnerInvalidTrade(subTrade); } service.SetCommissionInVaild(ids); //重新生成子交易 if (req.get_trade_swap_details.Any()) { var index = 1; foreach (var detail in req.get_trade_swap_details) { var trade = req.Clone(); trade.get_trade_swap_details = new List(); trade.trade_swap = req.trade_swap.Clone(); trade.trade_swap.OriginalTradeId = originalTradeId ?? dbTrade.id; if (!string.IsNullOrEmpty(detail.UnderlyingCode)) { var preHandler = new TradeSavePreHandler(this); trade.UnderlyingCode = detail.UnderlyingCode; var underlying = preHandler.PrepareUnderlying(trade, false); trade.trade_swap.SwapType = "普通"; if (trade.trade_swap.IsPayFloatingProfit) { trade.trade_swap.GetTradePrice = detail.TradePrice; } else { trade.trade_swap.PayTradePrice = detail.TradePrice; } trade.trade_swap.GetLongShort = detail.LongShort; trade.trade_swap.GetUnderlyingCode = detail.UnderlyingCode; trade.trade_swap.GetUnderlyingId = trade.UnderlyingId; trade.trade_swap.GetSpotPrice = detail.SpotPrice; trade.trade_swap.GetNotional = detail.Notional; trade.trade_swap.GetTradeAmount = trade.trade_swap.GetNotional / underlying.CountRatio; trade.BuySell = (trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) == 0 ? (trade.trade_swap.IsPayFloatingProfit ? "卖出" : "买入") : ((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) > 0 ? "卖出" : "买入"); trade.TradePrice = Math.Abs((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0)); trade.OriginalNotional = detail.Notional; trade.Notional = detail.Notional ?? 0; trade.TradeAmount = trade.trade_swap.GetTradeAmount ?? 0; trade.SpotPrice = detail.SpotPrice; trade.StockEqvNotionalReal = trade.Notional * trade.SpotPrice ?? 0; trade.OriginalStockEqvNotional = trade.StockEqvNotionalReal; trade.StockEqvNotional = trade.StockEqvNotionalReal; trade.ParentTradeId = dbTrade.id; trade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(trade, dbTrade, index, DbContext); index++; trade.IsGroup = 2; trade.TradeStatus = ConsTrade.新增待确认; trade.TradeSource = req.TradeSource; trade.Comments = null; SetDBModelCreator(trade); DbContext.trade.Add(trade); DbContext.SaveChanges(); detail.ChildTradeId = trade.id; InnerSaveTrade2(true, trade, trade, true); } } } else if (req.pay_trade_swap_details.Any()) { var index = 1; foreach (var detail in req.pay_trade_swap_details) { var trade = req.Clone(); trade.pay_trade_swap_details = new List(); trade.trade_swap = req.trade_swap.Clone(); trade.trade_swap.OriginalTradeId = originalTradeId ?? dbTrade.id; if (!string.IsNullOrEmpty(detail.UnderlyingCode)) { var preHandler = new TradeSavePreHandler(this); trade.UnderlyingCode = detail.UnderlyingCode; var underlying = preHandler.PrepareUnderlying(trade, false); trade.trade_swap.SwapType = "普通"; if (trade.trade_swap.IsPayFloatingProfit) { trade.trade_swap.GetTradePrice = detail.TradePrice; } else { trade.trade_swap.PayTradePrice = detail.TradePrice; } trade.trade_swap.PayLongShort = detail.LongShort; trade.trade_swap.PayUnderlyingCode = detail.UnderlyingCode; trade.trade_swap.PayUnderlyingId = trade.UnderlyingId; trade.trade_swap.PaySpotPrice = detail.SpotPrice; trade.trade_swap.PayNotional = detail.Notional; trade.trade_swap.PayTradeAmount = trade.trade_swap.PayNotional / underlying.CountRatio; trade.BuySell = (trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) == 0 ? (trade.trade_swap.IsPayFloatingProfit ? "卖出" : "买入") : ((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) > 0 ? "卖出" : "买入"); trade.TradePrice = Math.Abs((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0)); trade.OriginalNotional = detail.Notional; trade.Notional = detail.Notional ?? 0; trade.TradeAmount = trade.trade_swap.PayTradeAmount ?? 0; trade.SpotPrice = detail.SpotPrice; trade.StockEqvNotionalReal = trade.Notional * trade.SpotPrice ?? 0; trade.OriginalStockEqvNotional = trade.StockEqvNotionalReal; trade.StockEqvNotional = trade.StockEqvNotionalReal; trade.ParentTradeId = dbTrade.id; trade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(trade, dbTrade, index, DbContext); index++; trade.IsGroup = 2; trade.TradeStatus = ConsTrade.新增待确认; trade.TradeSource = req.TradeSource; SetDBModelCreator(trade); DbContext.trade.Add(trade); DbContext.SaveChanges(); detail.ChildTradeId = trade.id; InnerSaveTrade2(true, trade, trade, true); } } } } return dbTrade; } //修改交易保存 private trade InnerSaveEditTrade(trade req, out bool changeConfirmStatus) { var dbTrade = DbContext.trade.Find(req.id); if (dbTrade == null) { throw new ServiceException("保存失败,数据不存在"); } dbTrade.SalesCommission = new SalesCommissionDataService(OptUser).GetTradeCommissionInfo(dbTrade.id); //默认都没填销售信息时,不影响交易状态变更,都赋值空,这样下面GetDataChanges就不会包含commission变更信息 if (dbTrade.SalesCommission?.SalesIds == null && req.SalesCommission?.SalesIds == null) { dbTrade.SalesCommission = null; req.SalesCommission = null; } if (!ConsGlobal.IsValid(dbTrade.ValidState)) { throw new NotSupportedException("不支持对已无效的交易进行修改:" + dbTrade.TradeNumber); } if (req.ParentTradeId > 0 && req.TradeType == "收益互换") { var parentTrade = DbContext.trade.Find(req.ParentTradeId); if (parentTrade != null) { parentTrade.OriginalStockEqvNotional += req.StockEqvNotional - (dbTrade.OriginalStockEqvNotional ?? 0); parentTrade.StockEqvNotional += req.StockEqvNotional - (dbTrade.OriginalStockEqvNotional ?? 0); parentTrade.StockEqvNotionalReal += req.StockEqvNotional - (dbTrade.OriginalStockEqvNotional ?? 0); var tradePrice = (parentTrade.TradePrice ?? 0) * (parentTrade.BuySell == "买入" ? -1 : 1) + (req.TradePrice ?? 0) * (req.BuySell == "买入" ? -1 : 1) - (dbTrade.TradePrice ?? 0) * (dbTrade.BuySell == "买入" ? -1 : 1); parentTrade.TradePrice = Math.Abs(tradePrice); parentTrade.BuySell = tradePrice >= 0 ? "卖出" : "买入"; } } else if (req.IsGroup == 2) { var parentTrade = DbContext.trade.Find(req.ParentTradeId); if (parentTrade != null) { var tradePrice = (parentTrade.TradePrice ?? 0) * (parentTrade.BuySell == "买入" ? -1 : 1) + (req.TradePrice ?? 0) * (req.BuySell == "买入" ? -1 : 1) - (dbTrade.TradePrice ?? 0) * (dbTrade.BuySell == "买入" ? -1 : 1); parentTrade.TradePrice = tradePrice * (parentTrade.BuySell == "买入" ? -1 : 1); if (parentTrade.OriginalNotional != null && parentTrade.OriginalNotional != 0) { parentTrade.TradeSinglePrice = parentTrade.TradePrice / parentTrade.OriginalNotional; } if (parentTrade.OriginalStockEqvNotional != null && parentTrade.OriginalStockEqvNotional != 0) { parentTrade.PremiumRate = TradeHelper.GetPremiumRateByTradePrice(parentTrade.TradePrice, parentTrade.OriginalStockEqvNotional, parentTrade.ParticipationRate, parentTrade.PrincipalSum(), parentTrade.AnnualizeFactor, parentTrade.BuySell, parentTrade.TradeType, true); } } } if (valuedateBLL.SystemDate.EditTradeNeedRemark) { req.MetaDic.TryGetValue("remark", out var remark); req.MetaDic.Remove("remark"); //记录审核日志 DbContext.TradeAuditLog.Add(new TradeAuditLog { TradeId = dbTrade.id, Changes = remark, DataType = "00", OptId = UserId, OptName = UserName, OptDate = OptDate, OptType = "修改交易", AuditFlag = TradeAuditFlag.operation }); } //if (PS.Config.ErpElement.SecuritiesEnvironment && string.IsNullOrWhiteSpace(req.Comments)) //{ // throw new ServiceException("保存失败,交易编辑时,备注为必填字段"); //} //使用明确的IsUsePremiumRate布尔值 if (!req.IsUsePremiumRate.HasValue && dbTrade.IsUsePremiumRate.HasValue) { req.IsUsePremiumRate = false; } req.CalcFlag = dbTrade.CalcFlag; var oldClientId = dbTrade.ClientId; var oldTradeStatus = dbTrade.TradeStatus; var tradeDateChanged = dbTrade.TradeDate != req.TradeDate; //移除价格观察 if (dbTrade.UnderlyingId != req.UnderlyingId) { RemoveEntities(x => x.TradeId == req.id); } //移除观察日 if (dbTrade.TradeType == "凤凰期权") { RemoveEntities(x => x.TradeId == dbTrade.id); } //移除可能的TradeMeta中组合标的信息 RemoveEntities(x => x.TradeId == dbTrade.id && x.MetaKey.StartsWith(ConsTradeMetaKey.SyntheticUnderlying)); //交易编号调整 var canGenerateTradeNumber = false; if (req.ValidState == "InValid") { if (!string.IsNullOrWhiteSpace(dbTrade.TradeNumber)) { new TradeDocumentDataService(this).DeleteConfirmBook(dbTrade.id); if (dbTrade.TradeNumber.StartsWith("CW")) { req.TradeNumber = dbTrade.TradeNumber.Replace("CW", "XX"); } else // if (PS.Config.Is光大光子) { req.TradeNumber = dbTrade.TradeNumber.Insert(0, "XX"); } } } else { canGenerateTradeNumber = string.IsNullOrWhiteSpace(req.TradeNumber); if (canGenerateTradeNumber) { req.TradeNumber = dbTrade.TradeNumber; } } req.ContractVersion = dbTrade.ContractVersion; req.PairTrade = dbTrade.PairTrade; req.CreateDate = dbTrade.CreateDate; //确认成交状态的交易修改后变为原始标记 req.DividendDate = new DateTime(2000, 1, 1); //记录交易变更信息 var changsStr = string.Empty; changeConfirmStatus = true; TradeAuditFlag auditFlag = 0; tradeBLL.SetFieldsByTradeType(dbTrade); if (req.TradeType == "障碍期权") { req.trade_barrier_option.KnockInOutNotional = dbTrade.trade_barrier_option.KnockInOutNotional; req.trade_barrier_option.KnockInOutDate = dbTrade.trade_barrier_option.KnockInOutDate; } var changes = DataChangeHelper.GetDataChanges(dbTrade, req); if (req.TradeType == "远期" && changes.Any()) { changes = changes.Where(x => x[0] != "TradeSinglePrice" && x[0] != "TradeSinglePriceString").ToList(); foreach (var item in changes) { if (item[0] == "OptionType") { item[1] = "多头空头"; item[2] = item[2].Replace("看涨", "多头").Replace("看跌", "空头"); item[3] = item[3].Replace("看涨", "多头").Replace("看跌", "空头"); } else if (item[0] == "TradePrice") { item[1] = "开仓总费用"; } } } var dbTradeMeta = DbContext.TradeMeta.Where(a => a.TradeId == dbTrade.id).ToDictionary(a => a.MetaKey, b => b.MetaValue); var changMetas = new List>(); var keys = new string[] { "ExchangeRate", "交易场所", "清算机构", "主协议编号", "补充协议编号", "中央对手方清算", "中央清算平台", "交易平台", "收取周期", "支付周期", "敲入观察周期", "敲出观察周期" }; foreach (var key in keys) { bool isdbMeta = dbTradeMeta.TryGetValue(key, out string oldVal); bool isreqMeta = req.MetaDic.TryGetValue(key, out string newVal); if (!isdbMeta && !isreqMeta || oldVal == newVal || (string.IsNullOrWhiteSpace(oldVal) && string.IsNullOrWhiteSpace(newVal))) { continue; } var changeMeta = new List() { "", key, oldVal, newVal }; changMetas.Add(changeMeta); } if (changMetas.Any()) { changes.AddRange(changMetas); } changsStr = changes.ToJson(); TradeHelper2.ReduceTradeExt(dbTrade); TradeHelper2.ReduceTradeExt(req); if (dbTrade.TradeStatus != ConsTrade.新增待确认) { //var changes = TradeChangeUtil.GetAllChanges(dbTrade, req); //changsStr = TradeChangeUtil.SerializeChanges(changes, out auditFlag); if (PS.Config.Company == CompanyEnum.东莞) { changeConfirmStatus = changes.Any(); } else { //修改备注和簿记不需要提交审核和审批 changeConfirmStatus = !changes.All(n => string.IsNullOrEmpty(n[0]) || n[0] == nameof(trade.Comments) || n[0] == nameof(trade.AssetId) || n[0] == nameof(trade.AssetBookName)); } } //记录审核日志 DbContext.TradeAuditLog.Add(new TradeAuditLog { TradeId = dbTrade.id, Changes = changsStr, DataType = "C02", OptId = UserId, OptName = UserName, OptDate = OptDate, OptType = "修改交易", AuditFlag = TradeAuditFlag.operation | auditFlag }); //清除累计期权换月设置 ClearAccumulatorChangeDatas(dbTrade, req); //更新数据库实体 UpdateEntity(dbTrade, req); //交易状态处理 if (dbTrade.CheckTradeUpdate == Convert.ToInt32(TradeCheckEnum.StatusOfNew) || dbTrade.TradeStatus == ConsTrade.确认成交) { if (changeConfirmStatus) { dbTrade.TradeStatus = ConsTrade.修改待确认; dbTrade.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfOld); dbTrade.CheckStatus = null; } } else if (dbTrade.TradeStatus != ConsTrade.修改待确认) { dbTrade.TradeStatus = ConsTrade.新增待确认; dbTrade.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfOld); dbTrade.CheckStatus = null; //如果是新增待确认并且修改了客户,需要重新生成交易编号 if (oldClientId != dbTrade.ClientId && canGenerateTradeNumber) { dbTrade.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(dbTrade, DbContext); } } if (changeConfirmStatus) { if (dbTrade.TradeType == "障碍期权") { req.trade_barrier_option.KnockInOutNotional = null; req.trade_barrier_option.KnockInOutDate = null; req.trade_barrier_option.KnockInOutStatus = null; } else if (req.TradeType == "气囊结构") { req.trade_airbag.KnockInOutStatus = null; req.trade_airbag.KnockInOutDate = null; req.trade_airbag.KnockInOutNotional = null; } } dbTrade.TradeOldStatus = oldTradeStatus; //修改结构化交易父交易的状态 if (dbTrade.ParentTradeId > 0 && dbTrade.IsGroup == 0) { var parentTrade = DbContext.trade.FirstOrDefault(n => n.id == dbTrade.ParentTradeId); if (parentTrade != null) { SetParentTrade(dbTrade, parentTrade); //结构化交易子交易修改了交易编号的处理(需要用户自己规范交易编号,必须带有横杠分隔符) if (!string.IsNullOrWhiteSpace(req.TradeNumber) && !req.TradeNumber.StartsWith(parentTrade.TradeNumber)) { UpdateStructureTradeNumbers(parentTrade, dbTrade); } } } //配对交易数据同步修改 if (!string.IsNullOrWhiteSpace(dbTrade.PairTrade)) { SetPairTrade(dbTrade); } //重置历史数据(20210928:如果是当天修改也支持重置) var resetHisData = dbTrade.TradeStatus == "新增待确认" || tradeDateChanged || valuedateBLL.ValueDate == dbTrade.TradeDate; if (resetHisData) { dbTrade.TradeSavedVol = PS.Config.Is厦门象屿 ? dbTrade.TradeCloseVolatility : dbTrade.TradeOpenVolatility; if (PS.Config.ErpElement.VolMode == Configuration.VolModeEnum.VolSurface) { dbTrade.TradeSavedVol = dbTrade.Vol; } } new ExtensionTimeService(UserInfo, DbContext).DelExtensionTime(dbTrade.id, DateTime.MinValue, false); InnerSaveTrade2(false, dbTrade, req, resetHisData, changeConfirmStatus); return dbTrade; } //用于交易(不能是结构化主交易)入库后续处理 //changeConfirmStatus:保存交易修改时需要 private void InnerSaveTrade2(bool isAddNew, trade dbTrade, trade req, bool resetHisData, bool changeConfirmStatus = false) { //System.Diagnostics.Debug.Assert(dbTrade.TradeType != "结构化交易"); //期初价格确认状态(20210720:等需要时再放开) //SetInitialSpotPriceState(isAddNew, dbTrade); //保存修改 DbContext.SaveChanges(); //扩展数据保存 new TradeSaveExtend(this, isAddNew).Save(req, dbTrade); //保存历史数据(新增或交易状态为新增待确认或交易日期变更) if (resetHisData) { SaveHisDataForNewTrade(dbTrade); } //交易元数据 if (req.MetaDic.Any()) { foreach (var kv in req.MetaDic) { if (isAddNew) { if (!string.IsNullOrEmpty(kv.Value)) { AddTradeMeta(false, dbTrade.id, kv.Key, kv.Value); } } else { AddOrUpdateTradeMeta(false, dbTrade.id, kv.Key, kv.Value); } } } if (isAddNew) { var auditLog = new TradeAuditLog { TradeId = dbTrade.id, Changes = string.Empty, DataType = "00", OptType = "新增交易", OptId = UserId, OptName = UserName, OptDate = OptDate, AuditFlag = TradeAuditFlag.operation }; if (_source == TradeSourceEnum.导入交易) { auditLog.OptType = "导入交易"; } //记录审核日志 DbContext.TradeAuditLog.Add(auditLog); } else if (changeConfirmStatus) { //删除交易确认书 new TradeDocumentDataService(this).DeleteBooksAfterEditTrade(dbTrade); //保存客户资金 new ClientCashInCashOutService(this).SaveClientCashInCashOut(dbTrade); //删除票息记录 DbContext.autocall_observation.RemoveRange(DbContext.autocall_observation.Where(n => n.TradeId == dbTrade.id)); } //删除E/Bod_Trade记录(tradedate也可能会被修改) //如果修改不需要修改确认状态,客户资金相关数据不删除 RemoveEodTradeAndFutureInfo(false, dbTrade.id, changeConfirmStatus ? DateTime.MinValue : DateTime.MaxValue, deleteOtherCashs: true); if (dbTrade.InitialMargin == null && dbTrade.TradeType != "自定义交易" && dbTrade.TradeType != "结构化交易" && ((req.IsGroup != 1 && dbTrade.TradeType != "收益互换") || (req.IsGroup != 2 && dbTrade.TradeType == "收益互换"))) { dbTrade.InitialMargin = MarginDefault.GetInitialMarginWithPreHandle(dbTrade); } DbContext.SaveChanges(); } //配对交易数据同步修改 private void SetPairTrade(trade dbTrade) { var id = Convert.ToInt32(dbTrade.PairTrade); var pairTrade = DbContext.trade.Find(id); pairTrade.UnderlyingId = dbTrade.UnderlyingId; pairTrade.UnderlyingCode = dbTrade.UnderlyingCode; pairTrade.UnderlyingAssetClass = dbTrade.UnderlyingAssetClass; pairTrade.UnderlyingAssetName = dbTrade.UnderlyingAssetName; pairTrade.UnderlyingInstrumentType = dbTrade.UnderlyingInstrumentType; pairTrade.BuySell = dbTrade.BuySell == "买入" ? "卖出" : "买入"; pairTrade.ExerciseMode = dbTrade.ExerciseMode; pairTrade.OptionType = dbTrade.OptionType; pairTrade.StartDate = dbTrade.StartDate; pairTrade.ExerciseDate = dbTrade.ExerciseDate; pairTrade.Strike = dbTrade.Strike; pairTrade.StockEqvNotional = dbTrade.StockEqvNotional; // 场内期权交易不应该有标的期初价格 pairTrade.SpotPrice = dbTrade.TradeType == "场内期权" ? null : dbTrade.SpotPrice; pairTrade.Notional = dbTrade.Notional; pairTrade.OriginalNotional = dbTrade.OriginalNotional; pairTrade.OriginalStockEqvNotional = dbTrade.OriginalStockEqvNotional; pairTrade.TradeAmount = dbTrade.TradeAmount; pairTrade.TradePrice = pairTrade.PremiumRate == null || pairTrade.PremiumRate <= 0 ? pairTrade.TradePrice : (pairTrade.StockEqvNotional * pairTrade.PremiumRate); pairTrade.TradeSinglePrice = TradeHelper.GetTradeSinglePriceByTradePrice(pairTrade.TradePrice, pairTrade.Notional, pairTrade.OriginalPrincipalSum, pairTrade.BuySell, pairTrade.TradeType, true); } //为新增交易保存历史数据(持仓平仓波动率、对冲波动率、分红率、无风险利率) private void SaveHisDataForNewTrade(trade tr) { if (tr.id < 1) { throw new ServiceException("trade id不正确"); } var valueDate = tr.TradeDate ?? DateTime.Today; if (tr.TradeType != "远期" && tr.TradeType != "收益互换" && tr.TradeType != "现金流交易") { //---------------------------------- // trade_volatility //---------------------------------- _ = RemoveEntities(x => x.TradeId == tr.id); if (PS.Config.ErpElement.VolMode == VolModeEnum.VolSurface) { tr.TradeSavedVol ??= tr.Vol; tr.TradeOpenVolatility ??= tr.Vol; tr.TradeCloseVolatility ??= tr.Vol; tr.NumOfSmoothingDays = 1; } var tradVolatility = new TradeVolatility { TradeId = tr.id, ValueDate = valueDate, OptId = tr.OptId, OptName = tr.OptName, OptDate = DateTime.Now, NumOfSmoothingDays = tr.NumOfSmoothingDays, TradeCloseVolatility = tr.TradeCloseVolatility, TradePositionVolatility = tr.TradeOpenVolatility, IsFromTradeAdd = true }; DbContext.TradeVolatility.Add(tradVolatility); if (PS.Config.Company == Configuration.CompanyEnum.光大光子 && tradVolatility.TradePositionVolatility.HasValue && NumberHelper.TryParse(PS.Config.ErpElement.TradeOpenVolOff, out var d, out var isPercent) && d <= 1) { var openVol = tr.TradeOpenVolatility.Value; //开仓波动率高于目标波动率,则减点,否则加点 var positionVol = openVol - (openVol - tr.TradeCloseVolatility.Value) * d; //第一天使用折扣后的波动率(对冲+持仓) tr.TradeSavedVol = tradVolatility.TradePositionVolatility = positionVol; var clone = tradVolatility.Clone(); //第一天使用折扣后的波动率(不要平滑处理) tradVolatility.NumOfSmoothingDays = 1; tradVolatility.TradeCloseVolatility = positionVol; //第一天之后使用平滑波动率 clone.ValueDate = QdpModule.QdpCalendarHelper.GetNonHoliday(tradVolatility.ValueDate.AddDays(1)); DbContext.TradeVolatility.Add(clone); } //---------------------------------- // trade_hedge_vol //---------------------------------- _ = RemoveEntities(x => x.TradeId == tr.id); var hedgeTradeVol = new trade_hedge_vol { TradeId = tr.id, ValueDate = valueDate, OptId = tr.OptId, OptName = tr.OptName, OptDate = DateTime.Now, TradeSavedVol = tr.TradeSavedVol ?? 0 }; DbContext.trade_hedge_vol.Add(hedgeTradeVol); } //---------------------------------- // trade_hisdata:NoRiskRate + DividendRate //---------------------------------- RemoveEntities(x => x.TradeId == tr.id); var hisDataNoRisk = new TradeHisData { TradeId = tr.id, ValueDate = valueDate, ValueType = ConsTradeField.NoRiskRate, Value = tr.NoRiskRate ?? ((valuedateBLL.SystemDate.RiskFreeRate ?? 0) / 100), OptId = tr.OptId, OptName = tr.OptName, OptDate = DateTime.Now }; DbContext.TradeHisData.Add(hisDataNoRisk); if (hisDataNoRisk.Value < 1e-5) { LogFactory.GetLogger(nameof(SaveHisDataForNewTrade)).Info($"[NoRiskRate]{tr.id}--{tr.NoRiskRate}--{valuedateBLL.SystemDate.RiskFreeRate}--{tr.OptName}"); } if (tr.DividendRate.HasValue) { var hisDataDividendRate = new TradeHisData { TradeId = tr.id, ValueDate = valueDate, ValueType = ConsTradeField.DividendRate, Value = tr.DividendRate.Value, OptId = tr.OptId, OptName = tr.OptName, OptDate = DateTime.Now, }; DbContext.TradeHisData.Add(hisDataDividendRate); } } //结构化交易子交易修改了交易编号的处理 private void UpdateStructureTradeNumbers(trade parentTrade, trade saveTrade) { //浙期的子交易编号中不包含-,分腿编号是最后一位数字 var index = PS.Config.Company == Configuration.CompanyEnum.浙期 ? saveTrade.TradeNumber.Length - 1 : saveTrade.TradeNumber.LastIndexOf('-'); if (index < 1) { return; } //修改父交易的交易编号 parentTrade.TradeNumber = saveTrade.TradeNumber.Substring(0, index); //修改兄弟交易的交易编号 var siblingTds = DbContext.trade.Where(n => n.id != saveTrade.id && n.ParentTradeId == parentTrade.id).ToArray(); foreach (var std in siblingTds) { index = PS.Config.Company == Configuration.CompanyEnum.浙期 ? std.TradeNumber.Length - 1 : std.TradeNumber.LastIndexOf('-'); if (index > 0) { std.TradeNumber = parentTrade.TradeNumber + std.TradeNumber.Substring(index); } } } //清除累计期权换月设置 private void ClearAccumulatorChangeDatas(trade dbTrade, trade req) { if (dbTrade.TradeType != "累计期权") { return; } var changed = dbTrade.TradeType != req.TradeType || dbTrade.TradeDate != req.TradeDate || dbTrade.ExerciseDate != req.ExerciseDate || dbTrade.Strike != req.Strike || dbTrade.UnderlyingCode != req.UnderlyingCode || dbTrade.trade_accumulator_option.PayoffType != req.trade_accumulator_option.PayoffType || dbTrade.trade_accumulator_option.KOBarrier != req.trade_accumulator_option.KOBarrier || dbTrade.trade_accumulator_option.KOObservationDates != req.trade_accumulator_option.KOObservationDates; if (!changed) { return; } var actions = DbContext.TradeAction.Where(n => n.TradeId == dbTrade.id && n.IsValid && n.ActionType == TradeActionType.AccumulatorChange).ToArray(); foreach (var action in actions) { action.IsValid = false; } } } } //从远期交易保存上拷贝而来,暂时备份看看是否有用 //if (dbTrade.CheckTradeUpdate == Convert.ToInt32(TradeCheckEnum.StatusOfNew)) //{ // dbTrade.TradeStatus = ConsTrade.修改待确认; //} //else //{ // if (dbTrade.TradeStatus == ConsTrade.审批中) // { // dbTrade.ProcessOrderId = 1; // dbTrade.ProcessOptDate = DateTime.Now; // dbTrade.ProcessStatus = "审批中"; // dbTrade.TradeStatus = ConsTrade.新增待确认; // } // if (dbTrade.TradeStatus == ConsTrade.已拒绝) // { // if (dbTrade.CheckTradeUpdate == Convert.ToInt32(TradeCheckEnum.StatusOfNew)) // { // dbTrade.TradeStatus = ConsTrade.修改待确认; // } // else // { // dbTrade.TradeStatus = ConsTrade.新增待确认; // } // dbTrade.ProcessOrderId = 0; // dbTrade.ProcessOptDate = DateTime.Now; // dbTrade.ProcessStatus = "未审批"; // } //}