From 6708878d6aea311c06fbe8fa5ef2f6ee26a1c969 Mon Sep 17 00:00:00 2001 From: hjhan Date: Mon, 13 Apr 2026 14:05:15 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(swap-trade):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=94=B6=E7=9B=8A=E4=BA=92=E6=8D=A2=E4=BA=A4=E6=98=93=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=20-=20=E5=AE=9E=E7=8E=B0=E4=BA=86=E6=94=B6=E5=85=A5?= =?UTF-8?q?=E4=BA=92=E6=8D=A2=E4=BA=A4=E6=98=93=E7=9A=84=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E5=92=8C=E4=BA=A4=E4=BA=92=E9=80=BB=E8=BE=91?= =?UTF-8?q?=20-=20=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=B9=B3=E4=BB=93=E6=97=A5?= =?UTF-8?q?=E6=9C=9F=E3=80=81=E6=A0=87=E7=9A=84=E4=BB=B7=E6=A0=BC=E3=80=81?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E8=B4=B9=E7=94=A8=E7=AD=89=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=20-=20=E9=9B=86=E6=88=90=E4=BA=86?= =?UTF-8?q?=E4=BB=B7=E6=A0=BC=E6=A0=BC=E5=BC=8F=E5=8C=96=E5=92=8C=E6=95=B0?= =?UTF-8?q?=E5=80=BC=E7=B2=BE=E5=BA=A6=E6=8E=A7=E5=88=B6=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20-=20=E5=AE=9E=E7=8E=B0=E4=BA=86=E6=B5=AE=E5=8A=A8=E7=AB=AF?= =?UTF-8?q?=E5=B9=B3=E4=BB=93=E7=9B=88=E4=BA=8F=E8=AE=A1=E7=AE=97=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20-=20=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=88=A9=E6=81=AF?= =?UTF-8?q?=E7=AB=AF=E4=BF=A1=E6=81=AF=E8=8E=B7=E5=8F=96=E5=92=8C=E5=B9=B3?= =?UTF-8?q?=E4=BB=93=E9=87=91=E9=A2=9D=E8=AE=A1=E7=AE=97=20-=20=E9=9B=86?= =?UTF-8?q?=E6=88=90=E4=BA=86=E5=AE=A1=E6=89=B9=E6=B5=81=E7=A8=8B=E5=92=8C?= =?UTF-8?q?=E5=A4=8D=E6=A0=B8=E6=9C=BA=E5=88=B6=20-=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86=E5=90=8E=E7=AB=AF=E6=9C=8D=E5=8A=A1=E5=B1=82=E7=9A=84?= =?UTF-8?q?=E5=B9=B3=E4=BB=93=E5=88=9D=E5=A7=8B=E5=8C=96=E5=92=8C=E5=88=A9?= =?UTF-8?q?=E6=81=AF=E8=AE=A1=E7=AE=97=E5=8A=9F=E8=83=BD=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=BA=86=E5=A4=9A=E7=A9=BA=E7=BB=84=E5=90=88=E5=B9=B3?= =?UTF-8?q?=E4=BB=93=E5=92=8C=E6=94=B6=E7=9B=8A=E4=BA=92=E6=8D=A2=E7=9A=84?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91=20-=20=E9=9B=86=E6=88=90?= =?UTF-8?q?=E4=BA=86=E5=BA=95=E5=B1=82=E6=95=B0=E6=8D=AE=E5=BA=93=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E5=92=8C=E6=9C=8D=E5=8A=A1=E7=B1=BB=20-=20=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E4=BA=86=E4=BB=B7=E6=A0=BC=E7=BC=93=E5=AD=98=E5=92=8C?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=AA=8C=E8=AF=81=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Modules/SwapModule/SwapDealService.cs | 57 ++++++++++++------- .../Scripts/app/swaptrade/incomeSwapTrade.js | 6 +- .../Scripts/app/swaptrade/swapLongShort.js | 3 +- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 80d0f28f..d29f4352 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -181,8 +181,8 @@ namespace YLErp.Modules.SwapModule unwindData.StartDate = preDealDate.Value; } unwindData.ValueDate = dealDate; - unwindData.UnwindDate = unwindData.UnwindDate; - unwindData.PayDate = QdpCalendarHelper.GetNonHoliday(unwindData.UnwindDate.Value.AddDays(td.trade_extend.ExtendObj.SettlementRules)); + unwindData.UnwindDate = dealDate; + unwindData.PayDate = QdpCalendarHelper.GetNonHoliday(dealDate.AddDays(td.trade_extend.ExtendObj.SettlementRules)); unwindData.SwapTradeId = tradeId; unwindData.NotionalValue = Convert.ToDecimal(td.OriginalStockEqvNotional ?? 0); unwindData.NotionalQty = positions.Sum(s => s.PosiQuantity); @@ -610,17 +610,17 @@ namespace YLErp.Modules.SwapModule DateTime lastSwapDate = preEodPosition.ValueDate; decimal interestProfitSum = preEodPosition.InterestProfitSum; var TdInterestPrincipal = preEodPosition.TdInterestPrincipal; - decimal interest = 0; - decimal tdinterest = 0; + decimal interest = interestProfitSum * closePercent; + decimal tdinterest = interestProfitSum * closePercent; int interestPeriod = position.interest_rest_days ?? 1; decimal dynomicPrincipal = principal; decimal tdDynomicPrincipal = posiPrincipal; - var calcDays = (endDate - tradeDate).Days; + var calcDays = (endDate - lastSwapDate).Days; double floatRate = Convert.ToDouble(floateRate); for (int i = 0; i <= calcDays; i++) { - var rateDate = tradeDate.AddDays(i); - if (rateDate > lastSwapDate || endDate == tradeDate) + var rateDate = lastSwapDate.AddDays(i); + if (rateDate > lastSwapDate || endDate == lastSwapDate) { if (i % interestPeriod == 0) { @@ -663,11 +663,6 @@ namespace YLErp.Modules.SwapModule tdinterest += tdinterest1; } - else if (lastSwapDate >= rateDate) - { - interest = interestProfitSum * closePercent; - tdinterest = interestProfitSum * closePercent; - } } InterestAmount = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); @@ -1150,8 +1145,8 @@ namespace YLErp.Modules.SwapModule }); } - unwindData.SwapCloseAmount = decimal.Parse(unwindData.SwapCloseAmount.ToString("0.00")); - unwindData.SwapRealizedPnL = unwindData.SwapCloseAmount; + unwindData.SwapCloseAmount = Math.Round(unwindData.SwapCloseAmount, 2, MidpointRounding.AwayFromZero); + unwindData.SwapRealizedPnL = Math.Round(unwindData.SwapRealizedPnL, 2, MidpointRounding.AwayFromZero); } /// /// 多空组合平仓 @@ -1188,7 +1183,7 @@ namespace YLErp.Modules.SwapModule catch (Exception ex) { trans.Rollback(); - throw ex; + throw; } finally { @@ -1214,12 +1209,20 @@ namespace YLErp.Modules.SwapModule { int clientCashId = AddClientCashInCashOut(td, Convert.ToDouble(unwindData.SwapCloseAmount), ClientCashInCashOut.系统操作_互换, unwindData.ValueDate); SaveSwapDeal(unwindData, (int)SwapEventTypeEnum.互换, clientCashId, "系统操作_互换"); + td.UnWindDate = unwindData.UnwindDate; + if (td.ExerciseDate <= unwindData.ValueDate) + { + td.Notional = 0; + td.StockEqvNotional = 0; + td.TradeStatus = "已到期"; + } + DbContext.SaveChanges(); trans.Commit(); } catch (Exception ex) { trans.Rollback(); - throw ex; + throw; } finally { @@ -1267,7 +1270,7 @@ namespace YLErp.Modules.SwapModule catch (Exception ex) { trans.Rollback(); - throw ex; + throw; } finally { @@ -1345,7 +1348,7 @@ namespace YLErp.Modules.SwapModule catch (Exception ex) { trans.Rollback(); - throw ex; + throw; } finally { @@ -1412,10 +1415,20 @@ namespace YLErp.Modules.SwapModule { if (!string.IsNullOrEmpty(position.UnderlyingCode)) { - position.PosiQuantity -= unwindData.CloseQty; - position.PosiNotionalValue = unwindData.PosiNotionalValue - unwindData.CloseNotionalValue; - position.PosiTradingFee -= position.PosiTradingFee * unwindData.ClosePercent; - position.PosiTradingFeePending -= position.PosiTradingFeePending * unwindData.ClosePercent; + // 收益结算(互换)不改变持仓数量和名义本金,只更新费用 + if (eventType == (int)SwapEventTypeEnum.互换) + { + position.PosiTradingFee -= position.PosiTradingFee * unwindData.ClosePercent; + position.PosiTradingFeePending -= position.PosiTradingFeePending * unwindData.ClosePercent; + } + else + { + // 平仓时才扣减持仓 + position.PosiQuantity -= unwindData.CloseQty; + position.PosiNotionalValue -= unwindData.CloseNotionalValue; + position.PosiTradingFee -= position.PosiTradingFee * unwindData.ClosePercent; + position.PosiTradingFeePending -= position.PosiTradingFeePending * unwindData.ClosePercent; + } } else { diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/incomeSwapTrade.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/incomeSwapTrade.js index d623e349..ed510f43 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/incomeSwapTrade.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/incomeSwapTrade.js @@ -144,10 +144,10 @@ const vue = new Vue({ thisObj.deal.SwapMarginAmount = 0; thisObj.floatPosition.TradingAmount = parseFloat(thisObj.floatPosition.TradingAmountAvg) * parseFloat(thisObj.deal.CloseNotionalValue) * 0.01; thisObj.floatPosition.CloseFee = TradingFee; - if (thisObj.deal.PositionQty == 0) { - thisObj.floatPosition.TradingAmountFeeAvg = 0; - } else { + if (thisObj.deal.CloseQty > 0) { thisObj.floatPosition.TradingAmountFeeAvg = parseFloat(thisObj.floatPosition.TradingAmountAvg) * 0.01 + (TradingFee / thisObj.deal.CloseQty) * floatRatio; + } else { + thisObj.floatPosition.TradingAmountFeeAvg = parseFloat(thisObj.floatPosition.TradingAmountAvg) * 0.01; } this.interestList.forEach(x => { //let interestRatio = x.InterestDirection == 1 ? 1 : -1; diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapLongShort.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapLongShort.js index 920fec79..0cbe805b 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapLongShort.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapLongShort.js @@ -113,7 +113,8 @@ const vue = new Vue({ } let reqObj = _.cloneDeep(thisObj.deal); let marginCloneList = _.cloneDeep(thisObj.marginList); - reqObj.FlowEvents = thisObj.interestList; + + reqObj.FlowEvents = _.cloneDeep(thisObj.interestList); marginCloneList.forEach((item) => { reqObj.FlowEvents.push(item); }) From 80a3a7a3ba32d42f269896ef50054943d8f69472 Mon Sep 17 00:00:00 2001 From: hjhan Date: Mon, 13 Apr 2026 17:26:57 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(swaptrade):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BB=B7=E6=A0=BC=E8=AE=A1=E7=AE=97=E7=9A=84=E6=8B=AC=E5=8F=B7?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20-=20=E4=B8=BA=20PosiGrossPrice=20=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E6=B7=BB=E5=8A=A0=E6=AD=A3=E7=A1=AE=E7=9A=84=E6=8B=AC?= =?UTF-8?q?=E5=8F=B7=E5=8C=85=E8=A3=B9=20-=20=E4=B8=BA=20TradingAmountNetA?= =?UTF-8?q?vg=20=E8=AE=A1=E7=AE=97=E6=B7=BB=E5=8A=A0=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E7=9A=84=E6=8B=AC=E5=8F=B7=E5=8C=85=E8=A3=B9=20-=20=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E6=95=B0=E5=80=BC=E8=AE=A1=E7=AE=97=E4=BC=98=E5=85=88?= =?UTF-8?q?=E7=BA=A7=E6=AD=A3=E7=A1=AE=EF=BC=8C=E9=81=BF=E5=85=8D=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpWeb/Views/SwapTrade2/TradeView.cshtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/YLErpWeb/Views/SwapTrade2/TradeView.cshtml b/YLErpWeb/Views/SwapTrade2/TradeView.cshtml index 6e68cac3..e16fd470 100644 --- a/YLErpWeb/Views/SwapTrade2/TradeView.cshtml +++ b/YLErpWeb/Views/SwapTrade2/TradeView.cshtml @@ -940,8 +940,8 @@ @((SwapDirectionEnum)closeFloat.PayDirection) @(closeFloat.PositionType == (int)PositionTypeFlag.Long ? "多头" : "空头") @closeFloat.UnderlyingCode - @(closeFloat.PosiGrossPrice * multiplier).OtcFormat(OtcFormatFlag.umpriceP) - @((closeFloat.TradingAmountNetAvg ?? 0) * multiplier).OtcFormat(OtcFormatFlag.umpriceP) + @((closeFloat.PosiGrossPrice * multiplier).OtcFormat(OtcFormatFlag.umpriceP)) + @(((closeFloat.TradingAmountNetAvg ?? 0) * multiplier).OtcFormat(OtcFormatFlag.umpriceP)) @((closeFloat.TradingAmountAvg * multiplier).OtcFormat(OtcFormatFlag.umpriceP)) @((closeFloat.PositionQty??0).OtcFormat(OtcFormatFlag.StockEqvNotional)) @(closeFloat.TradingFee.OtcFormat(OtcFormatFlag.StockEqvNotional))