fix(swap): 统一处理【名义本金】数值精度舍入问题
- 在多个位置添加 Math.Round 函数确保金额计算精度 - 新增 NormalizeNotionalValues 方法统一处理 UnwindData 中的名义本金舍入 - 修复交易平仓时 StockEqvNotional 扣减计算的精度问题 - 解决持仓数据 PosiNotionalValue 的精度舍入处理 - 修复前端页面显示格式化问题 - 添加单元测试验证名义本金舍入逻辑正确性
This commit is contained in:
@@ -36,9 +36,17 @@ namespace YLErp.Modules.SwapModule
|
||||
/// 原 private 改 protected virtual,使测试 stub 可整体 override,规避内部 new SwapEventService 连库。</summary>
|
||||
protected virtual long SaveSwapDeal(UnwindData unwindData, int eventType, int clientCashId, string eventResason = "", bool approve = false)
|
||||
{
|
||||
NormalizeNotionalValues(unwindData);
|
||||
return SaveSwapDealInternal(unwindData, eventType, clientCashId, eventResason, approve);
|
||||
}
|
||||
|
||||
private static void NormalizeNotionalValues(UnwindData unwindData)
|
||||
{
|
||||
unwindData.NotionalValue = Math.Round(unwindData.NotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
|
||||
unwindData.PosiNotionalValue = Math.Round(unwindData.PosiNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
|
||||
unwindData.CloseNotionalValue = Math.Round(unwindData.CloseNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
|
||||
/// <summary>保存所有变更(生产: DbContext.SaveChanges;测试: 空操作)</summary>
|
||||
protected virtual void SaveAllChanges()
|
||||
{
|
||||
@@ -1222,6 +1230,7 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
throw new ServiceException("未找到交易信息");
|
||||
}
|
||||
NormalizeNotionalValues(unwindData);
|
||||
//CheckLastEod(unwindData.ValueDate, td.StartDate.Value, unwindData.SwapTradeId); //去掉平仓收盘限制
|
||||
ValidateFrontendPnL(unwindData, isIncome: false); // 只读校验告警,不阻断交易
|
||||
// 前端按"占期初(original)"语义传 ClosePercent(A);后端全链路按"占剩余(remaining)"语义(B)消费。
|
||||
@@ -1252,7 +1261,7 @@ namespace YLErp.Modules.SwapModule
|
||||
td.HasPartialUnWind = 1;
|
||||
}
|
||||
td.UnWindDate = unwindData.UnwindDate;
|
||||
td.StockEqvNotional -= Convert.ToDouble(unwindData.CloseNotionalValue);
|
||||
td.StockEqvNotional = Math.Round(td.StockEqvNotional - Convert.ToDouble(unwindData.CloseNotionalValue), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
|
||||
td.TradeAmount -= Convert.ToDouble(unwindData.CloseQty);
|
||||
SaveAllChanges();
|
||||
cofirm = true;
|
||||
@@ -1568,7 +1577,7 @@ namespace YLErp.Modules.SwapModule
|
||||
td.HasPartialUnWind = 1;
|
||||
}
|
||||
td.UnWindDate = unwindData.UnwindDate;
|
||||
td.StockEqvNotional -= Convert.ToDouble(unwindData.CloseNotionalValue);
|
||||
td.StockEqvNotional = Math.Round(td.StockEqvNotional - Convert.ToDouble(unwindData.CloseNotionalValue), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
|
||||
td.TradeAmount -= Convert.ToDouble(unwindData.CloseQty);
|
||||
td.Notional = td.TradeAmount;
|
||||
td.OptDate = DateTime.Now;
|
||||
@@ -1767,7 +1776,7 @@ namespace YLErp.Modules.SwapModule
|
||||
td.UnWindDate = swapEvent.unwindData.UnwindDate;
|
||||
if (eventType != (int)SwapEventTypeEnum.互换)
|
||||
{
|
||||
td.StockEqvNotional -= Convert.ToDouble(swapEvent.unwindData.CloseNotionalValue);
|
||||
td.StockEqvNotional = Math.Round(td.StockEqvNotional - Convert.ToDouble(swapEvent.unwindData.CloseNotionalValue), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
|
||||
td.TradeAmount -= Convert.ToDouble(swapEvent.unwindData.CloseQty);
|
||||
}
|
||||
|
||||
@@ -1933,7 +1942,7 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
// 平仓时才扣减持仓
|
||||
position.PosiQuantity -= unwindData.CloseQty;
|
||||
position.PosiNotionalValue -= unwindData.CloseNotionalValue;
|
||||
position.PosiNotionalValue = Math.Round(position.PosiNotionalValue - unwindData.CloseNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
|
||||
position.PosiTradingFee -= position.PosiTradingFee * unwindData.ClosePercent;
|
||||
position.PosiTradingFeePending -= position.PosiTradingFeePending * unwindData.ClosePercent;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user