fix(swap): 解决(观察日)利率计算精度问题并优化价格精度处理
- 在SwapDealService中对GetFixedRate结果进行精度调整,解决原数据精度误差问题 - 在swapPricePrecisionHelper中添加roundDecimal方法并移除TODO注释 - 新增observationRate相关的精度处理函数,包括roundObservationRate和percent转换函数 - 创建serializeSwapIntervals函数用于处理掉期区间利率精度序列化 - 将consNumberFormat.umpriceP替换为swapPricePrecision.shiftDecimal进行百分比转换 - 使用新的精度处理函数替代原有的toFixed(6)和乘以0.01的操作
This commit is contained in:
@@ -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);
|
||||
|
||||
// 根据场景计算利息
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 // 结算日期
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user