From f88f9f9d3b8faaf274c1f0ad08d071c38202eee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=94=A6=E9=BA=9F=20=E7=8E=8B?= Date: Thu, 27 Aug 2026 16:25:06 +0800 Subject: [PATCH] =?UTF-8?q?BugFix=20=E5=BC=80=E4=BB=93=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E8=B5=84=E9=87=91=E6=97=B6=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs b/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs index d4b6ae4f..d3a5b788 100644 --- a/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs +++ b/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs @@ -1538,8 +1538,27 @@ namespace YLErp.BLL.Eod if (query.Any()) { lastSettletDate = query.Max(t => t.BalanceDate).Value; + //基数行按客户各自最近一次结算日取(找不到全局最新结算日的行时向上回溯)—— + //无持仓/无交易的客户不参与每日EOD日结(如休眠客户、仅入金客户),其日结行会落后于全局结算日, + //严格取全局日期的行会把结存算成0(2026-08-27 客户84实证:日结只到8-24、全局已到8-26,100万入金被漏)。 + //lastSettletDate 仍保留全局口径供下方交易窗口等既有逻辑使用。 clientBanlances = db.ClientBalanceDaily.Where(t => - t.BalanceDate == lastSettletDate && clientIds.Contains(t.ClientId)).ToList(); + t.BalanceDate < valueDate && clientIds.Contains(t.ClientId)).ToList() + .GroupBy(t => t.ClientId) + .Select(g => g.OrderByDescending(x => x.BalanceDate).First()) + .ToList(); + } + //各客户自身基数日(+1为其流水窗口下界);无任何结算行的客户须全量流水 + var baseDateByClient = clientBanlances + .Where(t => t.BalanceDate.HasValue) + .GroupBy(t => t.ClientId) + .ToDictionary(g => g.Key, g => g.Max(t => t.BalanceDate.Value)); + var anyClientWithoutBaseRow = clientIds.Any(id => !baseDateByClient.ContainsKey(id)); + DateTime? flowWindowStart = null; + if (!anyClientWithoutBaseRow && baseDateByClient.Count > 0) + { + //窗口下界放宽到最早基数+1(≤原全局结算日+1,超集拉取),消费点按各客户自身基数过滤防双算 + flowWindowStart = baseDateByClient.Values.Min().AddDays(1); } //获取实时持仓 @@ -1551,16 +1570,19 @@ namespace YLErp.BLL.Eod var swapFlows = db.swap_flow.Where(x => x.DataState == (int)SwapFlowDateStateEnum.等待完成 && x.OccurTime == valueDate).ToList(); ; //获取当日所有出入金记录 var newValuedate = valueDate.AddDays(1); - var lastSettletDateAddOne = lastSettletDate.AddDays(1); //var ClientCashList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认 || (t.Direction == "出金" && ClientCashInCashOut.outCashCals.Contains(t.State))) && clientIds.Contains(t.ClientId ?? 0)) - var ClientCashList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && clientIds.Contains(t.ClientId ?? 0)) + var ClientCashList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" + && (flowWindowStart == null || t.HappenDate >= flowWindowStart) + && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && clientIds.Contains(t.ClientId ?? 0)) join trade in db.trade on cash.TradeId equals trade.id into trade from td in trade.DefaultIfEmpty() where td.TradeType != "收益互换" select cash; - var ClientCashSwapList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && clientIds.Contains(t.ClientId ?? 0)) + var ClientCashSwapList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" + && (flowWindowStart == null || t.HappenDate >= flowWindowStart) + && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && clientIds.Contains(t.ClientId ?? 0)) join trade in db.trade.Where(x => x.TradeType == "收益互换") on cash.TradeId equals trade.id select cash; @@ -1799,7 +1821,9 @@ namespace YLErp.BLL.Eod ? 0.0 : clientBanlance.TodayRemianFundProduct ?? 0.0; //资金净流入 + 权利金收支 + 期权费收支 - var clientCashSwap = ClientCashSwapList.Where(a => a.ClientId == client.id).ToList(); + //流水按该客户自身基数日过滤(窗口下界放宽到最早基数+1 拉取,此处防已结算进基数行的流水双算) + var clientFlowStart = baseDateByClient.TryGetValue(client.id, out var clientBaseDate) ? clientBaseDate.AddDays(1) : DateTime.MinValue; + var clientCashSwap = ClientCashSwapList.Where(a => a.ClientId == client.id && a.HappenDate >= clientFlowStart).ToList(); if (clientCashSwap.Any()) { @@ -1815,7 +1839,7 @@ namespace YLErp.BLL.Eod } curSwapFee = swapFlows.Where(x => x.ClientId == client.id).Sum(s => s.TradingFee); OptionPremiumSwap += Convert.ToDouble(curSwapFee); - var clientCash = ClientCashList.Where(a => a.ClientId == client.id).ToList(); + var clientCash = ClientCashList.Where(a => a.ClientId == client.id && a.HappenDate >= clientFlowStart).ToList(); if (clientCash.Any()) { if (clientCash.Any(a =>