using YLErp.Helpers; using YLErp.Modules.SwapModule.Margin; namespace YLErp.Modules.SwapModule; /// /// 平仓数据(UnwindData)规范化——纯 static,无 this 依赖。 /// 从 SwapDealService 提取,零行为变更。 /// internal static class UnwindNormalizer { internal 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); } internal static bool NormalizeFullCloseRequest(UnwindData unwindData) { if (unwindData.CloseMethod != (int)CloseMethodEnum.全部平仓 && unwindData.ClosePercent < 1 && !(unwindData.PositionQty > 0 && unwindData.CloseQty >= unwindData.PositionQty) && !(unwindData.PosiNotionalValue > 0 && unwindData.CloseNotionalValue >= unwindData.PosiNotionalValue)) { return false; } var closeQty = unwindData.CloseQty; var closeNotionalValue = unwindData.CloseNotionalValue; unwindData.ClosePercent = 1; if (unwindData.PositionQty > 0) unwindData.CloseQty = unwindData.PositionQty; if (unwindData.PosiNotionalValue > 0) unwindData.CloseNotionalValue = unwindData.PosiNotionalValue; return closeQty != unwindData.CloseQty || closeNotionalValue != unwindData.CloseNotionalValue; } internal static void RecalculateNormalizedUnwindAmounts(UnwindData unwindData) { var floatLeg = unwindData.FlowEvents.FirstOrDefault(x => !string.IsNullOrEmpty(x.UnderlyingCode)); if (floatLeg == null || floatLeg.PosiGrossPrice == 0) return; var input = new UnwindInput { Multiplier = ConsGlobal.InstrumentType.IsBond(floatLeg.UnderlyingInstrumentType) ? 100 : 1, PosiGrossPrice = floatLeg.PosiGrossPrice, TradingAmountAvg = floatLeg.TradingAmountAvg, CloseQty = unwindData.CloseQty, PositionQty = unwindData.PositionQty, ContractSize = floatLeg.ContractSize, CloseNotionalValue = unwindData.CloseNotionalValue, PayDirection = floatLeg.PayDirection, PositionType = floatLeg.PositionType, TradingFee = floatLeg.TradingFee.ToString(), TradingFeePending = floatLeg.TradingFeePending.ToString(), DividendIn = floatLeg.DividendIn.ToString() }; foreach (var leg in unwindData.FlowEvents.Where(x => string.IsNullOrEmpty(x.UnderlyingCode))) { var target = MarginModes.Contains(leg.InterestMode) ? input.MarginLegs : input.InterestLegs; target.Add(new LegInput { InterestClosePnL = leg.InterestClosePnL }); } var result = FrontendCalcReference.CalcUnwind(input); floatLeg.MarkClosePnl = result.MarkClosePnl; unwindData.SwapCloseAmount = result.SwapCloseAmount; unwindData.SwapRealizedPnL = result.SwapRealizedPnL; unwindData.SwapMarginRebatePnl = result.SwapMarginRebatePnl; } internal static bool IsFullCloseAfterDeduction(UnwindData unwindData, double remainingNotional, double remainingQuantity) { return unwindData.ClosePercent == 1 || (remainingNotional == 0 && remainingQuantity == 0); } /// /// 手工平仓、手工互换及收益结算的利息事件按金额两位落库。 /// 自动平仓保留原有计算与落库口径,不适用本阶段的手工结算规则。 /// internal static bool NormalizeSettledInterestAmounts(IEnumerable flowEvents, int eventType, string eventReason) { if ((eventType != (int)SwapEventTypeEnum.平仓 && eventType != (int)SwapEventTypeEnum.互换) || eventReason == "系统操作_自动平仓") { return false; } foreach (var flowEvent in flowEvents.Where(x => string.IsNullOrEmpty(x.UnderlyingCode))) { flowEvent.InterestPrincipal = Math.Round(flowEvent.InterestPrincipal, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); flowEvent.InterestAmount = Math.Round(flowEvent.InterestAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); flowEvent.TdInterestAmount = Math.Round(flowEvent.TdInterestAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); flowEvent.InterestClosePnL = Math.Round(flowEvent.InterestClosePnL, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); flowEvent.InterestFee = Math.Round(flowEvent.InterestFee, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); } return true; } internal static void NormalizeEventUnwindDate(UnwindData unwindData) { unwindData.UnwindDate = unwindData.ValueDate; } }