diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 58509c63..cf1b3440 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -162,11 +162,7 @@ namespace YLErp.Modules.SwapModule /// /// 获取用于互换浮动腿盯市的标的价格。 /// - /// 普通债券类收益互换的新录入页面将全价按小数保存,例如页面录入 20% 后 - /// PosiGrossPrice 为 0.2;而历史交易中仍可能存在直接保存为 20 的展示态价格。 - /// 中债估值正常经 EodPriceQueryService 转换后应为小数价格,但手工维护的历史 - /// 行情可能仍以展示态进入该服务,例如 2000 经一次转换后得到 20。若将 20 - /// 与 0.2 直接相减,会把 20% 的价格差误算成 1,980,000 的浮动损益。 + /// 普通债券类收益互换的新录入页面将全价按小数保存,例如页面录入 20% 后 PosiGrossPrice 为 0.2 /// /// 因此仅当交易期初价已经是小数口径、且当前债券价明显仍处于展示态时,再做 /// 一次展示态到存储态转换。期初价本身是历史展示态口径的存量交易保持原价格, @@ -176,10 +172,10 @@ namespace YLErp.Modules.SwapModule { var price = GetUnderlyingPrice(code, settleDate, out vobp); var underlying = GetUnderlyingData(code); - var usesStoragePrice = Math.Abs(posiGrossPrice) < 2m; - var usesDisplayPrice = Math.Abs(price) >= 10m; + // var usesStoragePrice = Math.Abs(posiGrossPrice) < 2m; + // var usesDisplayPrice = Math.Abs(price) >= 10m; - if (underlying?.IsBond() == true && usesStoragePrice && usesDisplayPrice) + if (underlying?.IsBond() == true) { var normalizedPrice = BondPriceConverter.ToStorage(price); Log.Error($"互换债券日终价格按展示态返回,已转换为存储态: UnderlyingCode={code}, ValueDate={settleDate:yyyy-MM-dd}, PosiGrossPrice={posiGrossPrice}, SourcePrice={price}, NormalizedPrice={normalizedPrice}"); diff --git a/YLErpDAL/Modules/SwapModule/SwapTradeService.cs b/YLErpDAL/Modules/SwapModule/SwapTradeService.cs index 9f96a210..d48b339a 100644 --- a/YLErpDAL/Modules/SwapModule/SwapTradeService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapTradeService.cs @@ -381,7 +381,10 @@ namespace YLErp.Modules.SwapModule CountRatio = underlying.CountRatio, ContractSize = Convert.ToDecimal(underlying.ContractSize), PosiNetPrice = flowMerge.TradingAmountFeeAvgAbs, - PosiGrossPrice = Math.Round(flowMerge.TradingAmountAvg, ConsGlobal.SwapDeliveryPriceRound, MidpointRounding.AwayFromZero), + PosiGrossPrice = Math.Round( + flowMerge.TradingAmountAvg, + underlying.IsBond() ? ConsGlobal.PriceRound : ConsGlobal.SwapDeliveryPriceRound, + MidpointRounding.AwayFromZero), PosiNetFeePrice = flowMerge.TradingAmountNetFeeAvg ?? 0, PosiNetNoFeePrice = flowMerge.TradingAmountNetAvg ?? 0, PosiQuantity = flowMerge.TradingQtyAbs, @@ -684,11 +687,7 @@ namespace YLErp.Modules.SwapModule private bool PrepareTrade(trade req, TradeSourceEnum dataSource, underlying_manager um) { bool tradeNumberGenerated = false; - req.InitialMargin = Convert.ToDouble(req.trade_Initial_Margin.MarginValue); - if (req.trade_Initial_Margin.MarginType == 0) - { - req.InitialMargin = req.StockEqvNotional == 0 ? 0 : Convert.ToDouble(req.trade_Initial_Margin.MarginValue) * req.StockEqvNotional; - }; + PrepareInitialMargin(req); var isAddNew = req.id == 0; if (isAddNew) { @@ -731,6 +730,17 @@ namespace YLErp.Modules.SwapModule return tradeNumberGenerated; } + + private static void PrepareInitialMargin(trade req) + { + // 初始预付金依赖最终入库的名义本金,须先统一金额精度,避免两者无法勾稽。 + req.StockEqvNotional = Math.Round(req.StockEqvNotional, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + req.InitialMargin = Convert.ToDouble(req.trade_Initial_Margin.MarginValue); + if (req.trade_Initial_Margin.MarginType == 0) + { + req.InitialMargin = req.StockEqvNotional == 0 ? 0 : Convert.ToDouble(req.trade_Initial_Margin.MarginValue) * req.StockEqvNotional; + } + } //准备单个交易 private trade PrepareSingleTrade(trade req, TradeSourceEnum dataSource, bool isAddNew, underlying_manager um) { @@ -1364,7 +1374,10 @@ namespace YLErp.Modules.SwapModule // position.PosiGrossPrice = string.IsNullOrEmpty(swap.UnderlyingCode) // ? Math.Round(swap.PosiGrossPrice, ConsGlobal.SwapDeliveryPriceRound, MidpointRounding.AwayFromZero) // : ValidateDeliveryPrice(swap.PosiGrossPrice, "期初交割价"); - position.PosiGrossPrice = Math.Round(swap.PosiGrossPrice, ConsGlobal.SwapDeliveryPriceRound, MidpointRounding.AwayFromZero); + var storagePriceRound = ConsGlobal.InstrumentType.IsBond(swap.UnderlyingInstrumentType) + ? ConsGlobal.PriceRound + : ConsGlobal.SwapDeliveryPriceRound; + position.PosiGrossPrice = Math.Round(swap.PosiGrossPrice, storagePriceRound, MidpointRounding.AwayFromZero); position.PosiNetPrice = swap.PosiQuantity == 0 ? 0 : (position.PosiGrossPrice + (position.PosiTradingFeePending / swap.PosiQuantity) * ratio); position.PosiNetPrice = Math.Round(position.PosiNetPrice, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); position.PosiNetNoFeePrice = swap.PosiNetNoFeePrice;