From 613fd66b65221d9a788c519aa49330fdc76901e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=90=8D=E9=94=90?= <1565842059@qq.com> Date: Mon, 3 Aug 2026 13:21:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(swap):=20=E8=A7=A3=E5=86=B3=EF=BC=88?= =?UTF-8?q?=E8=A7=82=E5=AF=9F=E6=97=A5=EF=BC=89=E5=88=A9=E7=8E=87=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E7=B2=BE=E5=BA=A6=E9=97=AE=E9=A2=98=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BB=B7=E6=A0=BC=E7=B2=BE=E5=BA=A6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在SwapDealService中对GetFixedRate结果进行精度调整,解决原数据精度误差问题 - 在swapPricePrecisionHelper中添加roundDecimal方法并移除TODO注释 - 新增observationRate相关的精度处理函数,包括roundObservationRate和percent转换函数 - 创建serializeSwapIntervals函数用于处理掉期区间利率精度序列化 - 将consNumberFormat.umpriceP替换为swapPricePrecision.shiftDecimal进行百分比转换 - 使用新的精度处理函数替代原有的toFixed(6)和乘以0.01的操作 --- .../Modules/SwapModule/SwapDealService.cs | 2 +- .../app/swaptrade/swapPricePrecisionHelper.js | 3 +- .../Scripts/app/swaptrade/swapTradeEdit.js | 39 ++++++++++++++----- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 70a5e50e..05d0a372 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -712,7 +712,7 @@ namespace YLErp.Modules.SwapModule } // 获取利率 - decimal rate = GetFixedRate(position, unwindDate); + decimal rate = Math.Round(GetFixedRate(position, unwindDate), InterestCalculationPrecision, MidpointRounding.AwayFromZero); // 做精度调整 原数据有精度误差 decimal floatRate = GetFloatRate(position, preEodPosition, td.StartDate.Value, endDate, interestPeriod, swap, positionClone); // 根据场景计算利息 diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapPricePrecisionHelper.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapPricePrecisionHelper.js index 6ff80ccc..fa37a9da 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapPricePrecisionHelper.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapPricePrecisionHelper.js @@ -42,7 +42,7 @@ var swapPricePrecision = (function (global) { FixingRepoRate: { integerDigits: 2, precision: 4 }, RateYield: {integerDigits: 6, precision: 8}, BondIndex: {integerDigits: 6, precision: 4}, - // TODO: Add InterestYield, BondIndex and GoldFutures after their enum values are confirmed. + }); function normalizeDecimal(value) { @@ -265,6 +265,7 @@ var swapPricePrecision = (function (global) { return rule ? Object.assign({}, options, rule) : Object.assign({}, options); }, format: format, + roundDecimal: roundDecimal, roundForSubmit: function (value, instrumentType, field, storagePrecisionOffset) { const rule = getRule(instrumentType, field); if (value === null || value === undefined || value === '' || !rule) return value; diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js index 7f0e627c..7500c3fd 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js @@ -20,6 +20,18 @@ const inputFormatPosiFeeUnit = Object.freeze({ precision: 6, negative: true, app const inputFormatMarginRate = Object.freeze({ precision: otcformat.trading.marginRateP.precision, append: '%' }); const inputFormatSwapDeliveryPrice = Object.freeze({ precision: 9, negative: true, append: '', percent: false }); const consPosiFeeType = Object.freeze({ Percent: 0, Unit: 1 }); +const observationRatePrecision = 12; +const roundObservationRate = function (value) { + const rounded = swapPricePrecision.roundDecimal(value, observationRatePrecision); + return rounded === null || rounded === '' ? value : rounded; +}; +const observationRateFromPercent = function (value) { + const rate = roundObservationRate(swapPricePrecision.shiftDecimal(value, -2)); + return rate === null || rate === '' ? value : Number(rate); +}; +const observationRateTextFromPercent = function (value) { + return roundObservationRate(swapPricePrecision.shiftDecimal(value, -2)); +}; const swapPosiFeeCalc = Object.freeze({ normalizeFeeType(feeType) { return Number(feeType) === consPosiFeeType.Unit ? consPosiFeeType.Unit : consPosiFeeType.Percent; @@ -712,6 +724,15 @@ const vue = new Vue({ if (this.trade.trade_extend.ExtendObj.InterestCalcMode == "00" || this.trade.trade_extend.ExtendObj.InterestCalcMode == "10") { date = moment(date).add(-1, 'days').format('YYYY-MM-DD'); } + const serializeSwapIntervals = function (position) { + position.SwapIntervalList.forEach(interval => { + const rate = roundObservationRate(interval.Rate); + if (rate !== null && rate !== '') { + interval.Rate = Number(rate); + } + }); + position.InterestSwapInterval = JSON.stringify(position.SwapIntervalList); + }; this.getSwapList.forEach((x,index) => { if ((x.UnderlyingCode == null || x.UnderlyingCode.length == 0) && x.SwapIntervalList.length == 0) { var interval = { @@ -727,7 +748,7 @@ const vue = new Vue({ return false; } x.FloatRateUnderlyingCode = x.FloatRateUnderlyingCode == "--" ? null : x.FloatRateUnderlyingCode; - x.InterestSwapInterval = JSON.stringify(x.SwapIntervalList); + serializeSwapIntervals(x); thisObj.trade.swap_positions.push(x); }); if (errorcount > 0) { @@ -750,7 +771,7 @@ const vue = new Vue({ } x.FloatRateUnderlyingCode = x.FloatRateUnderlyingCode == "--" ? null : x.FloatRateUnderlyingCode; margin = margin + x.InterestPrincipalFix * (x.InterestDirection == 1 ? 1 : -1); - x.InterestSwapInterval = JSON.stringify(x.SwapIntervalList); + serializeSwapIntervals(x); thisObj.trade.swap_positions.push(x); }); if (errorcount > 0) { @@ -1031,14 +1052,14 @@ const vue = new Vue({ date: _date, SettlementDate: m.format("YYYY-MM-DD"), floatRateCode: floatRateCode, - val: _.toString(val) ? parseFloat(consNumberFormat.umpriceP(val)) : "", + val: _.toString(val) ? swapPricePrecision.shiftDecimal(val, 2) : "", itemChecked: itemChecked, disabled: disabled }; } else { obdate = { date: _date, - val: _.toString(val) ? parseFloat(consNumberFormat.umpriceP(val)) : "", + val: _.toString(val) ? swapPricePrecision.shiftDecimal(val, 2) : "", itemChecked: itemChecked, disabled: disabled }; @@ -1099,7 +1120,7 @@ const vue = new Vue({ if (!isNaN(sm.date())) { _settleDate = sm.format("YYYY-MM-DD"); } - var val = parseFloat(consNumberFormat.umpriceP(thisObj.observation.DefaultTitle1Value)); + var val = swapPricePrecision.shiftDecimal(thisObj.observation.DefaultTitle1Value, 2); var itemChecked = true; var disabled = false; if (_date == thisObj.trade.ExerciseDate) { @@ -1135,7 +1156,7 @@ const vue = new Vue({ if (!isNaN(m.date())) { _date = m.format("YYYY-MM-DD"); } - var val = parseFloat(consNumberFormat.umpriceP(thisObj.observation.DefaultTitle1Value)); + var val = swapPricePrecision.shiftDecimal(thisObj.observation.DefaultTitle1Value, 2); var itemChecked = true; var disabled = false; if (_date == thisObj.trade.ExerciseDate) { @@ -1159,7 +1180,7 @@ const vue = new Vue({ var observationStr = ""; if (this.observation.ObservationDataList != null) { this.observation.ObservationDataList.forEach(item => { - observationStr = observationStr + item.date + ", " + item.SettlementDate + ", " + (item.val * 0.01).toFixed(6) + ", " + item.itemChecked + ";\n"; + observationStr = observationStr + item.date + ", " + item.SettlementDate + ", " + observationRateTextFromPercent(item.val) + ", " + item.itemChecked + ";\n"; }); } this.observation.ObservationInterval = observationStr; @@ -1209,7 +1230,7 @@ const vue = new Vue({ date: values[0], SettlementDate: values[1] || "", floatRateCode: floatRateCode, - val: _.toString(val) ? parseFloat(consNumberFormat.umpriceP(val)) : "", + val: _.toString(val) ? swapPricePrecision.shiftDecimal(val, 2) : "", itemChecked: itemChecked, disabled: disabled } @@ -1289,7 +1310,7 @@ const vue = new Vue({ } var observation = { Date: item.date, - Rate: item.val * 0.01, + Rate: observationRateFromPercent(item.val), Settlement: item.itemChecked ? 1 : 0, SettlementDate: item.SettlementDate || null // 结算日期 }