refactor(swap): Phase1 提取UnwindNormalizer+TradingFeeCalc出SwapDealService

SwapDealService的10个private static纯逻辑方法搬到两个新文件:
- UnwindNormalizer.cs: NormalizeNotionalValues/FullCloseRequest/Recalculate/IsFullClose/SettledInterestAmounts/EventUnwindDate (6个)
- TradingFeeCalc.cs: CalcInitTradingFee/CalcInitTradingFeePending (2个)

SwapDealService内21处调用点加类名前缀, 反射测试改为直接调用(public)
SwapModule零回归(7基线/510通过)
This commit is contained in:
hjhan
2026-08-12 16:26:12 +08:00
parent 89eae7555f
commit b9362ea700
4 changed files with 170 additions and 165 deletions
@@ -1,4 +1,3 @@
using System.Reflection;
using YLErp.DBModels;
namespace YLErp.Modules.SwapModule
@@ -7,26 +6,10 @@ namespace YLErp.Modules.SwapModule
public class InitUnwindTradingFeeTest
{
private static decimal InvokeCalcInitTradingFee(swap_position position, UnwindData unwindData)
{
var method = typeof(SwapDealService).GetMethod(
"CalcInitTradingFee",
BindingFlags.NonPublic | BindingFlags.Static);
Assert.IsNotNull(method, "未找到 CalcInitTradingFee 私有静态方法");
return (decimal)method.Invoke(null, new object[] { position, unwindData });
}
=> TradingFeeCalc.CalcInitTradingFee(position, unwindData);
private static decimal InvokeCalcInitTradingFeePending(swap_position oriPosition, swap_position position, UnwindData unwindData)
{
var method = typeof(SwapDealService).GetMethod(
"CalcInitTradingFeePending",
BindingFlags.NonPublic | BindingFlags.Static);
Assert.IsNotNull(method, "CalcInitTradingFeePending was not found");
return (decimal)method.Invoke(null, new object[] { oriPosition, position, unwindData });
}
=> TradingFeeCalc.CalcInitTradingFeePending(oriPosition, position, unwindData);
[TestMethod]
public void _按平仓名义本金计算并四舍五入到两位()
+21 -146
View File
@@ -46,106 +46,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);
UnwindNormalizer.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);
}
private 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;
}
private 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;
}
private static bool IsFullCloseAfterDeduction(UnwindData unwindData, double remainingNotional, double remainingQuantity)
{
return unwindData.ClosePercent == 1 || (remainingNotional == 0 && remainingQuantity == 0);
}
// 待实现利息会进入 decimal(30,12) 日终快照;精度常量统一引用 SwapInterest.FundingLegPrecision,消除重复定义。
private const int InterestCalculationPrecision = SwapInterest.FundingLegPrecision;
/// <summary>
/// 手工平仓、手工互换及收益结算的利息事件按金额两位落库。
/// 自动平仓保留原有计算与落库口径,不适用本阶段的手工结算规则。
/// </summary>
private static bool NormalizeSettledInterestAmounts(IEnumerable<swap_flow_event> 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;
}
// 客户现金在 SaveSwapDeal 之前创建,手工结算必须先收敛流水并重算汇总金额。
private void NormalizeManualSettlementAmounts(UnwindData unwindData, int eventType, string eventReason)
{
if (!NormalizeSettledInterestAmounts(unwindData.FlowEvents, eventType, eventReason))
if (!UnwindNormalizer.NormalizeSettledInterestAmounts(unwindData.FlowEvents, eventType, eventReason))
{
return;
}
@@ -372,7 +283,7 @@ namespace YLErp.Modules.SwapModule
floatEvent.UnderlyingInstrumentType = position.UnderlyingInstrumentType;
floatEvent.CloseFee = 0;
floatEvent.BeforeCloseFee = oriPosition.PosiTradingFeePending;
floatEvent.TradingFee = CalcInitTradingFee(oriPosition, unwindData);
floatEvent.TradingFee = TradingFeeCalc.CalcInitTradingFee(oriPosition, unwindData);
floatEvent.PosiTradingFeeUnit = oriPosition?.PosiTradingFeeUnit ?? 0;
floatEvent.PosiFeeType = oriPosition?.PosiFeeType ?? 0;
floatEvent.MarkClosePnl = 0;
@@ -387,7 +298,7 @@ namespace YLErp.Modules.SwapModule
floatEvent.ContractSize = position.ContractSize;
floatEvent.TradingAmount = floatEvent.Quantity * floatEvent.ContractSize;
var ratio = -DirectionRatio.ReceivePay(position.PosiDirection);
floatEvent.TradingFeePending = CalcInitTradingFeePending(oriPosition, position, unwindData);
floatEvent.TradingFeePending = TradingFeeCalc.CalcInitTradingFeePending(oriPosition, position, unwindData);
floatEvent.DataState = (int)SwapFlowDateStateEnum.;
floatEvent.InterestMode = position.InterestMode;
floatEvent.ClientId = td.ClientId;
@@ -397,37 +308,6 @@ namespace YLErp.Modules.SwapModule
}
return unwindData;
}
private static decimal CalcInitTradingFee(swap_position oriPosition, UnwindData unwindData)
{
if (oriPosition == null || unwindData == null)
{
return 0;
}
if (oriPosition.PosiFeeType == 1)
{
return Math.Round(oriPosition.PosiTradingFeeUnit * unwindData.CloseQty, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
}
return Math.Round(oriPosition.PosiTradingFeeUnit / 100m * unwindData.CloseNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
}
private static decimal CalcInitTradingFeePending(swap_position oriPosition, swap_position position, UnwindData unwindData)
{
if (oriPosition == null || unwindData == null || oriPosition.PosiTradingFeeUnit == 0)
{
return position?.PosiTradingFeePending ?? 0;
}
var closeBase = oriPosition.PosiFeeType == 1 ? unwindData.CloseQty : unwindData.CloseNotionalValue;
var originalBase = oriPosition.PosiFeeType == 1 ? unwindData.NotionalQty : unwindData.NotionalValue;
if (originalBase <= 0)
{
return position?.PosiTradingFeePending ?? 0;
}
return Math.Round(oriPosition.PosiTradingFeePending * closeBase / originalBase, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
}
/// <summary>
/// 校验上日是否收盘
/// </summary>
@@ -1573,16 +1453,16 @@ namespace YLErp.Modules.SwapModule
{
throw new ServiceException("未找到交易信息");
}
NormalizeEventUnwindDate(unwindData);
NormalizeNotionalValues(unwindData);
UnwindNormalizer.NormalizeEventUnwindDate(unwindData);
UnwindNormalizer.NormalizeNotionalValues(unwindData);
NormalizeManualSettlementAmounts(unwindData, (int)SwapEventTypeEnum., "系统操作_平仓");
//CheckLastEod(unwindData.ValueDate, td.StartDate.Value, unwindData.SwapTradeId); //去掉平仓收盘限制
// 前端按"占期初(original)"语义传 ClosePercent(A);后端全链路按"占剩余(remaining)"语义(B)消费。
// 入口统一转换为 B,落库展示用的 A 由 SaveSwapDealInternal 还原。
unwindData.ClosePercent = ToRemainingClosePercent(unwindData.ClosePercent, unwindData.NotionalValue, unwindData.PosiNotionalValue);
if (NormalizeFullCloseRequest(unwindData))
if (UnwindNormalizer.NormalizeFullCloseRequest(unwindData))
{
RecalculateNormalizedUnwindAmounts(unwindData);
UnwindNormalizer.RecalculateNormalizedUnwindAmounts(unwindData);
}
ValidateFrontendPnL(unwindData, isIncome: false); // 只读校验告警,不阻断交易
bool cofirm = false;
@@ -1595,7 +1475,7 @@ namespace YLErp.Modules.SwapModule
var eventId = SaveSwapDeal(unwindData, (int)SwapEventTypeEnum., clientCashId, "系统操作_平仓");
var remainingStockEqvNotional = Math.Round(td.StockEqvNotional - Convert.ToDouble(unwindData.CloseNotionalValue), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
var remainingTradeAmount = td.TradeAmount - Convert.ToDouble(unwindData.CloseQty);
var isFullClose = IsFullCloseAfterDeduction(unwindData, remainingStockEqvNotional, remainingTradeAmount);
var isFullClose = UnwindNormalizer.IsFullCloseAfterDeduction(unwindData, remainingStockEqvNotional, remainingTradeAmount);
if (isFullClose)
{
td.TradeStatus = "已平仓";
@@ -1968,7 +1848,7 @@ namespace YLErp.Modules.SwapModule
{
throw new ServiceException("未找到交易信息");
}
NormalizeEventUnwindDate(unwindData);
UnwindNormalizer.NormalizeEventUnwindDate(unwindData);
unwindData.SwapRealizedPnL = unwindData.SwapCloseAmount;
NormalizeManualSettlementAmounts(unwindData, (int)SwapEventTypeEnum., "系统操作_平仓");
var trans = DbContext.Database.BeginTransaction();
@@ -2006,7 +1886,7 @@ namespace YLErp.Modules.SwapModule
{
throw new ServiceException("未找到交易信息");
}
NormalizeEventUnwindDate(unwindData);
UnwindNormalizer.NormalizeEventUnwindDate(unwindData);
unwindData.SwapRealizedPnL = unwindData.SwapCloseAmount;
NormalizeManualSettlementAmounts(unwindData, (int)SwapEventTypeEnum., "系统操作_互换");
var trans = DbContext.Database.BeginTransaction();
@@ -2046,7 +1926,7 @@ namespace YLErp.Modules.SwapModule
{
throw new ServiceException("未找到交易信息");
}
NormalizeEventUnwindDate(unwindData);
UnwindNormalizer.NormalizeEventUnwindDate(unwindData);
ValidateIncomeValueDate(unwindData, td);
NormalizeManualSettlementAmounts(unwindData, (int)SwapEventTypeEnum., "系统操作_互换");
//CheckLastEod(unwindData.ValueDate, td.StartDate.Value, unwindData.SwapTradeId); //去掉平仓收盘限制
@@ -2084,8 +1964,8 @@ namespace YLErp.Modules.SwapModule
throw new Exception("该笔交易状态为平仓待复核,未找到相关记录,请检查该笔交易是否有效");
}
swapEvent.unwindData = JsonConvert.DeserializeObject<UnwindData>(swapEvent.EventData);
NormalizeEventUnwindDate(swapEvent.unwindData);
NormalizeNotionalValues(swapEvent.unwindData);
UnwindNormalizer.NormalizeEventUnwindDate(swapEvent.unwindData);
UnwindNormalizer.NormalizeNotionalValues(swapEvent.unwindData);
// Stored events keep display ratio A; approval calculations consume remaining ratio B.
swapEvent.unwindData.ClosePercent = ToRemainingClosePercent(
swapEvent.unwindData.ClosePercent,
@@ -2100,9 +1980,9 @@ namespace YLErp.Modules.SwapModule
swapEvent.unwindData.FlowEvents = flowList;
if (eventType == (int)SwapEventTypeEnum.)
{
if (NormalizeFullCloseRequest(swapEvent.unwindData))
if (UnwindNormalizer.NormalizeFullCloseRequest(swapEvent.unwindData))
{
RecalculateNormalizedUnwindAmounts(swapEvent.unwindData);
UnwindNormalizer.RecalculateNormalizedUnwindAmounts(swapEvent.unwindData);
}
}
if (eventType == (int)SwapEventTypeEnum.)
@@ -2131,7 +2011,7 @@ namespace YLErp.Modules.SwapModule
{
var remainingStockEqvNotional = Math.Round(td.StockEqvNotional - Convert.ToDouble(swapEvent.unwindData.CloseNotionalValue), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
var remainingTradeAmount = td.TradeAmount - Convert.ToDouble(swapEvent.unwindData.CloseQty);
var isFullClose = IsFullCloseAfterDeduction(swapEvent.unwindData, remainingStockEqvNotional, remainingTradeAmount);
var isFullClose = UnwindNormalizer.IsFullCloseAfterDeduction(swapEvent.unwindData, remainingStockEqvNotional, remainingTradeAmount);
if (isFullClose)
{
td.TradeStatus = "已平仓";
@@ -2176,7 +2056,7 @@ namespace YLErp.Modules.SwapModule
{
throw new ServiceException("未找到交易信息");
}
NormalizeEventUnwindDate(unwindData);
UnwindNormalizer.NormalizeEventUnwindDate(unwindData);
if (eventType == (int)SwapEventTypeEnum.)
{
ValidateIncomeValueDate(unwindData, td);
@@ -2190,9 +2070,9 @@ namespace YLErp.Modules.SwapModule
unwindData.ClosePercent = ToRemainingClosePercent(unwindData.ClosePercent, unwindData.NotionalValue, unwindData.PosiNotionalValue);
if (eventType == (int)SwapEventTypeEnum.)
{
if (NormalizeFullCloseRequest(unwindData))
if (UnwindNormalizer.NormalizeFullCloseRequest(unwindData))
{
RecalculateNormalizedUnwindAmounts(unwindData);
UnwindNormalizer.RecalculateNormalizedUnwindAmounts(unwindData);
}
}
string action = eventType == (int)SwapEventTypeEnum. ? ClientCashInCashOut._互换 : ClientCashInCashOut._平仓费;
@@ -2225,11 +2105,6 @@ namespace YLErp.Modules.SwapModule
}
}
private static void NormalizeEventUnwindDate(UnwindData unwindData)
{
unwindData.UnwindDate = unwindData.ValueDate;
}
/// <summary>
/// 保存平仓/互换事件
/// </summary>
@@ -2243,7 +2118,7 @@ namespace YLErp.Modules.SwapModule
throw new ServiceException("未找到交易信息");
}
var flowList = new List<swap_flow_event>(unwindData.FlowEvents);
NormalizeSettledInterestAmounts(flowList, eventType, eventResason);
UnwindNormalizer.NormalizeSettledInterestAmounts(flowList, eventType, eventResason);
unwindData.FlowEvents.Clear();
// 落库展示用"占期初(original)"语义(A);计算链(费用递减/全平判定)用"占剩余(remaining)"语义(B)。
// 序列化前把 ClosePercent 还原为 A,序列化后立即还原回 B 供后续使用。
@@ -0,0 +1,43 @@
using YLErp.DBModels;
using YLErp.DBModels.Consts;
namespace YLErp.Modules.SwapModule;
/// <summary>
/// 平仓手续费计算——纯 static,无 this 依赖。
/// 从 SwapDealService 提取,零行为变更。
/// </summary>
public static class TradingFeeCalc
{
public static decimal CalcInitTradingFee(swap_position oriPosition, UnwindData unwindData)
{
if (oriPosition == null || unwindData == null)
{
return 0;
}
if (oriPosition.PosiFeeType == 1)
{
return Math.Round(oriPosition.PosiTradingFeeUnit * unwindData.CloseQty, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
}
return Math.Round(oriPosition.PosiTradingFeeUnit / 100m * unwindData.CloseNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
}
public static decimal CalcInitTradingFeePending(swap_position oriPosition, swap_position position, UnwindData unwindData)
{
if (oriPosition == null || unwindData == null || oriPosition.PosiTradingFeeUnit == 0)
{
return position?.PosiTradingFeePending ?? 0;
}
var closeBase = oriPosition.PosiFeeType == 1 ? unwindData.CloseQty : unwindData.CloseNotionalValue;
var originalBase = oriPosition.PosiFeeType == 1 ? unwindData.NotionalQty : unwindData.NotionalValue;
if (originalBase <= 0)
{
return position?.PosiTradingFeePending ?? 0;
}
return Math.Round(oriPosition.PosiTradingFeePending * closeBase / originalBase, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
}
}
@@ -0,0 +1,104 @@
using YLErp.Helpers;
using YLErp.Modules.SwapModule.Margin;
namespace YLErp.Modules.SwapModule;
/// <summary>
/// 平仓数据(UnwindData)规范化——纯 static,无 this 依赖。
/// 从 SwapDealService 提取,零行为变更。
/// </summary>
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);
}
/// <summary>
/// 手工平仓、手工互换及收益结算的利息事件按金额两位落库。
/// 自动平仓保留原有计算与落库口径,不适用本阶段的手工结算规则。
/// </summary>
internal static bool NormalizeSettledInterestAmounts(IEnumerable<swap_flow_event> 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;
}
}