using YLErp.BLL; using YLErp.CustomizedBizLogic; using YLErp.DBModels.Consts; using YLErp.DBModels.Enums; using YLErp.Enums; using YLErp.Model; using YLErp.Model.Enum; using YLErp.Models; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.Modules.TradeModule; using YLErp.Modules.TradeModule.DealModule; using YLErp.Modules.TradeModule.DocGenerateModule; using YLErp.Modules.TradeModule.OrderModule; using YLErp.QdpModule; namespace YLErp.Modules.EodModule { /// /// 日终结算服务 /// public class EodHandleSwapFlowService : TradeServiceBase { public EodHandleSwapFlowService(OptUserInfo userInfo) : base(userInfo) { } public void ComposeGroupTrade(string tradeNumber) { using (var trans = BeginTransaction()) { var tradeNumbers = DbContext.trade_swap_flow.Where(x => x.TradeDate == valuedateBLL.ValueDate && x.TradeNumber != null && x.TradeNumber != "").Select(x => x.TradeNumber).Distinct().ToList(); if (!string.IsNullOrWhiteSpace(tradeNumber)) { tradeNumbers = tradeNumbers.Where(x => x == tradeNumber).ToList(); } if (tradeNumbers.Any()) { var flows = DbContext.trade_swap_flow.Where(x => x.TradeDate == valuedateBLL.ValueDate && tradeNumbers.Contains(x.TradeNumber)).ToList(); tradeNumbers.ForEach(x => { var hasNoPosition = true; var originalTrade = DbContext.trade.FirstOrDefault(y => y.TradeNumber == x); if (originalTrade == null) { throw new ServiceException($"未找到该交易编号:{x}"); } else { var client = DataCacheProvider.GetClientDataSource().GetData(originalTrade.ClientId); if (!client.DerivativesInvestmentVarieties.Contains((int)DerivativesInvestmentVarietiesEnum.场外互换 + "")) { throw new ServiceException($"客户:{client.Name}未设置交易种类“场外互换”,无法生成互换交易!"); } var tradeFlows = flows.Where(y => y.TradeNumber == x).ToList(); #region 还原之前收盘产生的历史数据 var originalTradeId = originalTrade.id; //获取收盘日当天已经生成的交易,需要先做删除,再重新生成 var todayTradeIds = (from td in DbContext.trade.Where(y => y.TradeDate == valuedateBLL.ValueDate && y.ValidState != "InValid") join swap in DbContext.trade_swap.Where(y => y.OriginalTradeId == originalTradeId && y.SwapType == "普通") on td.id equals swap.TradeId select td.id).ToList(); if (todayTradeIds.Any()) { todayTradeIds.ForEach(y => { new TradeInvalidService(this).InvalidTrade(y, false); }); var tradeSwapDetails = DbContext.trade_swap_detail.Where(y => todayTradeIds.Contains(y.ChildTradeId)); DbContext.trade_swap_detail.RemoveRange(tradeSwapDetails); DbContext.SaveChanges(); } //对当天主交易做初始化处理 var todayParentTradesIds = (from td in DbContext.trade.Where(y => y.TradeDate == valuedateBLL.ValueDate && y.ParentTradeId == 0 && y.ValidState != "InValid") join swap in DbContext.trade_swap.Where(y => y.SwapType == "多空组合") on td.id equals swap.TradeId where td.id == originalTradeId || swap.OriginalTradeId == originalTradeId select td.id).ToList(); if (todayParentTradesIds.Any()) { var todayParentTrades = DbContext.trade.Where(y => todayParentTradesIds.Contains(y.id)).ToList(); todayParentTrades.ForEach(y => { y.TradeStatus = "确认成交"; y.StockEqvNotional = 0; y.OriginalStockEqvNotional = 0; y.StockEqvNotionalReal = 0; y.TradePrice = 0; }); DbContext.SaveChanges(); } var preTradeDate = (from td in DbContext.trade.Where(y => y.TradeDate < valuedateBLL.ValueDate && y.ParentTradeId > 0 && y.ValidState != "InValid") join swap in DbContext.trade_swap.Where(y => y.OriginalTradeId == originalTradeId) on td.id equals swap.TradeId select td.TradeDate).ToList().Max(); var preTradeDateTradeIds = (from td in DbContext.trade.Where(y => y.TradeDate == preTradeDate && y.ParentTradeId > 0 && y.ValidState != "InValid") join swap in DbContext.trade_swap.Where(y => y.OriginalTradeId == originalTradeId) on td.id equals swap.TradeId select td.id).ToList(); if (preTradeDateTradeIds.Any()) { preTradeDateTradeIds.ForEach(y => { new TradeBackService(this).Execute(y, true, TradeBackActionEnum.backTrade); }); } #endregion #region 生成新的开平仓记录 var preTradeDateTrades = (from td in DbContext.trade.Where(y => y.TradeDate == preTradeDate && y.ParentTradeId > 0 && y.ValidState != "InValid") join swap in DbContext.trade_swap.Where(y => y.OriginalTradeId == originalTradeId) on td.id equals swap.TradeId select new { td, swap }).ToList(); //前一天存在持仓的场景 //先平仓再开仓的情景时,只有完全平仓的子交易:合成的流水手续费记为平仓手续费,存在持仓的子交易:合成的流水手续费记为开仓手续费。 if (preTradeDateTrades.Any()) { var newParentTradeId = 0; //对前一天的持仓标的做先平仓后开仓处理 preTradeDateTrades.ForEach(y => { var notional = (y.swap.IsPayFloatingProfit ? y.swap.PayNotional : y.swap.GetNotional) ?? 0; var longShort = y.swap.IsPayFloatingProfit ? y.swap.PayLongShort : y.swap.GetLongShort; var spotPrice = (y.swap.IsPayFloatingProfit ? y.swap.PaySpotPrice : y.swap.GetSpotPrice) ?? 0; y.td.trade_swap = y.swap; var totalNotional = notional * (longShort == "多头" ? 1 : -1); var totalSpotPrice = totalNotional * spotPrice; var underlyingTradeFlows = tradeFlows.Where(z => z.UnderlyingCode == y.td.UnderlyingCode); var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(y.td.UnderlyingCode); var sumBuyLots = underlyingTradeFlows.Sum(z => z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)); if (sumBuyLots > 0) { var sumBuyNotional = sumBuyLots * underlying.ContractSize; totalNotional += sumBuyNotional; var totalBuySpotPrice = underlyingTradeFlows.Sum(z => z.Lots * underlying.ContractSize * (z.SpotPrice ?? 0) * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)); totalSpotPrice += totalBuySpotPrice; } var sumSellLots = underlyingTradeFlows.Sum(z => z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)); if (sumSellLots > 0) { var sumSellNotional = sumSellLots * underlying.ContractSize; totalNotional -= sumSellNotional; var totalSellSpotPrice = underlyingTradeFlows.Sum(z => z.Lots * underlying.ContractSize * (z.SpotPrice ?? 0) * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)); totalSpotPrice -= totalSellSpotPrice; } var totalFee = underlyingTradeFlows.Sum(z => z.NeedCostFee ? (z.SingleFee != null ? (z.SingleFee.Value * z.Lots) : (z.UnAnnualRate * z.Lots * z.SpotPrice * underlying.ContractSize ?? 0)) : 0); //当天该标的完全平仓 if (totalNotional == 0) { y.td.UnWindDate = valuedateBLL.ValueDate; y.td.FinalPrice = spotPrice + totalSpotPrice * (longShort == "多头" ? -1 : 1) / notional; UnwindSwapTradeCashHandle(y.td, "平仓", null, totalFee); } //当天还存在持仓,需要先平仓,再开仓 else { #region 平仓 y.td.UnWindDate = valuedateBLL.ValueDate; //假设先用收盘价将当前的剩余份额平仓掉,再用收盘价重新开仓剩余份额 var fillNotional = -totalNotional; EodPrice eodPrice = null; new EodPriceProvider(valuedateBLL.ValueDate, false).TryGetEodPrice(y.td.UnderlyingCode, out eodPrice); var closePrice = eodPrice?.ClosePrice ?? underlying.Price ?? 0; totalSpotPrice += fillNotional * closePrice; y.td.FinalPrice = spotPrice + totalSpotPrice * (longShort == "多头" ? -1 : 1) / notional; UnwindSwapTradeCashHandle(y.td, "平仓", null, 0); #endregion #region 重新开仓 var flow = new trade_swap_flow() { UnderlyingCode = y.td.UnderlyingCode, TradeDate = valuedateBLL.ValueDate, StartDate = valuedateBLL.ValueDate, ExerciseDate = y.td.ExerciseDate, QuoteCurrency = y.td.QuoteCurrency, SettlementDate = y.td.SettlementDate, SingleFee = y.swap.IsPayFloatingProfit ? y.swap.GetSingleFee : y.swap.PaySingleFee, UnAnnualRate = y.swap.IsPayFloatingProfit ? y.swap.GetUnAnnualRate : y.swap.PayUnAnnualRate, TradeNumber = x }; flow.Lots = Math.Abs(totalNotional / underlying.ContractSize); flow.BuySell = totalNotional > 0 ? "买入" : "卖出"; flow.SpotPrice = closePrice; var trade = MapSwapTradeHandle(flow, false); InnerSaveSwapTrade(trade, totalFee); if (newParentTradeId == 0 && trade.ParentTradeId > 0) { newParentTradeId = trade.ParentTradeId; } hasNoPosition = false; #endregion } }); //对当天新的标的流水处理 var underlyingCodes = preTradeDateTrades.Select(y => y.td.UnderlyingCode).Distinct().ToList(); var tradeFlowsUnderlyingGroupNew = GetTradeFlowsUnderlyingGroup(tradeFlows.Where(y => !underlyingCodes.Contains(y.UnderlyingCode))); tradeFlowsUnderlyingGroupNew.ForEach(y => { var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(y.UnderlyingCode); var underlyingTradeFlows = tradeFlows.Where(z => z.UnderlyingCode == y.UnderlyingCode).ToList(); double buyTotalFee = 0d; double sellTotalFee = 0d; double totalFee = 0d; underlyingTradeFlows.ForEach(z => { if (z.NeedCostFee) { if (z.SingleFee == null && z.UnAnnualRate == null) { var varitey = DataCacheProvider.GetVariety(y.UnderlyingCode); var clientVarietyConfig = DbContext.client_variety_config.Where(o => o.ClientId == client.id && o.VarietyId == varitey.id && o.ValueDate <= y.flow.TradeDate).OrderByDescending(o => o.ValueDate).FirstOrDefault(); if (clientVarietyConfig == null) { throw new ServiceException($"该客户[{client.Name}]需要维护品种[{varitey.VarietyCode}]在[{y.flow.TradeDate}]相关的收费参数配置"); } buyTotalFee += clientVarietyConfig.SingleFee > 0 ? (clientVarietyConfig.SingleFee * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)) : (clientVarietyConfig.UnAnnualRate * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0); sellTotalFee += clientVarietyConfig.SingleFee > 0 ? (clientVarietyConfig.SingleFee * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)) : (clientVarietyConfig.UnAnnualRate * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0); totalFee += clientVarietyConfig.SingleFee > 0 ? (z.SingleFee.Value * z.Lots) : (z.UnAnnualRate * z.Lots * z.SpotPrice * underlying.ContractSize ?? 0); } else { buyTotalFee += z.SingleFee != null ? (z.SingleFee.Value * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)) : (z.UnAnnualRate * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0); sellTotalFee += z.SingleFee != null ? (z.SingleFee.Value * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)) : (z.UnAnnualRate * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0); totalFee += z.SingleFee != null ? (z.SingleFee.Value * z.Lots) : (z.UnAnnualRate * z.Lots * z.SpotPrice * underlying.ContractSize ?? 0); } } }); //当天新增的标的,买卖手数合成为0,即持仓数为0,新增一笔普通互换,然后当天平仓平掉 if (y.Lots == 0) { buyTotalFee = underlyingTradeFlows.Sum(z => z.NeedCostFee ? (z.SingleFee != null ? (z.SingleFee.Value * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)) : (z.UnAnnualRate * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0)) : 0); sellTotalFee = underlyingTradeFlows.Sum(z => z.NeedCostFee ? (z.SingleFee != null ? (z.SingleFee.Value * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)) : (z.UnAnnualRate * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0)) : 0); SetOpenUnwindSingleSwapTrade(y, buyTotalFee, sellTotalFee); } //当天新增的标的,存在持仓的,用均价作为开仓价 else { y.flow.Lots = Math.Abs(y.Lots); y.flow.BuySell = y.Lots > 0 ? "买入" : "卖出"; y.flow.SpotPrice = Math.Abs(y.SumSpotPrice / y.Lots); var trade = MapSwapTradeHandle(y.flow, false); totalFee = underlyingTradeFlows.Sum(z => z.NeedCostFee ? (z.SingleFee != null ? (z.SingleFee.Value * z.Lots) : (z.UnAnnualRate * z.Lots * z.SpotPrice * underlying.ContractSize ?? 0)) : 0); InnerSaveSwapTrade(trade, totalFee); if (newParentTradeId == 0 && trade.ParentTradeId > 0) { newParentTradeId = trade.ParentTradeId; } hasNoPosition = false; } }); var oldParentTradeId = preTradeDateTrades.FirstOrDefault().td.ParentTradeId; var oldParentTrade = DbContext.trade.Find(oldParentTradeId); AddTradeOperationHistoryAndSetParentTradeInfo(true, oldParentTrade, "合成多空组合流水平仓操作"); var newParentTrade = DbContext.trade.Find(newParentTradeId); if (newParentTrade != null) { AddTradeOperationHistoryAndSetParentTradeInfo(true, newParentTrade, "合成多空组合流水开仓操作"); } } //当天开仓的场景 //第一天开仓的交易,将流水费用合成变为对应子交易的交易费用; else { var tradeFlowsUnderlyingGroup = GetTradeFlowsUnderlyingGroup(tradeFlows); tradeFlowsUnderlyingGroup.ForEach(y => { var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(y.UnderlyingCode); var underlyingTradeFlows = tradeFlows.Where(z => z.UnderlyingCode == y.UnderlyingCode).ToList(); double buyTotalFee = 0d; double sellTotalFee = 0d; double totalFee = 0d; underlyingTradeFlows.ForEach(z => { if (z.NeedCostFee) { if (z.SingleFee == null && z.UnAnnualRate == null) { var varitey = DataCacheProvider.GetVariety(y.UnderlyingCode); var clientVarietyConfig = DbContext.client_variety_config.Where(o => o.ClientId == client.id && o.VarietyId == varitey.id && o.ValueDate <= y.flow.TradeDate).OrderByDescending(o => o.ValueDate).FirstOrDefault(); if (clientVarietyConfig == null) { throw new ServiceException($"该客户[{client.Name}]需要维护品种[{varitey.VarietyCode}]在[{y.flow.TradeDate}]相关的收费参数配置"); } buyTotalFee += clientVarietyConfig.SingleFee > 0 ? (clientVarietyConfig.SingleFee * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)) : (clientVarietyConfig.UnAnnualRate * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0); sellTotalFee += clientVarietyConfig.SingleFee > 0 ? (clientVarietyConfig.SingleFee * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)) : (clientVarietyConfig.UnAnnualRate * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0); totalFee += clientVarietyConfig.SingleFee > 0 ? (clientVarietyConfig.SingleFee * z.Lots) : (clientVarietyConfig.UnAnnualRate * z.Lots * z.SpotPrice * underlying.ContractSize ?? 0); } else { buyTotalFee += z.SingleFee != null ? (z.SingleFee.Value * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)) : (z.UnAnnualRate * z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0); sellTotalFee += z.SingleFee != null ? (z.SingleFee.Value * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)) : (z.UnAnnualRate * z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0) * z.SpotPrice * underlying.ContractSize ?? 0); totalFee += z.SingleFee != null ? (z.SingleFee.Value * z.Lots) : (z.UnAnnualRate * z.Lots * z.SpotPrice * underlying.ContractSize ?? 0); } } }); //持仓数为0,新增一笔普通互换,然后当天平仓平掉 if (y.Lots == 0) { SetOpenUnwindSingleSwapTrade(y, buyTotalFee, sellTotalFee); } //存在持仓的,用均价作为开仓价 else { y.flow.Lots = Math.Abs(y.Lots); y.flow.BuySell = y.Lots > 0 ? "买入" : "卖出"; y.flow.SpotPrice = Math.Abs(y.SumSpotPrice / y.Lots); var trade = MapSwapTradeHandle(y.flow, false); InnerSaveSwapTrade(trade, totalFee); } }); AddTradeOperationHistoryAndSetParentTradeInfo(true, originalTrade, "合成多空组合流水开仓"); } tradeFlows.ForEach(y => y.Status = "已完成"); DbContext.SaveChanges(); if (hasNoPosition) { var tradeDateTradeIds = (from td in DbContext.trade.Where(z => z.TradeDate == valuedateBLL.ValueDate && z.ValidState != "InValid") join swap in DbContext.trade_swap.Where(z => z.OriginalTradeId == originalTradeId && z.SwapType == "多空组合") on td.id equals swap.TradeId select td.id).ToList(); if (tradeDateTradeIds.Any()) { tradeDateTradeIds.ForEach(z => { new TradeInvalidService(this).InvalidTrade(z, false); }); } } #endregion } }); } trans.Commit(); } } private List GetTradeFlowsUnderlyingGroup(IEnumerable tradeFlows) { var tradeFlowsUnderlyingGroup = tradeFlows.GroupBy(y => y.UnderlyingCode) .Select(y => new trade_swap_flow_group() { UnderlyingCode = y.Key, BuyLots = y.Sum(z => z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)), SellLots = y.Sum(z => z.Lots * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)), Lots = y.Sum(z => z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : -1)), SumBuySpotPrice = y.Sum(z => z.Lots * (z.SpotPrice ?? 0) * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : 0)), SumSellSpotPrice = y.Sum(z => z.Lots * (z.SpotPrice ?? 0) * (z.BuySell == "卖出" || z.BuySell == "S" ? 1 : 0)), SumSpotPrice = y.Sum(z => z.Lots * (z.SpotPrice ?? 0) * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : -1)), flow = new trade_swap_flow() { UnderlyingCode = y.Key, BuySell = y.Sum(z => z.Lots * (z.BuySell == "买入" || z.BuySell == "B" ? 1 : -1)) >= 0 ? "买入" : "卖出", ClearingAgency = y.First().ClearingAgency, TradeNumber = y.First().TradeNumber, TradeDate = y.First().TradeDate, StartDate = y.First().StartDate, ExerciseDate = y.First().ExerciseDate, QuoteCurrency = y.First().QuoteCurrency, SettlementDate = y.First().SettlementDate, NeedCostFee = y.First().NeedCostFee, SingleFee = y.First().SingleFee, UnAnnualRate = y.First().UnAnnualRate } } ).ToList(); return tradeFlowsUnderlyingGroup; } private void SetOpenUnwindSingleSwapTrade(trade_swap_flow_group flowGroup, double openCostFee, double closeCostFee) { flowGroup.flow.Lots = flowGroup.BuyLots; flowGroup.flow.SpotPrice = flowGroup.SumBuySpotPrice / flowGroup.BuyLots; var trade = MapSwapTradeHandle(flowGroup.flow, true); InnerSaveSwapTrade(trade, openCostFee); trade.UnWindDate = valuedateBLL.ValueDate; trade.FinalPrice = flowGroup.SumSellSpotPrice / flowGroup.SellLots; UnwindSwapTradeCashHandle(trade, "平仓", null, closeCostFee); AddTradeOperationHistoryAndSetParentTradeInfo(true, trade, "合成多空组合流水时生成的单笔交易开平仓记录"); } private trade MapSwapTradeHandle(trade_swap_flow swapFlow, bool isSingleTrade) { var originalTrades = DbContext.trade.Where(x => x.TradeNumber == swapFlow.TradeNumber); new TradeExtendService(UserInfo).SetTradeExtend(originalTrades, true); var originalTrade = originalTrades.FirstOrDefault(); var lastParentTrade = originalTrade; if (originalTrade == null) { throw new ServiceException($"该交易编号[{swapFlow.TradeNumber}]在系统中不存在"); } else if (originalTrade.TradeType != "收益互换" || originalTrade.trade_swap.SwapType != "多空组合") { throw new ServiceException($"该交易编号[{swapFlow.TradeNumber}]的交易类型非多空组合的收益互换"); } var defaultExerciseDate = originalTrade.ExerciseDate; var td = new trade { TradeDate = swapFlow.TradeDate, StartDate = swapFlow.StartDate, ExerciseDate = swapFlow.ExerciseDate, TradeType = "收益互换", StructureType = "收益互换", ClientId = originalTrade.ClientId, ClientName = originalTrade.ClientName, QuoteCurrency = swapFlow.QuoteCurrency, SettlementCurrency = originalTrade.SettlementCurrency, UnderlyingCode = swapFlow.UnderlyingCode, SpotPrice = swapFlow.SpotPrice, Lots = swapFlow.Lots, IsNight = swapFlow.IsNight, OpponentRole = "甲方", MarginTemplateName = null, MarginType = MarginTypeEnum.DEFAULT, IsGroup = isSingleTrade ? 0 : 2 }; if (!isSingleTrade) { if (originalTrade.TradeDate == swapFlow.TradeDate) { td.ParentTradeId = originalTrade.id; } else if (originalTrade.TradeDate < swapFlow.TradeDate) { var todayParentTrade = (from trade in DbContext.trade.Where(x => x.ValidState != "InValid" && x.TradeDate == swapFlow.TradeDate && x.ClientId == originalTrade.ClientId) join swap in DbContext.trade_swap.Where(x => x.OriginalTradeId == originalTrade.id) on trade.id equals swap.TradeId select trade).FirstOrDefault(); if (todayParentTrade == null) { var lastParentTrades = (from trade in DbContext.trade.Where(x => x.ValidState != "InValid" && x.TradeDate < swapFlow.TradeDate && x.ClientId == originalTrade.ClientId && x.IsGroup == 1) join swap in DbContext.trade_swap.Where(x => x.OriginalTradeId == originalTrade.id) on trade.id equals swap.TradeId select trade).OrderByDescending(x => x.TradeDate); if (lastParentTrades.Any()) { new TradeExtendService(UserInfo).SetTradeExtend(lastParentTrades, true); lastParentTrade = lastParentTrades.First(); defaultExerciseDate = lastParentTrade.ExerciseDate; } var newParentTrade = new trade { TradeDate = swapFlow.TradeDate, StartDate = swapFlow.StartDate, ExerciseDate = defaultExerciseDate, TradeType = "收益互换", StructureType = "收益互换", ClientId = lastParentTrade.ClientId, ClientName = lastParentTrade.ClientName, QuoteCurrency = lastParentTrade.QuoteCurrency, SettlementCurrency = lastParentTrade.SettlementCurrency, UnderlyingCode = lastParentTrade.UnderlyingCode, UnderlyingId = lastParentTrade.UnderlyingId, UnderlyingAssetClass = lastParentTrade.UnderlyingAssetClass, MaturityDate = lastParentTrade.MaturityDate, UnderlyingInstrumentType = lastParentTrade.UnderlyingInstrumentType, UnderlyingAssetName = lastParentTrade.UnderlyingName, SpotPrice = lastParentTrade.SpotPrice, IsNight = lastParentTrade.IsNight, OpponentRole = lastParentTrade.OpponentRole, MarginTemplateName = lastParentTrade.MarginTemplateName, MarginType = lastParentTrade.MarginType, IsUsePremiumRate = lastParentTrade.IsUsePremiumRate, PrincipalRate = lastParentTrade.PrincipalRate, ParticipationRate = lastParentTrade.ParticipationRate, TraderId = lastParentTrade.TraderId, TraderName = lastParentTrade.TraderName, AssetId = lastParentTrade.AssetId, AssetBookName = lastParentTrade.AssetBookName, IsGroup = lastParentTrade.IsGroup }; newParentTrade.MetaDic = lastParentTrade.MetaDic; newParentTrade.trade_swap = new trade_swap() { SwapType = lastParentTrade.trade_swap.SwapType, OriginalTradeId = originalTrade.id, IsGetFloatingProfit = lastParentTrade.trade_swap.IsGetFloatingProfit, GetSingleFee = lastParentTrade.trade_swap.GetSingleFee, GetUnAnnualRate = lastParentTrade.trade_swap.GetUnAnnualRate, GetSwapTimeAndRate = lastParentTrade.trade_swap.GetSwapTimeAndRate, GetMarginRate = lastParentTrade.trade_swap.GetMarginRate, GetUnderlyingId = lastParentTrade.trade_swap.GetUnderlyingId, GetUnderlyingCode = lastParentTrade.trade_swap.GetUnderlyingCode, GetSpotPrice = lastParentTrade.trade_swap.GetSpotPrice, IsPayFloatingProfit = lastParentTrade.trade_swap.IsPayFloatingProfit, PaySingleFee = lastParentTrade.trade_swap.PaySingleFee, PayUnAnnualRate = lastParentTrade.trade_swap.PayUnAnnualRate, PayMarginRate = lastParentTrade.trade_swap.PayMarginRate, PayUnderlyingId = lastParentTrade.trade_swap.PayUnderlyingId, PayUnderlyingCode = lastParentTrade.trade_swap.PayUnderlyingCode, PaySpotPrice = lastParentTrade.trade_swap.PaySpotPrice, PaySwapTimeAndRate = lastParentTrade.trade_swap.PaySwapTimeAndRate, AnnualDays = lastParentTrade.trade_swap.AnnualDays, AnnualVarIncome = lastParentTrade.trade_swap.AnnualVarIncome, RateCalcMode = lastParentTrade.trade_swap.RateCalcMode, IsTradePriceWhenOpen = lastParentTrade.trade_swap.IsTradePriceWhenOpen, }; InnerSaveSwapTrade(newParentTrade, 0); td.ParentTradeId = newParentTrade.id; } else { td.ParentTradeId = todayParentTrade.id; defaultExerciseDate = todayParentTrade.ExerciseDate; } } else { throw new ServiceException($"交易编号[{swapFlow.TradeNumber}]对应的交易流水的交易日期[{swapFlow.TradeDate?.ToString("yyyy-MM-dd")}]不该在多空组合交易的交易日[{originalTrade.TradeDate?.ToString("yyyy-MM-dd")}]之前"); } } td.MetaDic = lastParentTrade.MetaDic; //标的代码(必需) var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); if (underlying == null) { throw new ServiceException($"该标的代码[{td.UnderlyingCode}]在系统中不存在"); } else { td.UnderlyingId = underlying.id; td.UnderlyingAssetClass = underlying.UnderlyingType; td.MaturityDate = underlying.MaturityDate; if (td.ExerciseDate == null) { td.ExerciseDate = underlying.MaturityDate; swapFlow.ExerciseDate = underlying.MaturityDate; } td.UnderlyingInstrumentType = underlying.UnderlyingInstrumentType; td.UnderlyingAssetName = underlying.UnderlyingName; } if (td.ExerciseDate == null) { td.ExerciseDate = defaultExerciseDate; } var variety = DataCacheProvider.GetVarietyDataSource().GetData(underlying.UnderlyingTypeId); //交易份额 td.Notional = (td.Lots ?? 0) * underlying.ContractSize; td.TradeAmount = td.Notional / variety.CountRatio; td.OriginalNotional = td.Notional; td.StockEqvNotional = (td.SpotPrice ?? 0) * td.Notional; td.StockEqvNotionalReal = td.StockEqvNotional; td.OriginalStockEqvNotional = td.StockEqvNotional; td.PrincipalRate = 0; td.ParticipationRate = 1; td.AssetId = originalTrade.AssetId; td.AssetBookName = originalTrade.AssetBookName; td.TraderId = originalTrade.TraderId; td.TraderName = originalTrade.TraderName; //td.InitialMargin = td.StockEqvNotional * (lastParentTrade.trade_swap.GetMarginRate - lastParentTrade.trade_swap.PayMarginRate); td.trade_swap = new trade_swap() { TradeId = td.id, OriginalTradeId = originalTrade.id }; td.trade_swap.SwapType = "普通"; td.trade_swap.AnnualDays = lastParentTrade.trade_swap.AnnualDays; td.trade_swap.AnnualVarIncome = lastParentTrade.trade_swap.AnnualVarIncome; td.trade_swap.RateCalcMode = lastParentTrade.trade_swap.RateCalcMode; td.trade_swap.IsTradePriceWhenOpen = true; td.trade_swap.IsPayFloatingProfit = lastParentTrade.trade_swap.IsPayFloatingProfit; td.trade_swap.IsGetFloatingProfit = lastParentTrade.trade_swap.IsGetFloatingProfit; td.trade_swap.GetSwapTimeAndRate = lastParentTrade.trade_swap.GetSwapTimeAndRate; td.trade_swap.PaySwapTimeAndRate = lastParentTrade.trade_swap.PaySwapTimeAndRate; var isAnnualSet = swapFlow.SingleFee != null || swapFlow.UnAnnualRate != null; if (isAnnualSet) { if (td.trade_swap.IsPayFloatingProfit) { td.trade_swap.GetSingleFee = swapFlow.SingleFee ?? 0; td.trade_swap.GetUnAnnualRate = swapFlow.UnAnnualRate ?? 0; } else { td.trade_swap.PaySingleFee = swapFlow.SingleFee ?? 0; td.trade_swap.PayUnAnnualRate = swapFlow.UnAnnualRate ?? 0; } } else { var varitey = DataCacheProvider.GetVariety(td.UnderlyingCode); var clientVarietyConfig = DbContext.client_variety_config.Where(x => x.ClientId == td.ClientId && x.VarietyId == varitey.id && x.ValueDate <= td.TradeDate).OrderByDescending(x => x.ValueDate).FirstOrDefault(); if (clientVarietyConfig == null) { throw new ServiceException($"该客户[{td.ClientName}]需要维护品种[{varitey.VarietyCode}]在[{td.TradeDate}]相关的收费参数配置"); } if (td.trade_swap.IsPayFloatingProfit) { td.trade_swap.GetSingleFee = clientVarietyConfig.SingleFee; td.trade_swap.GetUnAnnualRate = clientVarietyConfig.UnAnnualRate; } else { td.trade_swap.PaySingleFee = clientVarietyConfig.SingleFee; td.trade_swap.PayUnAnnualRate = clientVarietyConfig.UnAnnualRate; } } if (td.trade_swap.IsPayFloatingProfit) { td.trade_swap.GetTradePrice = (td.trade_swap.GetSingleFee ?? 0) * (td.Lots ?? 0) + (td.trade_swap.GetUnAnnualRate ?? 0) * td.StockEqvNotional; td.trade_swap.GetMarginRate = lastParentTrade.trade_swap.GetMarginRate; td.trade_swap.PaySpotPrice = td.SpotPrice; td.trade_swap.PayUnderlyingId = td.UnderlyingId; td.trade_swap.PayUnderlyingCode = td.UnderlyingCode; td.trade_swap.PayNotional = td.Notional; td.trade_swap.PayTradeAmount = td.TradeAmount; } else { td.trade_swap.PayTradePrice = (td.trade_swap.PaySingleFee ?? 0) * (td.Lots ?? 0) + (td.trade_swap.PayUnAnnualRate ?? 0) * td.StockEqvNotional; td.trade_swap.PayMarginRate = lastParentTrade.trade_swap.PayMarginRate; td.trade_swap.GetSpotPrice = td.SpotPrice; td.trade_swap.GetUnderlyingId = td.UnderlyingId; td.trade_swap.GetUnderlyingCode = td.UnderlyingCode; td.trade_swap.GetNotional = td.Notional; td.trade_swap.GetTradeAmount = td.TradeAmount; } //交易方向 var longshort = swapFlow.BuySell; switch (longshort) { case "买入": case "B": if (td.trade_swap.IsPayFloatingProfit) { td.trade_swap.PayLongShort = "多头"; } else { td.trade_swap.GetLongShort = "多头"; } break; case "卖出": case "S": if (td.trade_swap.IsPayFloatingProfit) { td.trade_swap.PayLongShort = "空头"; } else { td.trade_swap.GetLongShort = "空头"; } break; default: throw new ServiceException("买卖方向 填写错误:" + longshort); } return td; } private void InnerSaveSwapTrade(trade td, double tradePriceQuote) { if (!string.IsNullOrWhiteSpace(td.TradeNumber)) { if (DbContext.trade.Any(x => x.TradeNumber == td.TradeNumber)) { throw new ServiceException($"存在重复的交易编号[{td.TradeNumber}]"); } } td.TradeStatus = ConsTrade.确认成交; var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.TradeDate.Value, seekPreday: true); if (td.trade_swap.IsPayFloatingProfit) { td.trade_swap.GetTradePrice = tradePriceQuote; td.TradePrice = tradePriceQuote * currencyRate; td.BuySell = "卖出"; } else { td.trade_swap.PayTradePrice = tradePriceQuote; td.TradePrice = tradePriceQuote * currencyRate; td.BuySell = "买入"; } td.OriginalNotional = td.Notional; td.OriginalStockEqvNotional = td.StockEqvNotional; td.StockEqvNotionalReal = td.StockEqvNotionalReal; td.MarginTemplateName = null; td.MarginType = MarginTypeEnum.DEFAULT; td.IsTradePricePayType = true; td.TradeSource = TradeSourceEnum.导入交易.ToString(); td.OptId = UserId; td.OptName = UserName; td.OptDate = DateTime.Now; td.CreatorId = UserId; td.CreatorName = UserName; td.CreateDate = DateTime.Now; DbContext.trade.Add(td); DbContext.SaveChanges(); td.trade_swap.TradeId = td.id; td.trade_swap.OptId = UserId; td.trade_swap.OptName = UserName; td.trade_swap.OptDate = DateTime.Now; DbContext.trade_swap.Add(td.trade_swap); SaveTradeMeta(td); var tc = new trade_cash { ValidState = "Valid" }; DbContext.trade_cash.Add(tc); tc.OptId = UserId; tc.OptName = UserName; tc.OptDate = DateTime.Now; tc.Action = ClientCashInCashOut.系统操作_期权费; tc.Amount = (td.TradePrice ?? 0) * (td.BuySell == "买入" ? -1 : 1); tc.QuoteAmount = tradePriceQuote * (td.BuySell == "买入" ? -1 : 1); tc.CurrencyRate = currencyRate; tc.ExceciseType = "现金"; tc.TradeId = td.id; tc.ValueDate = td.TradeDate.Value; tc.Notional = td.Notional; tc.TradeAmount = td.TradeAmount; tc.Status = TradeCashStatusEnum.已执行; tc.TradeType = td.BuySell; DbContext.SaveChanges(); new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate); var tcdGet = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = tc.Amount, QuoteAmount = tc.QuoteAmount, TradeCashType = TradeCashTypeEnum.开仓手续费.ToString(), ValueDate = tc.ValueDate, IsForGet = true, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now }; DbContext.trade_cash_detail.Add(tcdGet); if (td.ParentTradeId > 0) { var parentTrade = DbContext.trade.Find(td.ParentTradeId); if (parentTrade != null) { parentTrade.OriginalStockEqvNotional += td.StockEqvNotional; parentTrade.StockEqvNotional += td.StockEqvNotional; parentTrade.StockEqvNotionalReal += td.StockEqvNotional; var tradePrice = (parentTrade.TradePrice ?? 0) * (parentTrade.BuySell == "买入" ? -1 : 1) + (td.TradePrice ?? 0) * (td.BuySell == "买入" ? -1 : 1); parentTrade.TradePrice = Math.Abs(tradePrice); parentTrade.BuySell = tradePrice >= 0 ? "卖出" : "买入"; var swapTrade = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == parentTrade.id); if (swapTrade != null) { if (swapTrade.IsPayFloatingProfit) { swapTrade.GetTradePrice = tradePrice; } else { swapTrade.PayTradePrice = -tradePrice; } } td.trade_swap.AnnualDays = swapTrade.AnnualDays; trade_swap_detail detail = new trade_swap_detail() { IsForGet = td.trade_swap.IsGetFloatingProfit, TradeId = td.ParentTradeId, ChildTradeId = td.id, LongShort = td.trade_swap.IsGetFloatingProfit ? td.trade_swap.GetLongShort : td.trade_swap.PayLongShort, UnderlyingCode = td.UnderlyingCode, SpotPrice = td.SpotPrice, OriginalNotional = td.OriginalNotional, Notional = td.Notional, TradePrice = td.trade_swap.IsGetFloatingProfit ? (td.trade_swap.PayTradePrice ?? 0) : (td.trade_swap.GetTradePrice ?? 0) }; DbContext.trade_swap_detail.Add(detail); if (string.IsNullOrWhiteSpace(td.TradeNumber)) { var childCount = DbContext.trade.Where(x => x.ParentTradeId == parentTrade.id && x.ValidState != "InValid").Count(); td.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(td, parentTrade, childCount, DbContext); } } } else { if (string.IsNullOrWhiteSpace(td.TradeNumber)) { if (GuolianContractNoGenerator.IsGuolianSwapTrade(td)) { GuolianContractNoGenerator.TryGenerateTradeNumberAfterSave(DbContext, td); } else { td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext); } } } DbContext.SaveChanges(); } private void SaveTradeMeta(trade t) { if (t != null && t.MetaDic != null && t.MetaDic.Count() > 0) { foreach (var kv in t.MetaDic) { if (!string.IsNullOrEmpty(kv.Value)) { new TradeServiceBase(UserInfo).AddTradeMeta(false, t.id, kv.Key, kv.Value); } } } } private void UnwindSwapTradeCashHandle(trade td, string action, double? annualFee, double? costFee) { var client = DataCacheProvider.GetClientDataSource().GetData(td.ClientId); var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); //增加现金交割交易记录 var tc = new trade_cash(); DbContext.trade_cash.Add(tc); tc.OptId = UserId; tc.OptName = UserName; tc.OptDate = OptDate; tc.ExceciseType = "现金"; tc.TradeType = td.BuySell; tc.CallPut = td.CallPut; tc.Notional = td.Notional; tc.TradeAmount = td.TradeAmount; tc.IsLastAction = true; tc.TradeId = td.id; tc.FinalPrice = td.FinalPrice; tc.UnwindType = "全部平仓"; tc.UnwindNotional = td.Notional; tc.UnwindTradeAmount = td.TradeAmount; tc.UnwindPercentRate = 1; tc.NotionalPercentRate = tc.UnwindPercentRate; var trade_cash_swap = new trade_cash_swap(); if (td.trade_swap.IsPayFloatingProfit) { var initialAmountPayQuote = PayoffSwapCalcService.GetInitialAmountSwapPay(td, td.trade_swap, td.SpotPrice ?? 0 , td.FinalPrice ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0), td.UnWindDate.Value, null); var preSwapDate = td.trade_swap.IncludeFirstDay ? td.StartDate.Value.AddDays(-1) : td.StartDate.Value; var extraAmountGetQuote = annualFee ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.GetSwapTimeAndRate, preSwapDate, td.UnWindDate.Value, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0)); var extraAmountPayQuote = annualFee ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.PaySwapTimeAndRate, preSwapDate, td.UnWindDate.Value, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0)); var costFeeGetQuote = costFee ?? 0; var costTradePriceGetQuote = 0.0; if (!td.trade_swap.IsTradePriceWhenOpen) { costTradePriceGetQuote = PayoffSwapCalcService.GetCostFee(td, td, tc, true, true); } var quoteAmount = extraAmountGetQuote + costFeeGetQuote + costTradePriceGetQuote - initialAmountPayQuote - extraAmountPayQuote; var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: quoteAmount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell); var initialAmountPay = initialAmountPayQuote * currencyRate; var extraAmountGet = extraAmountGetQuote * currencyRate; var extraAmountPay = extraAmountPayQuote * currencyRate; var costFeeGet = costFeeGetQuote * currencyRate; var costTradePriceGet = costTradePriceGetQuote * currencyRate; td.TradeStatus = tc.ValueDate == td.ExerciseDate ? "已到期" : "已平仓"; td.StockEqvNotional = 0; td.Notional = 0; td.TradeAmount = 0; td.UnWindNotional = tc.UnwindNotional; tc.Amount = extraAmountGet + costFeeGet + costTradePriceGet - initialAmountPay - extraAmountPay; tc.QuoteAmount = quoteAmount; tc.CurrencyRate = currencyRate; tc.Action = action == "平仓" ? ClientCashInCashOut.系统操作_平仓费 : ClientCashInCashOut.系统操作_互换; tc.IsLastAction = true; tc.Status = TradeCashStatusEnum.已执行; tc.ValueDate = td.UnWindDate.Value; tc.ValidState = "Valid"; tc.ExerciseWay = td.UnWindDate == td.ExerciseDate ? TradeCashExerciseWayEnum.到期行权 : TradeCashExerciseWayEnum.提前终止行权; DbContext.SaveChanges(); //增加出入金记录 new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate); var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId); trade_cash_swap.StartDate = td.StartDate.Value; trade_cash_swap.PayStartPrice = trade_swap.PayFinalPrice ?? trade_swap.PaySpotPrice; trade_cash_swap.PayFinalPrice = tc.FinalPrice; trade_cash_swap.PayInitialAmount = initialAmountPay; trade_cash_swap.PayExtraAmount = extraAmountPay; trade_cash_swap.PayAmount = initialAmountPay + extraAmountPay; var customizedResultsPay = QdpHelper.ParseAutocallCustomizedInfo(td.trade_swap.PaySwapTimeAndRate); var paySwapRates = customizedResultsPay.Item2; trade_cash_swap.PaySwapRate = paySwapRates.FirstOrDefault(); trade_cash_swap.GetExtraAmount = extraAmountGet; trade_cash_swap.GetCostFee = costFeeGet + costTradePriceGet; trade_cash_swap.GetAmount = extraAmountGet + costFeeGet + costTradePriceGet; var customizedResultsGet = QdpHelper.ParseAutocallCustomizedInfo(td.trade_swap.GetSwapTimeAndRate); var getSwapRates = customizedResultsGet.Item2; trade_cash_swap.GetSwapRate = getSwapRates.FirstOrDefault(); trade_cash_swap.TradeId = tc.TradeId; trade_cash_swap.TradeCashId = tc.id; trade_cash_swap.OptId = tc.OptId; trade_cash_swap.OptName = tc.OptName; trade_cash_swap.OptDate = DateTime.Now; DbContext.trade_cash_swap.Add(trade_cash_swap); var tcdGet = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = extraAmountGet - extraAmountPay, QuoteAmount = extraAmountGetQuote - extraAmountPayQuote, ValueDate = tc.ValueDate, IsForGet = true, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now, TradeCashType = TradeCashTypeEnum.利息.ToString() }; DbContext.trade_cash_detail.Add(tcdGet); var tcdCostFeeGet = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = costFeeGet, QuoteAmount = costFeeGetQuote, ValueDate = tc.ValueDate, IsForGet = true, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now, TradeCashType = TradeCashTypeEnum.了结手续费.ToString() }; DbContext.trade_cash_detail.Add(tcdCostFeeGet); var tcdCostTradePriceGet = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = costTradePriceGet, QuoteAmount = costTradePriceGetQuote, ValueDate = tc.ValueDate, IsForGet = true, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now, TradeCashType = TradeCashTypeEnum.开仓手续费.ToString() }; DbContext.trade_cash_detail.Add(tcdCostTradePriceGet); var tcdPay = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = -initialAmountPay, QuoteAmount = -initialAmountPayQuote, ValueDate = tc.ValueDate, IsForGet = false, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now, TradeCashType = TradeCashTypeEnum.浮动收益.ToString() }; DbContext.trade_cash_detail.Add(tcdPay); } else { var initialAmountGetQuote = PayoffSwapCalcService.GetInitialAmountSwapGet(td, td.trade_swap, td.SpotPrice ?? 0 , td.FinalPrice ?? 0, td.OriginalStockEqvNotional ?? 0, td.UnWindDate.Value, null); var preSwapDate = td.trade_swap.IncludeFirstDay ? td.StartDate.Value.AddDays(-1) : td.StartDate.Value; var extraAmountPayQuote = annualFee ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.PaySwapTimeAndRate, preSwapDate, td.UnWindDate.Value, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0)); var extraAmountGetQuote = annualFee ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.GetSwapTimeAndRate, preSwapDate, td.UnWindDate.Value, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0)); var costFeePayQuote = costFee ?? 0; var costTradePricePayQuote = 0.0; if (!td.trade_swap.IsTradePriceWhenOpen) { costTradePricePayQuote = PayoffSwapCalcService.GetCostFee(td, td, tc, false, true); } var quoteAmount = initialAmountGetQuote + extraAmountGetQuote - extraAmountPayQuote - costFeePayQuote - costTradePricePayQuote; var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: quoteAmount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell); var initialAmountGet = initialAmountGetQuote * currencyRate; var extraAmountPay = extraAmountPayQuote * currencyRate; var extraAmountGet = extraAmountGetQuote * currencyRate; var costFeePay = costFeePayQuote * currencyRate; var costTradePricePay = costTradePricePayQuote * currencyRate; tc.Amount = initialAmountGet + extraAmountGet - extraAmountPay - costFeePay - costTradePricePay; tc.QuoteAmount = quoteAmount; tc.CurrencyRate = currencyRate; tc.Action = action == "平仓" ? ClientCashInCashOut.系统操作_平仓费 : ClientCashInCashOut.系统操作_互换; tc.IsLastAction = true; tc.Status = TradeCashStatusEnum.已执行; tc.ValueDate = td.UnWindDate.Value; tc.ValidState = "Valid"; tc.ExerciseWay = td.UnWindDate == td.ExerciseDate ? TradeCashExerciseWayEnum.到期行权 : TradeCashExerciseWayEnum.提前终止行权; DbContext.SaveChanges(); td.TradeStatus = tc.ValueDate == td.ExerciseDate ? "已到期" : "已平仓"; td.StockEqvNotional = 0; td.Notional = 0; td.TradeAmount = 0; td.UnWindNotional = tc.UnwindNotional; //增加出入金记录 new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate); var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId); trade_cash_swap.StartDate = td.StartDate.Value; trade_cash_swap.GetStartPrice = trade_swap.GetFinalPrice ?? trade_swap.GetSpotPrice; trade_cash_swap.GetFinalPrice = tc.FinalPrice; trade_cash_swap.GetInitialAmount = initialAmountGet; trade_cash_swap.GetExtraAmount = extraAmountGet; trade_cash_swap.GetAmount = initialAmountGet + extraAmountGet; var customizedResultsGet = QdpHelper.ParseAutocallCustomizedInfo(td.trade_swap.GetSwapTimeAndRate); var getSwapRates = customizedResultsGet.Item2; trade_cash_swap.GetSwapRate = getSwapRates.FirstOrDefault(); trade_cash_swap.PayExtraAmount = extraAmountPay; trade_cash_swap.PayCostFee = costFeePay + costTradePricePay; trade_cash_swap.PayAmount = extraAmountPay + costFeePay + costTradePricePay; var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(td.trade_swap.PaySwapTimeAndRate); var paySwapRates = customizedResults.Item2; trade_cash_swap.PaySwapRate = paySwapRates.FirstOrDefault(); trade_cash_swap.TradeId = tc.TradeId; trade_cash_swap.TradeCashId = tc.id; trade_cash_swap.OptId = tc.OptId; trade_cash_swap.OptName = tc.OptName; trade_cash_swap.OptDate = DateTime.Now; DbContext.trade_cash_swap.Add(trade_cash_swap); var tcdGet = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = extraAmountGet - extraAmountPay, QuoteAmount = extraAmountGetQuote - extraAmountPayQuote, ValueDate = tc.ValueDate, IsForGet = true, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now, TradeCashType = TradeCashTypeEnum.利息.ToString() }; DbContext.trade_cash_detail.Add(tcdGet); var tcdCostFeeGet = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = -costFeePay, QuoteAmount = -costFeePayQuote, ValueDate = tc.ValueDate, IsForGet = true, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now, TradeCashType = TradeCashTypeEnum.了结手续费.ToString() }; DbContext.trade_cash_detail.Add(tcdCostFeeGet); var tcdCostTradePriceGet = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = -costTradePricePay, QuoteAmount = -costTradePricePayQuote, ValueDate = tc.ValueDate, IsForGet = true, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now, TradeCashType = TradeCashTypeEnum.开仓手续费.ToString() }; DbContext.trade_cash_detail.Add(tcdCostTradePriceGet); var tcdPay = new trade_cash_detail { TradeId = tc.TradeId, TradeCashId = tc.id, Action = tc.Action, Amount = initialAmountGet, QuoteAmount = initialAmountGetQuote, ValueDate = tc.ValueDate, IsForGet = false, OptId = tc.OptId, OptName = tc.OptName, OptDate = DateTime.Now, TradeCashType = TradeCashTypeEnum.浮动收益.ToString() }; DbContext.trade_cash_detail.Add(tcdPay); } if (td.ParentTradeId > 0) { var parentTrade = DbContext.trade.Find(td.ParentTradeId); if (parentTrade != null) { parentTrade.UnWindDate = tc.ValueDate; parentTrade.StockEqvNotional = 0; parentTrade.TradeStatus = "已平仓"; var tradeSwapDetail = DbContext.trade_swap_detail.FirstOrDefault(x => x.TradeId == parentTrade.id && x.ChildTradeId == td.id); if (tradeSwapDetail != null) { tradeSwapDetail.Notional = td.Notional; } var tradeCash = DbContext.trade_cash.FirstOrDefault(x => x.TradeId == td.ParentTradeId && x.Action == ClientCashInCashOut.系统操作_平仓费 && x.ValidState != "InValid"); if (tradeCash == null) { tradeCash = new trade_cash() { TradeId = td.ParentTradeId, Notional = parentTrade.OriginalNotional ?? 0, ValueDate = tc.ValueDate, Action = tc.Action, Amount = 0, ExerciseWay = tc.ExerciseWay, IsLastAction = true, UnwindNotional = parentTrade.OriginalNotional ?? 0, UnwindPercentRate = 1, OptId = UserId, OptName = UserName, OptDate = DateTime.Now }; DbContext.trade_cash.Add(tradeCash); } DbContext.SaveChanges(); var tradeCashSwap = DbContext.trade_cash_swap.FirstOrDefault(x => x.TradeCashId == tradeCash.id && x.TradeId == parentTrade.id); if (tradeCashSwap == null) { tradeCashSwap = new trade_cash_swap() { TradeId = parentTrade.id, TradeCashId = tradeCash.id, StartDate = parentTrade.StartDate, OptId = UserId, OptName = UserName, OptDate = DateTime.Now }; DbContext.trade_cash_swap.Add(tradeCashSwap); } tradeCashSwap.GetAmount = (tradeCashSwap.GetAmount ?? 0) + (trade_cash_swap.GetAmount ?? 0); tradeCashSwap.GetInitialAmount = (tradeCashSwap.GetInitialAmount ?? 0) + (trade_cash_swap.GetInitialAmount ?? 0); tradeCashSwap.GetExtraAmount = (tradeCashSwap.GetExtraAmount ?? 0) + (trade_cash_swap.GetExtraAmount ?? 0); tradeCashSwap.GetCostFee = (tradeCashSwap.GetCostFee ?? 0) + (trade_cash_swap.GetCostFee ?? 0); tradeCashSwap.PayAmount = (tradeCashSwap.PayAmount ?? 0) + (trade_cash_swap.PayAmount ?? 0); tradeCashSwap.PayInitialAmount = (tradeCashSwap.PayInitialAmount ?? 0) + (trade_cash_swap.PayInitialAmount ?? 0); tradeCashSwap.PayExtraAmount = (tradeCashSwap.PayExtraAmount ?? 0) + (trade_cash_swap.PayExtraAmount ?? 0); tradeCashSwap.PayCostFee = (tradeCashSwap.PayCostFee ?? 0) + (trade_cash_swap.PayCostFee ?? 0); new TradeCashService(this).SaveTradeCashDetail(tradeCash); new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(parentTrade, tradeCash, tradeCash.ValueDate, true); tradeCash.Amount += tc.Amount; tc.ParentTradeId = td.ParentTradeId; tc.ParentTradeCashId = tradeCash.id; DbContext.SaveChanges(); } } DbContext.SaveChanges(); } } }