From 5ba3618bcafffb657f8b067bb08ec305954324a8 Mon Sep 17 00:00:00 2001 From: hjhan Date: Fri, 13 Feb 2026 14:52:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(swap):=20=E6=B7=BB=E5=8A=A0=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AE=B0=E5=BD=95=E5=B9=B6=E4=BF=AE=E5=A4=8D=E6=95=B0?= =?UTF-8?q?=E5=80=BC=E8=AE=A1=E7=AE=97=E7=B2=BE=E5=BA=A6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了静态日志记录器用于跟踪方法执行 - 在SwapPositionCompose和SwapEodCompose方法中添加详细的执行参数日志 - 为合约处理流程添加开始和结束状态日志 - 在利息腿归档逻辑中添加处理状态和参数的日志输出 - 将decimal类型的字面量从整数改为带m后缀以确保精度 - 修复了RealizedPnl计算公式,加入利息费用的影响 - 调整了名义金额计算方式,在关闭处理中排除平仓金额 - 修正了利息收入计算中的绝对值问题 - 在数据库操作前后添加详细的实体状态日志 --- .../SwapModule/SwapEodPositionService.cs | 63 +++++++++++++++---- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index edcad514..a8eb3b68 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -18,6 +18,7 @@ namespace YLErp.Modules.SwapModule public class SwapEodPositionService : SwapTradeBaseService { private List marginTypes = new List() { (int)InterestModeEnum.追加预付金, (int)InterestModeEnum.初始预付金 }; + private static readonly IYcLogger Log = LogFactory.GetLogger(typeof(SwapEodPositionService).FullName); public SwapEodPositionService(OptUserInfo optUser) : base(optUser) { @@ -61,6 +62,7 @@ namespace YLErp.Modules.SwapModule public void SwapPositionCompose(DateTime settleDate, DateTime preSettleDate, IEnumerable ClientIds) { var dateStr = settleDate.ToString("yyyy-MM-dd"); + Log.Info("SwapPositionCompose:"+"settleDate:" + settleDate+ " preSettleDate:"+ preSettleDate+ " ClientIds:"+JsonHelper.Serialize(ClientIds)); var tradePredicate = PredicateBuilder.Create(n => n.ValidState != ConsGlobal.InValid && n.TradeType == "收益互换" && n.TradeDate <= settleDate @@ -164,6 +166,7 @@ namespace YLErp.Modules.SwapModule /// public void SwapEodCompose(DateTime settleDate, DateTime preSettleDate, IEnumerable ClientIds) { + Log.Info("SwapEodCompose:" + "settleDate:" + settleDate + " preSettleDate:" + preSettleDate + " ClientIds:" + JsonHelper.Serialize(ClientIds)); var tradePredicate = PredicateBuilder.Create(n => n.ValidState != ConsGlobal.InValid && n.TradeType == "收益互换" && n.TradeDate <= settleDate @@ -177,7 +180,9 @@ namespace YLErp.Modules.SwapModule var tradeQueryList = DbContext.trade.Where(tradePredicate).ToList(); foreach (var td in tradeQueryList) { + Log.Info("【框架合约汇总】处理合约ID为:[" + td.id + "]的数据,收盘时间为:[" + settleDate + "]。开始"); SaveEodSwap(td, settleDate, preSettleDate); + Log.Info("【框架合约汇总】处理合约ID为:[" + td.id + "]的数据,收盘时间为:[" + settleDate + "]。结束"); } DbContext.SaveChanges(); } @@ -207,10 +212,12 @@ namespace YLErp.Modules.SwapModule decimal grossPrice, decimal orginPv) { + Log.Info("===================处理利息腿归档===================="); var hasClose = flowEvents.Any(x => x.EventType == (int)SwapEventTypeEnum.平仓); var hasSwap = flowEvents.Any(x => x.EventType == (int)SwapEventTypeEnum.互换); foreach (var interest in interestList) { + Log.Info($"InterestMode is {interest.InterestMode},HappenDate is {interest.HappenDate},settleDate is {settleDate}"); if (interest.InterestMode == (int)InterestModeEnum.追加预付金 && interest.HappenDate > settleDate) { continue; @@ -223,6 +230,7 @@ namespace YLErp.Modules.SwapModule var dealInterest = dealInterests.FirstOrDefault(n => n.PositionId == interest.id);//当日是否做过互换或平仓 var swapEvents = flowEvents.Where(x => (x.EventType == (int)SwapEventTypeEnum.互换 || x.EventType == (int)SwapEventTypeEnum.平仓) && x.PositionId == interest.id).ToList(); //如果当日有互换/当日有平仓 不再重新生成或更新 + Log.Info($"insterval is {insterval},hasSwap is {hasSwap},hasClose is {hasClose}"); if (insterval != null && !hasSwap) { if (!hasClose)//当日无平仓 @@ -276,9 +284,22 @@ namespace YLErp.Modules.SwapModule DateTime preSettleDate, List flowEvents) { + string settleDateStr = settleDate.ToString("yyyy-MM-dd"); + string preSettleDateStr = preSettleDate.ToString("yyyy-MM-dd"); + Log.Info($"================开始处理{settleDateStr}浮动腿归档=================="); List list = new List(); + Log.Info($"浮动腿归档各项参数如下:\n " + + $"settleDate为:{settleDateStr} \n" + + $"preSettleDate为:{preSettleDateStr} \n " + + $"td为:{td.id} \n " + + $"posiList为:{JsonHelper.Serialize(posiList)} \n " + + $"realPosiList为:{JsonHelper.Serialize(realPosiList)} \n " + + $"eodPositions为:{JsonHelper.Serialize(eodPositions)} \n " + + $"todyEodPositions为:{JsonHelper.Serialize(todyEodPositions)} \n " + + $"flowEvents为:{JsonHelper.Serialize(flowEvents)} \n "); foreach (var posi in posiList) { + Log.Info($"posi为:{JsonHelper.Serialize(posi, false)}"); var eodPosition = eodPositions.Where(x => x.PositionId == posi.id).FirstOrDefault();//上一日日终持仓信息 var tdEodPosition = todyEodPositions.FirstOrDefault(x => x.PositionId == posi.id);//当前结算日日终持仓信息 var unwindEvents = flowEvents.Where(x => x.PositionId == posi.id).ToList();//当前日平仓信息 @@ -296,8 +317,10 @@ namespace YLErp.Modules.SwapModule { eodPosi = UpdateEodPosition(posi, eodPosition, tdEodPosition, td, settleDate, preSettleDate, unwindEvents); } + Log.Info($"eodPosi为:{JsonHelper.Serialize(eodPosi, false)}"); list.Add(eodPosi); } + Log.Info($"================{settleDateStr}浮动腿归档结束=================="); return list; } /// @@ -570,6 +593,7 @@ namespace YLErp.Modules.SwapModule DateTime valueDate, List flowEvents) { + Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}"); if (eodPayPosition == null) { eodPayPosition = new eod_swap_position(); @@ -579,7 +603,7 @@ namespace YLErp.Modules.SwapModule eodPayPosition.PosiMatuirityDate = td.ExerciseDate.Value; } var tradeExtend = td.trade_extend.ExtendObj; - decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负 + decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负 if (marginTypes.Contains(position.InterestMode)) { ratio = -ratio; @@ -655,7 +679,7 @@ namespace YLErp.Modules.SwapModule /// 上一日终框架合约估值 private List SaveAutoEodInterestPosition(eod_swap_position eodPayPosition, eod_swap_position newEodPayPosition, swap_position position, trade td, DateTime valueDate, IntervalModel interval, eod_swap lastEodSwap, decimal posiLongNotional, decimal posiShortNational, decimal grossPrice, decimal orginPv) { - + Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}"); var tradeExtend = td.trade_extend.ExtendObj; decimal oriPosiNotionalValue = posiLongNotional + posiShortNational; decimal posiNotionalValue = oriPosiNotionalValue; @@ -665,7 +689,7 @@ namespace YLErp.Modules.SwapModule posiNotionalValue = lastEodSwap.NotionalValue; } decimal closePercent = 1; - decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负 + decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负 if (marginTypes.Contains(position.InterestMode)) { ratio = -ratio; @@ -723,6 +747,7 @@ namespace YLErp.Modules.SwapModule // newEodPayPosition.TdCloseInterestFee = newEodPayPosition.TdInterestFee; //持仓内容-利息腿-损益统计(本方视角) newEodPayPosition.TdInterestIncome = TdInterestAmount; + Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee},TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}"); newEodPayPosition.InterestIncomeSum = 0; newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee; newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum; @@ -732,7 +757,7 @@ namespace YLErp.Modules.SwapModule //累计已实现 newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio; newEodPayPosition.RealizedInterestFee = eodPayPosition.RealizedInterestFee + newEodPayPosition.TdCloseInterestFee; - newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest; + newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest + newEodPayPosition.RealizedInterestFee; var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, valueDate , seekPreday: true, currencyRateType: position.InterestDirection == (int)SwapDirectionEnum.收取 ? CurrencyRateType.Buy : CurrencyRateType.Sell); newEodPayPosition.TdCurrency = Convert.ToDecimal(currencyRate); @@ -740,6 +765,7 @@ namespace YLErp.Modules.SwapModule { DbContext.eod_swap_position.Add(newEodPayPosition); } + Log.Info($"the last newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}"); return interests; } @@ -758,11 +784,11 @@ namespace YLErp.Modules.SwapModule /// 平仓主信息 private List SaveAutoEodWithCloseInterestPosition(eod_swap_position eodPayPosition, eod_swap_position newEodPayPosition, swap_position position, trade td, DateTime valueDate, IntervalModel interval, decimal posiLongNotional, decimal posiShortNational, List flowEvents, decimal closeNational, bool autoSwap, decimal grossPrice, decimal orginPv) { - + Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}"); var tradeExtend = td.trade_extend.ExtendObj; decimal oriPosiNotionalValue = posiLongNotional + posiShortNational + closeNational; - decimal posiNotionalValue = oriPosiNotionalValue; - decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负 + decimal posiNotionalValue = posiLongNotional + posiShortNational; + decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负 if (marginTypes.Contains(position.InterestMode)) { ratio = -ratio; @@ -837,13 +863,17 @@ namespace YLErp.Modules.SwapModule newEodPayPosition.TdInterestFee = flowEvents.Sum(s => s.InterestFee); newEodPayPosition.TdCloseInterestFee = newEodPayPosition.TdInterestFee; newEodPayPosition.TdCloseInterest = flowEvents.Sum(s => s.InterestClosePnL); + Log.Info($"InterestIncomeSum is {eodPayPosition.InterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" + + $",TdCloseInterest is {newEodPayPosition.TdCloseInterest}"); + Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee}" + + $",TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}"); if (closePercent == 1) { newEodPayPosition.InterestIncomeSum = 0; } else { - newEodPayPosition.InterestIncomeSum = eodPayPosition.InterestIncomeSum + TdInterestAmount - Math.Abs(newEodPayPosition.TdCloseInterest); + newEodPayPosition.InterestIncomeSum = eodPayPosition.InterestIncomeSum + TdInterestAmount - newEodPayPosition.TdCloseInterest; } //持仓内容-利息腿-损益统计(本方视角) newEodPayPosition.TdInterestIncome = TdInterestAmount * (1 - closePercent); @@ -852,13 +882,18 @@ namespace YLErp.Modules.SwapModule //持仓价值 newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum; + Log.Info($"InterestIncomeSum is {eodPayPosition.InterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" + + $",TdCloseInterest is {newEodPayPosition.TdCloseInterest}"); + Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee}" + + $",TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}"); //累计已实现 newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio ; newEodPayPosition.RealizedInterestFee = eodPayPosition.RealizedInterestFee + newEodPayPosition.TdCloseInterestFee; - newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest; + newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest + newEodPayPosition.RealizedInterestFee;; var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, valueDate , seekPreday: true, currencyRateType: position.InterestDirection == (int)SwapDirectionEnum.收取 ? CurrencyRateType.Buy : CurrencyRateType.Sell); newEodPayPosition.TdCurrency = Convert.ToDecimal(currencyRate); + Log.Info($"即将插入数据库的 newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}"); if (newEodPayPosition.id == 0) { DbContext.eod_swap_position.Add(newEodPayPosition); @@ -876,6 +911,7 @@ namespace YLErp.Modules.SwapModule /// 互换交易主干 private void SaveEodInterestPositionCopy(eod_swap_position eodPayPosition, eod_swap_position newEodPayPosition, DateTime valueDate, trade td, swap_position position, eod_swap lastEodSwap, bool needPrice, decimal posiLongNational, decimal posiShortNational, decimal grossPrice, decimal orginPv) { + Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}"); List intervals = position.SwapIntervalList; var tradeExtend = td.trade_extend.ExtendObj; if (eodPayPosition == null) @@ -931,7 +967,7 @@ namespace YLErp.Modules.SwapModule { closePercent = 1; } - decimal ratio = eodPayPosition.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负 + decimal ratio = eodPayPosition.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负 if (marginTypes.Contains(position.InterestMode)) { ratio = -ratio; @@ -963,6 +999,10 @@ namespace YLErp.Modules.SwapModule //持仓内容-利息腿-损益统计(本方视角) newEodPayPosition.TdInterestIncome = TdInterestAmount; newEodPayPosition.TdInterestFee = 0; + Log.Info($"InterestIncomeSum is {eodPayPosition.InterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" + + $",TdCloseInterest is {newEodPayPosition.TdCloseInterest}"); + Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee}" + + $",TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}"); newEodPayPosition.InterestIncomeSum = eodPayPosition.InterestIncomeSum + newEodPayPosition.TdInterestIncome - newEodPayPosition.TdCloseInterest; newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee; newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum; @@ -972,10 +1012,11 @@ namespace YLErp.Modules.SwapModule //累计已实现 newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio; newEodPayPosition.RealizedInterestFee = eodPayPosition.RealizedInterestFee + newEodPayPosition.TdCloseInterestFee; - newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest; + newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest + newEodPayPosition.RealizedInterestFee; var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, valueDate , seekPreday: true, currencyRateType: eodPayPosition.InterestDirection == (int)SwapDirectionEnum.收取 ? CurrencyRateType.Buy : CurrencyRateType.Sell); newEodPayPosition.TdCurrency = Convert.ToDecimal(currencyRate); + Log.Info($"the last newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}"); if (newEodPayPosition.id == 0) { DbContext.eod_swap_position.Add(newEodPayPosition);