diff --git a/YLErpDAL/BLL/EodSettlement/RealTimeClientBanlanceService.cs b/YLErpDAL/BLL/EodSettlement/RealTimeClientBanlanceService.cs index 3270e665..fef0aa83 100644 --- a/YLErpDAL/BLL/EodSettlement/RealTimeClientBanlanceService.cs +++ b/YLErpDAL/BLL/EodSettlement/RealTimeClientBanlanceService.cs @@ -954,13 +954,13 @@ namespace YLErp.BLL.Eod }; var todayPostionList = todayPositionQuery.ToArray(); - //using var bondDb = new BondOmsDBContext(); - //var clientLongIds = new List(); - //clientIds.ForEach(item => - //{ - // clientLongIds.Add(Convert.ToInt64(item)); - //}); - //var swapPositionQuery = bondDb.client_position.Where(x => clientLongIds.Contains(x.client_id ?? 0)).ToList().GroupBy(g => g.client_id); + using var bondDb = new BondOmsDBContext(); + var clientLongIds = new List(); + clientIds.ForEach(item => + { + clientLongIds.Add(Convert.ToInt64(item)); + }); + var swapPositionQuery = bondDb.client_position.Where(x => clientLongIds.Contains(x.client_id ?? 0)).ToList().GroupBy(g => g.client_id); //持仓合计 var pQuerySum = from t in todayPostionList group t by t.ClientId into g @@ -1048,101 +1048,19 @@ namespace YLErp.BLL.Eod balance.ClientSellPositionPnl = (parentPositionPnlTotal.FirstOrDefault(x => x.clientId == data.clientId)?.ClientSellPositionPnl ?? 0) + (singlePositionPnlTotal.FirstOrDefault(x => x.clientId == data.clientId)?.ClientSellPositionPnl ?? 0); } - //foreach (var data in swapPositionQuery) - //{ - // var clientId = Convert.ToInt32(data.Key); - // var balance = _clientBalanceDic[clientId]; - // var pvSum = data.Sum(s => s.swap_market_value ?? 0); - // var pnlSum = data.Sum(s => s.position_profit_loss ?? 0); - // var preminumSum = data.Sum(s => s.commission ?? 0); - // var dayPnlSum = data.Sum(s => s.today_profit_loss ?? 0); - // balance.PotentialSurpluses += -Convert.ToDouble(pvSum); - // balance.PositionPv += Convert.ToDouble(pvSum); - // balance.RoundedPositionPv += Convert.ToDouble(pvSum); - // balance.PositionPnl += Convert.ToDouble(pnlSum); - // balance.RoundedPositionPnl += Convert.ToDouble(pnlSum); - // balance.PositionPremiumNetCash += Convert.ToDouble(preminumSum); - // //balance.DaliyPnl += Convert.ToDouble(dayPnlSum); - // //balance.RoundedDaliyPnl += Convert.ToDouble(dayPnlSum); - //} - //专业版雪球预付金 - if (PS.Config.ErpElement.SuppotSnowballSpecialist) + foreach (var data in swapPositionQuery) { - //DbContext.SetDebugLog(); - - var query = from p in DbContext.intraday_trade_position - join sn in DbContext.trade_snowball on p.TradeId equals sn.TradeId - join t in DbContext.trade on p.TradeId equals t.id - where p.ValueDate == _valueDate && clientIds.Contains(p.ClientId) - && ConsTrade.NeedMarginTradeStatusList.Contains(p.TradeStatus) - && sn.PrepaymentUsed - select new - { - p.ClientId, - Prepayment = (sn.PrepaymentRatio ?? 0) * t.Notional * (t.SpotPrice ?? 0) - * (t.BuySell == "卖出" ? 1 : -1) - }; - - var querySum = from q in query - group q by q.ClientId into g - select new - { - ClientId = g.Key, - Prepayment = g.Sum(t => t.Prepayment) - }; - - var sumPrepayments = querySum.ToArray(); - - foreach (var item in sumPrepayments) - { - if (_clientBalanceDic.TryGetValue(item.ClientId, out var balance)) - { - balance.PrepaymentAmount = item.Prepayment; - } - } + var clientId = Convert.ToInt32(data.Key); + var balance = _clientBalanceDic[clientId]; + var pvSum = data.Sum(s => s.swap_market_value ?? 0); + var pnlSum = data.Sum(s => s.position_profit_loss ?? 0); + var posiSum = data.Sum(s => s.position_notional_principal ?? 0); + balance.PotentialSurpluses += Convert.ToDouble(pvSum); + balance.PositionPv += Convert.ToDouble(pvSum); + balance.RoundedPositionPv += Convert.ToDouble(pvSum); + balance.PositionNotionalPrincipal += Convert.ToDouble(posiSum); } } - /// - /// 获取国君互换实时持仓 - /// - private void ProcessClientSwapPosition_GuoJun(DateTime startDate, DateTime lastSettletDate) - { - var underlyDataSource = DataCacheProvider.GetUnderlyingDataSource(); - var varietyDataSource = DataCacheProvider.GetVarietyDataSource(); - var clientIds = _clientBalanceDic.Keys; - var swap_mannualQuery = DbContext.eod_trade_position_swap_mannual.Where(x => x.ValueDate <= startDate && x.ValueDate >= lastSettletDate);//取收盘日后的最大日期 - if (!swap_mannualQuery.Any()) - { - return; - } - var maxValueDate = swap_mannualQuery.Max(x => x.ValueDate); - var eodPositionSwapMannuals = DbContext.eod_trade_position_swap_mannual.Where(x => x.ValueDate == maxValueDate && clientIds.Contains(x.ClientId)).ToLookup(n => n.ClientId); - foreach (var item in eodPositionSwapMannuals) - { - double swapMargin = 0.0; - double swappv = 0.0; - double swappnl = 0.0; - var eodPostionsSwaps = item.ToList(); - var clientBalance = _clientBalanceDic[item.Key]; - foreach (var x in eodPostionsSwaps) - { - var underly = underlyDataSource.GetData(x.UnderlyingCode); - var variety = varietyDataSource.GetData(underly.UnderlyingTypeId); - - _currencyProvider.TryGetCurrencyRate(variety.QuoteCurrency, clientBalance.SettlementCurrency, out var rateObj); - //预付金导入是客户方向,其他值是交易员方向 - swapMargin += (x.Margin) * rateObj.Rate; - swappv += (x.PositionPnl - x.TotalFee) * rateObj.Rate; - swappnl += (x.PositionPnl * rateObj.Rate); - } - clientBalance.PositionPnl += swappnl; - clientBalance.PositionPv += swappv; - clientBalance.RoundedPositionPv += swappv; - clientBalance.RoundedPositionPnl += swappnl; - clientBalance.PayableMargin -= swapMargin; - } - - } //获取当日所有出入金记录 private void ProcessClientCash(DateTime lastSettletDate) { @@ -1328,7 +1246,7 @@ namespace YLErp.BLL.Eod var marginList = clientPositions.Where(x =>ConsTrade.InterestMarginModels.Contains(x.InterestMode)).Sum(s=>s.InterestPrincipalFix * (s.InterestDirection == 1 ? -1 : 1)); balance.SwapMargin =Convert.ToDouble(marginList); balance.PositionCount= clientTradeIds.Count(); - balance.PositionNotionalPrincipal = Convert.ToDouble(positions.Sum(s=>s.PosiNotionalValue));//实时 + // balance.PositionNotionalPrincipal = Convert.ToDouble(positions.Sum(s=>s.PosiNotionalValue));//实时 } var eodSwapQuery = DbContext.eod_swap.Where(x => clientIds.Contains(x.ClientId) && x.ValueDate >= lastSettletDate && x.ValueDate <= startDate).AsEnumerable().GroupBy(x => x.SwapTradeId) .Select(g => g.OrderByDescending(x => x.ValueDate).FirstOrDefault()).ToList(); @@ -1337,6 +1255,8 @@ namespace YLErp.BLL.Eod eodTradeIds = eodTrades.Select(s => s.id).ToList(); eodSwapQuery = eodSwapQuery.Where(x => eodTradeIds.Contains(x.SwapTradeId)).ToList(); var eodSwapPositions = DbContext.eod_swap_position.Where(x => eodTradeIds.Contains(x.SwapTradeId) && x.ValueDate >= lastSettletDate && x.ValueDate <= startDate && x.PosiDirection > 0); + var swapFlowEvents = DbContext.swap_flow_event.Where(x => x.DataState == (int)SwapFlowDateStateEnum.完成 && x.EventType == (int)SwapFlowEventTypeEnum.平仓 && x.EventDate > lastSettletDate && tradeIds.Contains(x.SwapTradeId)).AsNoTracking().ToList(); + var swapPositions = DbContext.swap_position.Where(x => tradeIds.Contains(x.SwapTradeId) && x.IsInitial && !x.Invalid && x.PosiDirection > 0).AsNoTracking().ToList(); var eodSwaps = eodSwapQuery.GroupBy(g => g.ClientId).ToList(); foreach (var data in eodSwaps) { @@ -1344,33 +1264,46 @@ namespace YLErp.BLL.Eod var clientEodSwaps = data.GroupBy(g => g.SwapTradeId).ToList(); foreach (var item in clientEodSwaps) { - var eodSwapList = item.OrderBy(o => o.ValueDate).ToList(); - var eodSwap = eodSwapList[eodSwapList.Count - 1]; - var lastEodSwap = eodSwapList.Count <= 1 ? null : eodSwapList[eodSwapList.Count - 2]; - //潜在行权收益等于实值额 - balance.PotentialSurpluses += -Convert.ToDouble(eodSwap.PostionValue); - //持仓市值 - balance.PositionPv += Convert.ToDouble(eodSwap.PostionValue); - balance.RoundedPositionPv += Math.Round(Convert.ToDouble(eodSwap.PostionValue), 2); - balance.SellPv += -Convert.ToDouble(eodSwap.MarketValueShort); - //持仓盈亏 - var pnl = eodSwap.PostionValue; - var lastPnl = lastEodSwap?.PostionValue; - //当日盈亏 - if (eodSwap.ValueDate == startDate) + var lastEodSwap = item.First(); + var eodPosi = eodSwapPositions.FirstOrDefault(x => x.ValueDate == lastEodSwap.ValueDate && x.SwapTradeId == lastEodSwap.SwapTradeId); + var posiQty = eodPosi?.PosiQuantity ?? 0; + var flowEvents = swapFlowEvents.Where(x => x.SwapTradeId == item.Key).ToList(); + var unwindQty = flowEvents.Sum(s => s.Quantity); + var pnl = lastEodSwap.PostionValue; + decimal unwindPercent = 0; + if (unwindQty != 0) { - balance.DaliyPnl += Convert.ToDouble(pnl - lastPnl + eodSwap.TdRealizedPnL); - balance.RoundedDaliyPnl += Math.Round(Convert.ToDouble(pnl - lastPnl), 2); - balance.UpdateDate = balance.UpdateDate > eodSwap.OptTime ? balance.UpdateDate : eodSwap.OptTime; + if (posiQty == 0 || unwindQty >= posiQty) + { + pnl = 0; + } + else + { + pnl = pnl - (pnl * unwindQty / posiQty); + } + unwindPercent = posiQty == 0 ? 0 : unwindQty / posiQty; } - balance.WinLoss += Convert.ToDouble(eodSwap.TdRealizedPnL); - + var tdRealizedPnL = flowEvents.Where(x => x.EventDate > lastSettletDate).ToList().Sum(s => s.InterestClosePnL + s.MarkClosePnl); + var tdRealizedInterestPnL = flowEvents.Where(x => x.EventDate > lastSettletDate).ToList().Sum(s => s.InterestClosePnL * unwindPercent); + var currentEvents = flowEvents.Where(x => x.EventDate == startDate).ToList(); + var currentRealizedPnl = currentEvents.Sum(s => s.InterestClosePnL + s.MarkClosePnl); + //潜在行权收益等于实值额 + balance.PotentialSurpluses += -Convert.ToDouble(pnl); + //持仓市值 + balance.SellPv += -Convert.ToDouble(lastEodSwap.MarketValueShort) * -1; + //当日盈亏 + balance.DaliyPnl += Convert.ToDouble(currentRealizedPnl) * -1; + balance.RoundedDaliyPnl += Math.Round(Convert.ToDouble(currentRealizedPnl), 2) * -1; + if (lastEodSwap.ValueDate == startDate) + { + balance.UpdateDate = balance.UpdateDate > lastEodSwap.OptTime ? balance.UpdateDate : lastEodSwap.OptTime; + } + balance.WinLoss += Convert.ToDouble(tdRealizedPnL) * -1; balance.PositionPnl += Convert.ToDouble(pnl); balance.RoundedPositionPnl += Math.Round(Convert.ToDouble(pnl), 2); //期权空头浮动盈利=∑max(期权空头持仓*(期权合约成本价-期权合约现价), 0) 从客户角度看的 - balance.ClientSellPositionPnl += Convert.ToDouble(eodSwap.FloatingPnL); + balance.ClientSellPositionPnl += Convert.ToDouble(lastEodSwap.FloatingPnL) * -1; } - } } /// @@ -1397,7 +1330,10 @@ namespace YLErp.BLL.Eod UnderlyingCode = item.security_id, ClientId = item.client_id ?? 0, ClientName = item.client_name, - TradingQty = (item.order_qty ?? 0) - (item.last_shares ?? 0) + TradingQty = (item.order_qty ?? 0) - (item.last_shares ?? 0), + TradingAmountAvg = item.full_price ?? 0, + TradingAmountFeeAvg = item.full_price ?? 0, + TradingFee = 0 }; // clientOrder中数量单位为万 flow.TradingQty *= 10000; @@ -1408,25 +1344,27 @@ namespace YLErp.BLL.Eod var positionQuery = from t in DbContext.trade.Where(x => clientIds.Contains(x.ClientId) && x.TradeType == "收益互换" && x.ValidState != ConsGlobal.InValid && ConsTrade.PositionTradeStatusList.Contains(x.TradeStatus)) join p in DbContext.swap_position on t.id equals p.SwapTradeId where !p.IsInitial && !p.Invalid - select new + select new swap_flow { - t.ClientId, - p.PosiDirection, - p.PosiQuantity, - p.UnderlyingCode, - p.PositionType + ClientId = t.ClientId, + TradingQty = p.PosiQuantity, + UnderlyingCode = p.UnderlyingCode, + BsType = p.PositionType, + TradingAmountAvg = p.PosiGrossPrice, + TradingAmountFeeAvg = p.PosiNetPrice, + TradingFee = 0 }; var positions = positionQuery.ToList(); // step4 将未簿记持仓与已有持仓分别 按客户,标的分组计算各自轧差名义本金 // 取设置的预付金比例 var clientMarginTemplates = DbContext.client_marginrate.Where(x => x.ValueDate <= startDate).OrderByDescending(o => o.ValueDate).AsNoTracking().ToList(); - var flowGroup = flows.GroupBy(s => new { s.ClientId, s.UnderlyingCode }); + var flowGroup = flows.GroupBy(s => s.ClientId); foreach (var itemGroup in flowGroup) { - var balance = clientBalanceDic[itemGroup.Key.ClientId ?? 0]; + var balance = clientBalanceDic[itemGroup.Key ?? 0]; //string marginType = balance.ClientType == 1 ? "多空组合" : "品种"; // 获取客户预付金比例设置 - var clientMarginTemplate = clientMarginTemplates.FirstOrDefault(x => x.ClientId == itemGroup.Key.ClientId ); + var clientMarginTemplate = clientMarginTemplates.FirstOrDefault(x => x.ClientId == itemGroup.Key ); if (clientMarginTemplate == null) { clientMarginTemplate = clientMarginTemplates.FirstOrDefault(x => x.ClientId == 0 ); @@ -1436,84 +1374,89 @@ namespace YLErp.BLL.Eod { continue; } - // 获取当前客户当前标的持仓数据,合并后的名义本金数量 - var positionLsit = positions.Where(x => x.UnderlyingCode == itemGroup.Key.UnderlyingCode && x.ClientId == itemGroup.Key.ClientId).ToList(); - var positionNotional = positionLsit.Sum(s => s.PosiQuantity * (s.PositionType == (int)PositionTypeFlag.Long ? 1 : -1)); - //获取虚拟持仓合并后的名义本金数量 - var virtualNotional = itemGroup.Sum(s => s.TradingQty * (s.BsType == (int)PositionTypeFlag.Long ? 1 : -1)); - decimal money = CalcFrozanMarginMoney(positionNotional, virtualNotional, balance.ClientType == 1, clientMarginTemplate); - balance.FrozenMarginMoney += Convert.ToDouble(money); + var clientPositions = positions.Where(x => x.ClientId == itemGroup.Key).ToList(); + foreach (var item in itemGroup.GroupBy(s => s.UnderlyingCode)) + { + // 获取当前客户当前标的持仓数据,合并后的名义本金数量 + var positionLsit = clientPositions.Where(x => x.UnderlyingCode == item.Key).ToList(); + decimal money = CalcDmaMoney(positionLsit, item.ToList(), clientMarginTemplate); + balance.FrozenMarginMoney += Convert.ToDouble(money); + } } } /// - /// 计算冻结的预付金变化 + /// 计算流水带来的资金变化 /// - /// 持仓名义本金 - /// 虚拟持仓名义本金 - /// 是否定义文件类型客户 - /// 预付金设置信息 - /// - private decimal CalcFrozanMarginMoney(decimal positionNotional, decimal virtualNotional, bool dma, client_marginrate clientMarginTemplate) + /// 持仓列表 + /// 流水列表 + /// 客户保证金模板 + /// 资金变化金额 + public decimal CalcDmaMoney(List positions, List flows, client_marginrate clientMarginTemplate) { decimal money = 0; - var virtualPosi = positionNotional + virtualNotional; - var posiType = positionNotional >= 0 ? (int)PositionTypeFlag.Long : (int)PositionTypeFlag.Short; - var virtualPosiType = virtualPosi >= 0 ? (int)PositionTypeFlag.Long : (int)PositionTypeFlag.Short; - var positionNotionalAbs = Math.Abs(positionNotional); - var virtualNotionalAbs = Math.Abs(virtualNotional); - decimal longMarginRate = 0; - decimal shortMarginRate = 0; - //普通客户 - if (!dma) + var marginRate = (decimal)clientMarginTemplate.InitMarginRate; + + // 处理持仓与流水的平仓逻辑 + foreach (var position in positions.ToList()) // 使用 ToList() 避免修改集合时的问题 { - longMarginRate = Convert.ToDecimal(clientMarginTemplate.InitMarginRate); - shortMarginRate = longMarginRate; - } - else //定义文件类型客户 - { - longMarginRate = Convert.ToDecimal(clientMarginTemplate.LongInitMarginRate); - shortMarginRate = Convert.ToDecimal(clientMarginTemplate.ShortInitMarginRate); - } - // 当前持仓多头 - if (posiType == (int)PositionTypeFlag.Long) - { - if (virtualPosiType == (int)PositionTypeFlag.Long) + var oppositeFlows = flows.Where(x => x.BsType != position.BsType && x.TradingQty > 0).ToList(); + foreach (var flow in oppositeFlows) { - money = virtualNotional * longMarginRate; - } - else //虚拟持仓空头 - { - if (virtualNotionalAbs <= positionNotionalAbs) - { - money = virtualNotional * longMarginRate; - } - else - { - money = (-virtualNotional * shortMarginRate) - positionNotional * (longMarginRate + shortMarginRate); - } + if (position.TradingQty <= 0) break; // 持仓已处理完毕 + + decimal tradedQty = Math.Min(position.TradingQty, flow.TradingQty); + money += CalculateClosePositionProfit(position, flow, tradedQty, marginRate, isPositionFlow: true); + + // 更新持仓和流水的数量 + position.TradingQty -= tradedQty; + flow.TradingQty -= tradedQty; } } - // 当前持仓空头 - else + + // 处理流水之间的轧差逻辑 + foreach (var flow in flows.Where(x => x.TradingQty > 0).ToList()) { - if (virtualPosiType == (int)PositionTypeFlag.Short) + var oppositeFlows = flows.Where(x => x.BsType != flow.BsType && x.TradingQty > 0).ToList(); + foreach (var oppositeFlow in oppositeFlows) { - money = (-virtualNotional) * shortMarginRate; - } - else //虚拟持仓多头 - { - if (virtualNotionalAbs <= positionNotionalAbs) - { - money = (-virtualNotional) * shortMarginRate; - } - else - { - money = (virtualNotional + positionNotional) * longMarginRate + positionNotional * shortMarginRate; - } + if (flow.TradingQty <= 0) break; // 当前流水已处理完毕 + + decimal tradedQty = Math.Min(flow.TradingQty, oppositeFlow.TradingQty); + money += CalculateClosePositionProfit(flow, oppositeFlow, tradedQty, marginRate, isPositionFlow: false); + + // 更新流水的数量 + flow.TradingQty -= tradedQty; + oppositeFlow.TradingQty -= tradedQty; } } - return money; + + // 处理剩余流水的新开仓逻辑 + foreach (var flow in flows.Where(x => x.TradingQty > 0)) + { + // 新开仓保证金 + money += marginRate * flow.TradingQty * flow.TradingAmountAvg; + } + + return Math.Round(money, 2, MidpointRounding.AwayFromZero); } + + /// + /// 计算平仓损益和保证金释放 + /// + private decimal CalculateClosePositionProfit(swap_flow position, swap_flow flow, decimal tradedQty, decimal marginRate, bool isPositionFlow) + { + decimal floatRatio = -1m; // 默认支付 + decimal longRatio = position.BsType == 1 ? 1m : -1m; + + // 平仓损益 + decimal profit = (flow.TradingAmountAvg - position.TradingAmountAvg) * tradedQty * floatRatio * longRatio; + + // 如果是持仓与流水平仓,计算保证金释放;否则不计算 + decimal releasedMargin = isPositionFlow ? marginRate * tradedQty * position.TradingAmountAvg : 0; + + return profit - releasedMargin; + } + public class ClientBalanceEx : ClientSettleBalance { public double InFundOther { get; set; } diff --git a/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs b/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs index a6b18619..cee49fc2 100644 --- a/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs +++ b/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs @@ -586,6 +586,9 @@ namespace YLErp.BLL.Eod } bondDb.SaveChanges(); SetClientPositionPrice(clientPosition); + clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1); + clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1) - clientPosition.commission; + clientPosition.position_profit_loss = Math.Round(clientPosition.position_profit_loss ?? 0, 2, MidpointRounding.AwayFromZero); clientPosition.today_profit_loss = clientPosition.swap_market_value - lastPv; if (clientPosition.deal_full_price_avg > 0 && enableCalcBongd)//发kafka 获取成交收益率 { @@ -629,8 +632,10 @@ namespace YLErp.BLL.Eod } bondDb.SaveChanges(); SetClientPositionPrice(clientPosition); + clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1); + clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1); + clientPosition.position_profit_loss = Math.Round(clientPosition.position_profit_loss ?? 0, 2, MidpointRounding.AwayFromZero); clientPosition.today_profit_loss = clientPosition.swap_market_value; - //发kafka 获取成交收益率 if (clientPosition.deal_full_price_avg > 0 && enableCalcBongd) { @@ -781,23 +786,21 @@ namespace YLErp.BLL.Eod UnderlyingCode = swapflow.UnderlyingCode, BsType = swapflow.BsType, TradingQty = gourpItem.Sum(s => s.TradingQty), - TradingFeePending = gourpItem.Sum(s => s.TradingFee), + TradingFee = gourpItem.Sum(s => s.TradingFee), DataState = (int)SwapFlowDateStateEnum.等待完成, ContractSize = swapflow.ContractSize, ClientId = swapflow.ClientId, + TradingAmount = gourpItem.Sum(s => s.TradingAmount) }; int tradeSide = swap_flow_summary.BsType == (int)EnumDirection.Long ? 1 : -1; swap_flow_summary.FirstFlowTime = swapflow.OptTime; swap_flow_summary.SettleDate = gourpItem.Max(s => s.SettleDate); - swap_flow_summary.TradingAmount = swap_flow_summary.TradingQty * swap_flow_summary.ContractSize; swap_flow_summary.TradingAmountAvg = swap_flow_summary.TradingQty == 0 ? 0 : gourpItem.Sum(s => s.TradingAmountAvg * s.TradingQty) / swap_flow_summary.TradingQty; - swap_flow_summary.TradingAmountFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountAvg : swap_flow_summary.TradingAmountAvg + swap_flow_summary.TradingFeePending * tradeSide / swap_flow_summary.TradingQty; - swap_flow_summary.TradingAmountNetAvg = swap_flow_summary.TradingQty == 0 ? 0 : gourpItem.Sum(s => s.TradingAmountNet * s.TradingQty) / swap_flow_summary.TradingQty; - swap_flow_summary.TradingAmountNetFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountNetAvg : swap_flow_summary.TradingAmountNetAvg + swap_flow_summary.TradingFeePending * tradeSide / swap_flow_summary.TradingQty; + swap_flow_summary.TradingAmountAvg = Math.Round(swap_flow_summary.TradingAmountAvg, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); + swap_flow_summary.TradingAmountFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountAvg : swap_flow_summary.TradingAmountAvg + swap_flow_summary.TradingFee * tradeSide / swap_flow_summary.TradingQty; + swap_flow_summary.TradingAmountFeeAvg = Math.Round(swap_flow_summary.TradingAmountFeeAvg, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); swap_flow_summary.TradingAmountAvg *= multiplier; swap_flow_summary.TradingAmountFeeAvg *= multiplier; - swap_flow_summary.TradingAmountNetAvg *= multiplier; - swap_flow_summary.TradingAmountNetFeeAvg *= multiplier; list.Add(swap_flow_summary); } return list.OrderByDescending(o => o.TradingQty).ToList(); diff --git a/YLErpDAL/Model/TradeClientCashCalcReq.cs b/YLErpDAL/Model/TradeClientCashCalcReq.cs index 44c882ac..266bce89 100644 --- a/YLErpDAL/Model/TradeClientCashCalcReq.cs +++ b/YLErpDAL/Model/TradeClientCashCalcReq.cs @@ -27,5 +27,9 @@ namespace YLErp.Model /// 买卖方向 /// public int side { get; set; } + /// + /// 含费全价 + /// + public decimal price { get; set; } } } diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index bb640927..6055432a 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -837,7 +837,7 @@ namespace YLErp.Modules.SwapModule unwindData.AnnualDays = tradeExtend == null ? 365 : tradeExtend.ExtendObj.AnnualDays; unwindData.CloseMethod = unwindQty == unwindData.PositionQty ? (int)CloseMethodEnum.全部平仓 : (int)CloseMethodEnum.部分平仓; unwindData.ClosePercent = unwindData.PositionQty == 0 ? 0 : unwindPercent; - unwindData.CloseNotionalValue = unwindData.PosiNotionalValue* unwindPercent; + unwindData.CloseNotionalValue = position == null ? 0 : unwindQty * position.PosiGrossPrice * position.ContractSize; unwindData.CloseQty = unwindQty; if (position != null) { @@ -867,9 +867,9 @@ namespace YLErp.Modules.SwapModule floatEvent.TradingFeePending = position.PosiTradingFeePending * unwindData.ClosePercent; var mergeClosePercent = mergeQty == 0 ? 0 : unwindQty / mergeQty; floatEvent.TradingFee = penddingFee * mergeClosePercent; - floatEvent.MarkClosePnl = (unwindPriceFee - position.PosiNetPrice) * unwindQty * floatRatio * longRatio; - floatEvent.MarkClosePnl = decimal.Parse(floatEvent.MarkClosePnl.ToString("0.00")); - floatEvent.TradingAmount = floatEvent.Quantity * floatEvent.ContractSize; + floatEvent.MarkClosePnl = (unwindPrice - position.PosiGrossPrice) * unwindQty * floatRatio * longRatio; + floatEvent.MarkClosePnl = Math.Round(floatEvent.MarkClosePnl + (floatEvent.TradingFee * floatRatio * -1), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + floatEvent.TradingAmount = unwindPrice * floatEvent.Quantity * floatEvent.ContractSize; floatEvent.OptLog = "流水自动"; floatEvent.ClientId = td.ClientId; floatEvent.SetOpt(UserInfo); @@ -1038,10 +1038,10 @@ namespace YLErp.Modules.SwapModule { AddClientCashInCashOut(td, Convert.ToDouble(unwindData.SwapMarginAmount), ClientCashInCashOut.系统操作_应付预付金, unwindData.ValueDate); } - if (unwindData.SwapMarginRebatePnl != 0) - { - AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapMarginRebatePnl), ClientCashInCashOut.系统操作_预付金返息, unwindData.ValueDate); - } + //if (unwindData.SwapMarginRebatePnl != 0) + //{ + // AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapMarginRebatePnl), ClientCashInCashOut.系统操作_预付金返息, unwindData.ValueDate); + //} var flowList = new List(unwindData.FlowEvents); var eventId = SaveSwapDeal(unwindData, (int)SwapEventTypeEnum.平仓, clientCashId, actionMsg); if (unwindData.CloseMethod == (int)CloseMethodEnum.全部平仓) @@ -1376,15 +1376,9 @@ namespace YLErp.Modules.SwapModule { if (!string.IsNullOrEmpty(position.UnderlyingCode)) { - var dealFloat = flowList.FirstOrDefault(x => !string.IsNullOrEmpty(x.UnderlyingCode)); - if (dealFloat != null) - { - decimal ratio = dealFloat.EventType == (int)SwapFlowEventTypeEnum.平仓 ? -1m : 1m; - position.PosiTradingFeePending += dealFloat.TradingFeePending * ratio; - position.PosiDividendIncome += dealFloat.DividendPending; - } position.PosiQuantity -= unwindData.CloseQty; - position.PosiNotionalValue = position.PosiQuantity * position.ContractSize; + position.PosiNotionalValue = position.PosiGrossPrice * position.PosiQuantity * position.ContractSize; + position.PosiTradingFee -= position.PosiTradingFee * unwindData.ClosePercent; } else { @@ -1401,73 +1395,6 @@ namespace YLErp.Modules.SwapModule } } } - /// - /// 单标的互换更新实时持仓信息 - /// - /// - /// - /// - public void UpdateInitalPosition(DateTime valueDate, trade td, List positions, List swpFlowEvents) - { - var preSettleDate = GetPreValueDate(valueDate);//上一交易日期 - var realPositions = positions.Where(x => !x.IsInitial); - var originalPositions = positions.Where(x => x.IsInitial); - var unwindFlowEvents = swpFlowEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.开仓 || x.EventType == (int)SwapFlowEventTypeEnum.平仓).ToList(); - List preEodSwapPositions = DbContext.eod_swap_position.Where(x => !x.Invalid && x.SwapTradeId == td.id && valueDate == preSettleDate).ToList(); - foreach (var position in realPositions) - { - var currEod = new eod_swap_position() { ContractSize = position.ContractSize }; - var eod = preEodSwapPositions.FirstOrDefault(x => x.PositionId == position.PositionId); - if (eod == null) - { - eod = new eod_swap_position() - { - ContractSize = position.ContractSize, - PositionType = position.PositionType, - PosiDirection = position.PosiDirection, - PosiFeePending = 0, - PosiNetPrice = position.PosiNetPrice, - PosiGrossPrice = position.PosiGrossPrice, - PosiNetFeePrice = position.PosiNetFeePrice, - PosiNetNoFeePrice = position.PosiNetNoFeePrice, - }; - } - new SwapEodPositionService(UserInfo).SetPriceInfoByFlowEvent(eod, currEod, unwindFlowEvents, position); - var oriPosition = originalPositions.FirstOrDefault(x => x.id == position.PositionId); - position.InterestAmount = currEod.RealizedInterest; - position.InterestFeePending = currEod.InterestFeePending; - position.PosiTradingFeePending = currEod.PosiFeePending; - position.PosiDividendIncome = currEod.PosiDividendSum; - position.PosiQuantity = currEod.PosiQuantity; - position.PosiNetPrice = currEod.PosiNetPrice; - position.PosiGrossPrice = currEod.PosiGrossPrice; - position.PosiNetFeePrice = currEod.PosiNetFeePrice; - position.PosiNetNoFeePrice = currEod.PosiNetNoFeePrice; - position.PosiNotionalValue = currEod.PosiNotionalValue; - td.StockEqvNotional = Convert.ToDouble(position.PosiNotionalValue); - td.TradeAmount = Convert.ToDouble(position.PosiQuantity); - } - } - - /// - /// 获取标的平仓比例 - /// - /// - /// - private decimal GetUnwindPercent(int tradeId) - { - var swapEvents = DbContext.swap_event.Where(x => x.SwapTradeId == tradeId && !x.Invalid && x.EventType == (int)SwapEventTypeEnum.平仓).ToList(); - decimal unwindPercent = 0; - foreach (var swapEvent in swapEvents) - { - if (!string.IsNullOrEmpty(swapEvent.EventData)) - { - swapEvent.unwindData = JsonConvert.DeserializeObject(swapEvent.EventData); - unwindPercent += swapEvent.unwindData.ClosePercent; - } - } - return unwindPercent; - } } } diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 460aa950..0a6d5906 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -156,11 +156,7 @@ namespace YLErp.Modules.SwapModule var curEodPosis = DealFloatPositions(posiList, realPosiList, eodPositions, todyEodPositions, settleDate, td, preSettleDate, flowEvents); var posiLongNotional = curEodPosis.Where(s => s.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue); var posiShortNotional = curEodPosis.Where(s => s.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue); - var closePosiNotional = curEodPosis.Where(s => s.TdCloseQty > 0).Sum(s => s.TdCloseQty * s.ContractSize); - if (longShort) - { - closePosiNotional = curEodPosis.Where(s => s.TdCloseQty > 0).Sum(s => s.TdCloseQty * s.ContractSize * s.PosiNetPrice); - } + var closePosiNotional = curEodPosis.Where(s => s.TdCloseQty > 0).Sum(s => s.TdCloseQty * s.ContractSize * s.PosiNetPrice); var grossPrice = curEodPosis.Where(x => x.PosiDirection > 0).FirstOrDefault()?.PosiGrossPrice ?? 0; //处理利息腿 DealInterests(interestList, eodPositions, todyEodPositions, settleDate, td, flowEvents, autoInterests, lastEodSwap, posiLongNotional, posiShortNotional, closePosiNotional, grossPrice, orginPv); @@ -314,20 +310,9 @@ namespace YLErp.Modules.SwapModule var unwindEvents = flowEvents.Where(x => x.PositionId == posi.id).ToList();//当前日平仓信息 var realPosition = realPosiList.FirstOrDefault(s => s.PositionId == posi.id); eod_swap_position eodPosi = new eod_swap_position(); - if (eodPosition == null || td.StartDate == settleDate) + if (eodPosition == null || td.TradeDate == settleDate) { - if (tdEodPosition == null)//第一次生成归档信息 - { - eodPosi = SaveCurrentEodInitalPosi(posi, td, settleDate, preSettleDate, unwindEvents); - } - else - { - tdEodPosition.PosiFeePending = posi.PosiTradingFeePending; - tdEodPosition.PosiNotionalValue = tdEodPosition.PosiQuantity * tdEodPosition.ContractSize; - tdEodPosition.PosiNetFeePrice = posi.PosiNetFeePrice; - tdEodPosition.PosiNetNoFeePrice = posi.PosiNetNoFeePrice; - } - + eodPosi = SaveCurrentEodInitalPosi(posi, td, settleDate, preSettleDate, unwindEvents); } else if (unwindEvents.Count() == 0) { @@ -1276,12 +1261,12 @@ namespace YLErp.Modules.SwapModule curretEod.PosiNetFeePrice = position.PosiNetFeePrice; curretEod.PosiNetNoFeePrice = position.PosiNetNoFeePrice; curretEod.PosiQuantity = position.PosiQuantity; - curretEod.PosiTradingFee = position.PosiTradingFee; + curretEod.PosiTradingFee = -position.PosiTradingFee * directionRatio; } else { - var eventTradingFee = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.开仓 || x.EventType == (int)SwapFlowEventTypeEnum.平仓).Sum(s => s.TradingFeePending * (s.EventType == (int)SwapFlowEventTypeEnum.开仓 ? 1 : -1)); - curretEod.PosiFeePending = eod.PosiFeePending + eventTradingFee; + var eventTradingFee = openFlowEvents.Sum(s => s.TradingFee); + curretEod.PosiTradingFee = eod.PosiTradingFee - eventTradingFee * directionRatio; if (openFlowEvents.Count() == 0) { curretEod.PosiNetPrice = eod.PosiNetPrice; @@ -1297,12 +1282,16 @@ namespace YLErp.Modules.SwapModule { posiQty = 0; } - curretEod.PosiGrossPrice = (eod.PosiGrossPrice * posiQty + openFlowEvents.Sum(a => a.Quantity * a.TradingAmountAvg)) / (eod.PosiQuantity + openQty); - curretEod.PosiNetNoFeePrice = (eod.PosiNetNoFeePrice * posiQty + openFlowEvents.Sum(a => a.Quantity * a.TradingAmountNetAvg)) / (eod.PosiQuantity + openQty); - curretEod.PosiNetFeePrice = curretEod.PosiQuantity == 0 ? eod.PosiNetFeePrice : curretEod.PosiNetNoFeePrice + curretEod.PosiFeePending / curretEod.PosiQuantity * shortRatio; - curretEod.PosiNetPrice = curretEod.PosiQuantity == 0 ? eod.PosiNetPrice : curretEod.PosiGrossPrice + curretEod.PosiFeePending / curretEod.PosiQuantity * shortRatio; + curretEod.PosiGrossPrice = (eod.PosiGrossPrice * eod.PosiQuantity + openFlowEvents.Sum(a => a.Quantity * a.TradingAmountAvg)) / (eod.PosiQuantity + openQty); + curretEod.PosiGrossPrice = Math.Round(curretEod.PosiGrossPrice, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); + curretEod.PosiNetPrice = (eod.PosiNetPrice * eod.PosiQuantity + openFlowEvents.Sum(a => a.Quantity * a.TradingAmountFeeAvg)) / (eod.PosiQuantity + openQty); + curretEod.PosiNetPrice = Math.Round(curretEod.PosiNetPrice, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); + curretEod.PosiNetNoFeePrice = (eod.PosiNetNoFeePrice * eod.PosiQuantity + openFlowEvents.Sum(a => a.Quantity * a.TradingAmountNetAvg)) / (eod.PosiQuantity + openQty); + curretEod.PosiNetNoFeePrice = Math.Round(curretEod.PosiNetNoFeePrice ?? 0, 10, MidpointRounding.AwayFromZero); + curretEod.PosiNetFeePrice = (eod.PosiNetFeePrice * eod.PosiQuantity + openFlowEvents.Sum(a => a.Quantity * a.TradingAmountNetFeeAvg)) / (eod.PosiQuantity + openQty); + curretEod.PosiNetFeePrice = Math.Round(curretEod.PosiNetFeePrice ?? 0, 10, MidpointRounding.AwayFromZero); } - curretEod.PosiNotionalValue = curretEod.PosiQuantity * curretEod.ContractSize; + curretEod.PosiNotionalValue = curretEod.PosiGrossPrice * curretEod.PosiQuantity * curretEod.ContractSize; curretEod.TdPosiDividend = unwindEvents.Sum(x => x.DividendIn) * directionRatio; //curretEod.TdCloseFee = unwindEvents.Sum(x => x.TradingFee); curretEod.TdCloseQty = unwindQty; diff --git a/YLErpDAL/Modules/SwapModule/SwapTradeAutoService.cs b/YLErpDAL/Modules/SwapModule/SwapTradeAutoService.cs index 3be05eb7..6be6567e 100644 --- a/YLErpDAL/Modules/SwapModule/SwapTradeAutoService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapTradeAutoService.cs @@ -341,15 +341,19 @@ namespace YLErp.Modules.SwapModule DataState = (int)SwapFlowDateStateEnum.等待完成, ContractSize = swapflow.ContractSize, ClientId = swapflow.ClientId, + TradingAmount = gourpItem.Sum(s => s.TradingAmount), }; int tradeSide = swap_flow_summary.BsType == (int)EnumDirection.Long ? 1 : -1; swap_flow_summary.FirstFlowTime = swapflow.OptTime; swap_flow_summary.SettleDate = gourpItem.Max(s => s.SettleDate); - swap_flow_summary.TradingAmount = swap_flow_summary.TradingQty * swap_flow_summary.ContractSize; swap_flow_summary.TradingAmountAvg = swap_flow_summary.TradingQty == 0 ? 0 : gourpItem.Sum(s => s.TradingAmountAvg * s.TradingQty) / swap_flow_summary.TradingQty; - swap_flow_summary.TradingAmountFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountAvg : swap_flow_summary.TradingAmountAvg + swap_flow_summary.TradingFeePending * tradeSide / swap_flow_summary.TradingQty; + swap_flow_summary.TradingAmountAvg = Math.Round(swap_flow_summary.TradingAmountAvg, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); + swap_flow_summary.TradingAmountFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountAvg : swap_flow_summary.TradingAmountAvg + swap_flow_summary.TradingFee * tradeSide / swap_flow_summary.TradingQty; + swap_flow_summary.TradingAmountFeeAvg = Math.Round(swap_flow_summary.TradingAmountFeeAvg, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); swap_flow_summary.TradingAmountNetAvg = swap_flow_summary.TradingQty == 0 ? 0 : gourpItem.Sum(s => s.TradingAmountNet * s.TradingQty) / swap_flow_summary.TradingQty; - swap_flow_summary.TradingAmountNetFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountNetAvg : swap_flow_summary.TradingAmountNetAvg + swap_flow_summary.TradingFeePending * tradeSide / swap_flow_summary.TradingQty; + swap_flow_summary.TradingAmountNetAvg = Math.Round(swap_flow_summary.TradingAmountNetAvg ?? 0, 10); + swap_flow_summary.TradingAmountNetFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountNetAvg : swap_flow_summary.TradingAmountNetAvg + swap_flow_summary.TradingFee * tradeSide / swap_flow_summary.TradingQty; + swap_flow_summary.TradingAmountNetFeeAvg = Math.Round(swap_flow_summary.TradingAmountNetFeeAvg ?? 0, 10); swap_flow_summary.SetOpt(UserInfo); if (save) { diff --git a/YLErpDAL/Modules/SwapModule/SwapTradeService.cs b/YLErpDAL/Modules/SwapModule/SwapTradeService.cs index d0ce95d8..b9a21eda 100644 --- a/YLErpDAL/Modules/SwapModule/SwapTradeService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapTradeService.cs @@ -114,32 +114,6 @@ namespace YLErp.Modules.SwapModule return dbTrade; } /// - /// 生成推送记录给衡泰 - /// - /// - /// - public void AddPushLog(trade td) - { - bool longShort = td.StructureType == "多空组合"; - if (!longShort) - { - AddSinglePushLog(td); - } - } - /// - /// 生成非多空组合记录 - /// - /// - /// - /// - public void AddSinglePushLog(trade td) - { - var marginModes = new int[] { (int)InterestModeEnum.追加预付金, (int)InterestModeEnum.初始预付金 }; - var positions = DbContext.swap_position.Where(x => x.SwapTradeId == td.id && x.IsInitial && !x.Invalid).ToList(); - td.swap_positions = positions.Where(x => marginModes.Contains(x.InterestMode)).ToList(); - var posiPositions = positions.Where(x => x.PosiDirection > 0).ToList(); - } - /// /// 单标的生成开仓事件 /// /// @@ -254,20 +228,6 @@ namespace YLErp.Modules.SwapModule { var dbTrade = req.Clone(); 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; - } - } - } - InnerSaveTrade(true, dbTrade, ""); return dbTrade; @@ -413,10 +373,8 @@ namespace YLErp.Modules.SwapModule PosiNetFeePrice = flowMerge.TradingAmountNetFeeAvg ?? 0, PosiNetNoFeePrice = flowMerge.TradingAmountNetAvg ?? 0, PosiQuantity = flowMerge.TradingQtyAbs, - PosiNotionalValue = flowMerge.TradingQtyAbs * flowMerge.ContractSize, + PosiNotionalValue = flowMerge.TradingAmountAvg * flowMerge.TradingQtyAbs * flowMerge.ContractSize, PosiTradingFeePending = flowMerge.TradingFeePending, - //PosiTradingFee = flowMerge.TradingFee, - //PosiTradingFeeUnit = flowMerge.TradingQtyAbs == 0 ? 0 : flowMerge.TradingFee * flowMerge.ContractSize / flowMerge.TradingQtyAbs, PosiTradingFee = 0, PosiTradingFeeUnit = 0, SwapTradeId = td.id, @@ -700,10 +658,6 @@ namespace YLErp.Modules.SwapModule new TradeDocumentDataService(this).DeleteBooksAfterEditTrade(dbTrade); } int eventType = isAddNew ? (int)SwapEventTypeEnum.新增交易 : (int)SwapEventTypeEnum.修改交易; - if (!string.IsNullOrEmpty(changsStr)) - { - changsStr = new DatatraceQueryService(UserInfo).ReplaceDataChanges(new trade(), changsStr); - } new SwapEventService(UserInfo).AddSwapEventDate(dbTrade.TradeDate.Value, dbTrade.id, eventType, "", 0, true, "", true); DbContext.SaveChanges(); } @@ -1435,10 +1389,9 @@ namespace YLErp.Modules.SwapModule position.UnderlyingInstrumentType = swap.UnderlyingInstrumentType; position.PosiDirection = swap.PosiDirection; position.PosiGrossPrice = swap.PosiGrossPrice; - position.PosiNetPrice = swap.PosiQuantity == 0 ? 0 : (swap.PosiGrossPrice + (position.PosiTradingFeePending / swap.PosiQuantity) * ratio); - position.PosiNetNoFeePrice = swap.PosiNetNoFeePrice; - position.PosiNetFeePrice = swap.PosiQuantity == 0 ? 0 : (swap.PosiNetNoFeePrice + (position.PosiTradingFeePending / swap.PosiQuantity) * ratio); - position.PosiNotionalValue = swap.PosiQuantity * swap.ContractSize; + position.PosiNetPrice = swap.PosiQuantity == 0 ? 0 : (swap.PosiGrossPrice + (position.PosiTradingFee / swap.PosiQuantity) * ratio); + position.PosiNetPrice = Math.Round(position.PosiNetPrice, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); + position.PosiNotionalValue = position.PosiGrossPrice * swap.PosiQuantity * swap.ContractSize; position.PosiQuantity = swap.PosiQuantity; position.InterestDirection = swap.InterestDirection; position.InterestMode = swap.InterestMode; @@ -1570,7 +1523,6 @@ namespace YLErp.Modules.SwapModule InvalidTradeOptionDatasByDate(tradeId, valueDate, backToBegin); swapEventService.AddSwapEventDate(valueDate, tradeId, (int)SwapEventTypeEnum.回退, string.Empty, 0, false, $"交易回退至{valueDate:yyyy年MM月dd日}"); DbContext.SaveChanges(); - AddPushLog(td); if (del) { new TradeRiskCheckLogService(UserInfo).DeleteLog(td.TradeNumber, valueDate);//重置风控记录 @@ -1708,6 +1660,7 @@ namespace YLErp.Modules.SwapModule { posi.InterestAmount = eodPosi.RealizedInterest; posi.InterestFeePending = eodPosi.InterestFeePending; + posi.InterestPrincipalFix= eodPosi.InterestPrincipalFix; posi.PosiTradingFeePending = eodPosi.PosiFeePending; posi.PosiDividendIncome = eodPosi.PosiDividendSum; posi.PosiQuantity = eodPosi.PosiQuantity; @@ -1731,8 +1684,6 @@ namespace YLErp.Modules.SwapModule var clientCashs = DbContext.ClientCashInCashOut.Where(x => x.TradeId == td.id && x.HappenDate >= valueDate).ToList(); DbContext.ClientCashInCashOut.RemoveRange(clientCashs); DbContext.SaveChanges(); - var marginPosis = swapPositions.Where(x => x.HappenDate <= valueDate || x.InterestMode == (int)InterestModeEnum.初始预付金).ToList(); - ResetMarginAmount(td, valueDate, marginPosis); } /// /// 多空组合回到初始 diff --git a/YLErpWeb/Controllers/SwapTrade2Controller.cs b/YLErpWeb/Controllers/SwapTrade2Controller.cs index ccc4a7f5..0fbe5358 100644 --- a/YLErpWeb/Controllers/SwapTrade2Controller.cs +++ b/YLErpWeb/Controllers/SwapTrade2Controller.cs @@ -337,8 +337,7 @@ namespace YLErp.Web.Controllers try { bool edit = req.id != 0; - var r = swapTradeService.SaveTrade(req); - swapTradeService.AddPushLog(r); + var r= swapTradeService.SaveTrade(req); Task.Run(() => { RealtimePnlCalc.RealtimeSwapPosition(new OptUserInfo(0, "互换实时持仓服务", OptUserFrom.Service)); diff --git a/YLErpWeb/Controllers/trade_spanController.cs b/YLErpWeb/Controllers/trade_spanController.cs index 04c88458..373fa481 100644 --- a/YLErpWeb/Controllers/trade_spanController.cs +++ b/YLErpWeb/Controllers/trade_spanController.cs @@ -191,7 +191,9 @@ namespace YLErp.Web.Controllers BsType = item.side + 1, UnderlyingCode = item.underlyingCode, ClientId = item.clientId, - TradingQty = item.tradingQty + TradingQty = item.tradingQty, + TradingAmountAvg = item.price, + TradingAmountFeeAvg = item.price }; bondFlows.Add(flow); } @@ -205,7 +207,9 @@ namespace YLErp.Web.Controllers clientId = item.Key }; var clientBalanceCache = _yLCache.StringGet("ClientBalance:" + item.Key); - tradeClientCashCalc.availableAmount = (clientBalanceCache?.AvailableMoney ?? 0) - item.Value.FrozenMarginMoney; + var availableMoney = clientBalanceCache?.AvailableMoney ?? 0; + tradeClientCashCalc.availableAmount = availableMoney - item.Value.FrozenMarginMoney; + tradeClientCashCalc.availableAmount = Math.Round(tradeClientCashCalc.availableAmount, 2, MidpointRounding.AwayFromZero); list.Add(tradeClientCashCalc); } return JsonSuccess("", list); diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js index 755506cf..8a707458 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js @@ -205,20 +205,15 @@ const vue = new Vue({ }, //变更数量 changeQuantity(item) { - this.changeSpotPrice(item); - this.changeTradingFeeUnit(item); + this.changeSpotPrice(); }, //变更标的单价 changeSpotPrice(item) { - var notional = item.PosiQuantity * item.ContractSize; - var stockEqvNotional = this.trade.StructureType != '普通收益互换' ? notional : item.PosiGrossPrice * notional; - this.trade.StockEqvNotional = otcformat.trading.stockEqvNotional(stockEqvNotional); - this.StockEqvNotional = item.PosiGrossPrice * notional; + this.changeSpotPrice(); }, //变更标的合约乘数 changeContractSize(item) { - this.changeSpotPrice(item); - this.changeTradingFeeUnit(item); + this.calcNotional(); }, //变更名义本金 changeStockEqvNotional() { @@ -226,10 +221,9 @@ const vue = new Vue({ //计算数量 if (this.paySwapList.length > 0) { var item = this.paySwapList[0]; - var notional = this.trade.StructureType != '普通收益互换' ? item.ContractSize : item.PosiGrossPrice * item.ContractSize; + var notional = item.PosiGrossPrice * item.ContractSize; item.PosiQuantity = notional == 0 ? 0 : this.trade.StockEqvNotional / notional; - this.StockEqvNotional = item.PosiGrossPrice * item.ContractSize * item.PosiQuantity; - this.changeTradingFeeUnit(item); + this.calcNotional(); } }, @@ -250,15 +244,23 @@ const vue = new Vue({ if (this.Obervation) { this.Obervation.ObservationStart = this.trade.StartDate; } - var payItem = this.paySwapList[0]; - this.getSpotPrice(payItem.UnderlyingCode, this.trade.StartDate, payItem); - var national = payItem.PosiQuantity * payItem.ContractSize; - var stockEqvNotional = this.trade.StructureType != '普通收益互换' ? national : payItem.PosiGrossPrice * national;//名义本金=期初价格*数量*乘数 - this.trade.StockEqvNotional = otcformat.trading.stockEqvNotional(stockEqvNotional); + this.calcNotional(); this.refreshDatepicker(); this.changeMarginDate(); //this.initMarginRate(); }, + calcNotional(calcPrice) { + if (this.paySwapList.length > 0) { + var payItem = this.paySwapList[0]; + if (calcPrice) { + this.getSpotPrice(payItem.UnderlyingCode, this.trade.StartDate, payItem); + } + var national = payItem.PosiQuantity * payItem.ContractSize; + var stockEqvNotional = payItem.PosiGrossPrice * national;//名义本金=期初价格*数量*乘数 + this.trade.StockEqvNotional = otcformat.trading.stockEqvNotional(stockEqvNotional); + payItem.PosiNotionalValue = this.StockEqvNotional; + } + }, //变更到期日 changeExerciseDate() { this.refreshDatepicker();