diff --git a/YLErpDAL/Modules/SwapModule/ReturnLegs/DirectionRatio.cs b/YLErpDAL/Modules/SwapModule/ReturnLegs/DirectionRatio.cs
index 13808855..e349bfe9 100644
--- a/YLErpDAL/Modules/SwapModule/ReturnLegs/DirectionRatio.cs
+++ b/YLErpDAL/Modules/SwapModule/ReturnLegs/DirectionRatio.cs
@@ -1,5 +1,6 @@
using YLErp.DBModels;
using YLErp.DBModels.Enums;
+using YLErp.Modules.SwapModule.Margin;
namespace YLErp.Modules.SwapModule.ReturnLegs;
@@ -19,4 +20,12 @@ public static class DirectionRatio
/// 收付方向因子。收取=+1, 支付=-1。
public static int ReceivePay(int direction)
=> direction == (int)SwapDirectionEnum.收取 ? 1 : -1;
+
+ /// 利息腿 PnL 方向因子。收取=+1/支付=-1;保证金腿翻转(利息现金流与本金方向相反)。
+ /// 原 7 处内联 `收取?1:-1; if(MarginModes) ratio=-ratio` 收口到此。
+ public static int InterestLegPnl(int interestDirection, int interestMode)
+ {
+ var ratio = ReceivePay(interestDirection);
+ return MarginModes.Contains(interestMode) ? -ratio : ratio;
+ }
}
diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
index c70476bb..252a4cb4 100644
--- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
+++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
@@ -662,7 +662,7 @@ namespace YLErp.Modules.SwapModule
decimal premiumTotal = 0;
premiumInterests.ForEach(x =>
{
- var ratio = x.InterestDirection == (int)SwapDirectionEnum.收取 ? -1 : 1;
+ var ratio = -DirectionRatio.ReceivePay(x.InterestDirection);
premiumTotal += x.InterestClosePnL * ratio;
});
unwindData.SwapMarginRebatePnl = premiumTotal;
@@ -670,7 +670,7 @@ namespace YLErp.Modules.SwapModule
decimal interestTotal = 0;
interestLegs.ForEach(x =>
{
- var ratio = x.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;
+ var ratio = DirectionRatio.ReceivePay(x.InterestDirection);
interestTotal += x.InterestClosePnL * ratio;
});
unwindData.SwapCloseAmount = interestTotal ;
@@ -1041,11 +1041,7 @@ namespace YLErp.Modules.SwapModule
eodPayPosition.PosiMatuirityDate = td.ExerciseDate.Value;
}
var tradeExtend = td.trade_extend.ExtendObj;
- decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负
- if (MarginModes.Contains(position.InterestMode))
- {
- ratio = -ratio;
- }
+ var ratio = DirectionRatio.InterestLegPnl(position.InterestDirection, position.InterestMode);
if (newEodPayPosition == null)
{
newEodPayPosition = new eod_swap_position();
@@ -1176,11 +1172,7 @@ namespace YLErp.Modules.SwapModule
var tradeExtend = td.trade_extend.ExtendObj;
decimal posiNotionalValue = posiLongNotional + posiShortNational;
decimal closePercent = 1;
- decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负
- if (MarginModes.Contains(position.InterestMode))
- {
- ratio = -ratio;
- }
+ var ratio = DirectionRatio.InterestLegPnl(position.InterestDirection, position.InterestMode);
if (eodPayPosition == null)
{
eodPayPosition = new eod_swap_position();
@@ -1296,11 +1288,7 @@ namespace YLErp.Modules.SwapModule
decimal oriPosiNotionalValue = posiLongNotional + posiShortNational + closeNational;
decimal posiNotionalValue = posiLongNotional + posiShortNational;
// ratio 只负责把腿内原始金额转换为本方盈亏方向,不参与计息金额本身的计算。
- decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负
- if (MarginModes.Contains(position.InterestMode))
- {
- ratio = -ratio;
- }
+ var ratio = DirectionRatio.InterestLegPnl(position.InterestDirection, position.InterestMode);
// 首次日终结算可能包含当日收盘,因此尚无先前的日终利息持仓。
// 部分平仓仍要续接上一日日终:CalcUnwindInterest 会将 InterestProfitSum
// 加入本次待实现,已实现字段也必须按日累计,不能从新建的临时对象重新开始。
@@ -1374,7 +1362,7 @@ namespace YLErp.Modules.SwapModule
var autoInterest = interests[0];
autoInterest.InterestAmount = autoSettledInterestAmount;
autoInterest.InterestClosePnL = autoSettledInterestAmount
- * (autoInterest.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m);
+ * DirectionRatio.ReceivePay(autoInterest.InterestDirection);
}
newEodPayPosition.ValueDate = valueDate;
newEodPayPosition.PositionId = position.id;
@@ -1604,11 +1592,7 @@ namespace YLErp.Modules.SwapModule
{
closePercent = 1;
}
- decimal ratio = eodPayPosition.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负
- if (MarginModes.Contains(position.InterestMode))
- {
- ratio = -ratio;
- }
+ var ratio = DirectionRatio.InterestLegPnl(eodPayPosition.InterestDirection, position.InterestMode);
List positions = new List
{
position
@@ -1692,7 +1676,7 @@ namespace YLErp.Modules.SwapModule
bool open)
{
payQty = Math.Abs(payQty);
- int ratio = eventFlow.PayDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负
+ int ratio = DirectionRatio.ReceivePay(eventFlow.PayDirection);//收取为正,支付为负
int shortRatio = DirectionRatio.LongShort(newEodPayPosition.PositionType);
newEodPayPosition.ValueDate = eventFlow.PayDate.Value;
newEodPayPosition.PositionId = eventFlow.PositionId;
@@ -1792,7 +1776,7 @@ namespace YLErp.Modules.SwapModule
}
var dealDate = curretEod.ValueDate;
int shortRatio = DirectionRatio.LongShort(eod.PositionType);
- int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;
+ int directionRatio = DirectionRatio.ReceivePay(eod.PosiDirection);
curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0;
var price = GetSwapValuationPrice(eod.UnderlyingCode, dealDate, out decimal vobp);
curretEod.dv01 = Dv01Helper.CalcDv01(eod.UnderlyingCode, curretEod.PosiQuantity, eod.PosiDirection, eod.PositionType, vobp);
@@ -1884,7 +1868,7 @@ namespace YLErp.Modules.SwapModule
}
var dealDate = curretEod.ValueDate;
int shortRatio = DirectionRatio.LongShort(eod.PositionType);
- int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;
+ int directionRatio = DirectionRatio.ReceivePay(eod.PosiDirection);
var price = GetSwapValuationPrice(eod.UnderlyingCode, dealDate, out decimal vobp);
var todayConsumedDividend = CalcConsumedDividend(curretEod, unwindEvents);
var originNotional = (decimal)td.OriginalStockEqvNotional / swapPosition.PosiNetPrice;
@@ -1972,7 +1956,7 @@ namespace YLErp.Modules.SwapModule
return;
}
int shortRatio = DirectionRatio.LongShort(eod.PositionType);
- int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;
+ int directionRatio = DirectionRatio.ReceivePay(eod.PosiDirection);
var unwindFlowEvents = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.平仓).ToList();
var openFlowEvents = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.开仓).ToList();
decimal unwindQty = unwindFlowEvents.Sum(s => s.Quantity);
@@ -2053,7 +2037,7 @@ namespace YLErp.Modules.SwapModule
curretEod.PositionId = position.id;
curretEod.ClientId = td.ClientId;
int shortRatio = DirectionRatio.LongShort(position.PositionType);
- int directionRatio = position.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;
+ int directionRatio = DirectionRatio.ReceivePay(position.PosiDirection);
curretEod.PositionType = position.PositionType;
var eod = new eod_swap_position()
{
@@ -2205,11 +2189,7 @@ namespace YLErp.Modules.SwapModule
// 因此保证金腿需要额外反转符号,确保 InterestPnL 表示我方的合约利率端收益。
interestPositions.ForEach(x =>
{
- decimal ratio = x.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负
- if (MarginModes.Contains(x.InterestMode))
- {
- ratio = -ratio;
- }
+ var ratio = DirectionRatio.InterestLegPnl(x.InterestDirection, x.InterestMode);
interestPnL += x.InterestProfitSum * ratio;
});
eod_Swap.InterestPnL = interestPnL;
@@ -2273,20 +2253,12 @@ namespace YLErp.Modules.SwapModule
eod_Swap.dv01 = positions.Sum(s => s.dv01 ?? 0);
interestPositions.ForEach(x =>
{
- decimal ratio = x.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负
- if (MarginModes.Contains(x.InterestMode))
- {
- ratio = -ratio;
- }
+ var ratio = DirectionRatio.InterestLegPnl(x.InterestDirection, x.InterestMode);
eod_Swap.InterestPnL += x.InterestProfitSum * ratio;
});
eodSwapPositions.ForEach(x =>
{
- decimal ratio = x.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;//收取为正,支付为负
- if (MarginModes.Contains(x.InterestMode))
- {
- ratio = -ratio;
- }
+ var ratio = DirectionRatio.InterestLegPnl(x.InterestDirection, x.InterestMode);
eod_Swap.TdRealizedPnL += x.TdCloseMtmPnl + x.TdCloseDividend + x.TdCloseFee + x.TdCloseInterest * ratio + x.TdCloseInterestFee;
});
eod_Swap.PostionValue = eodSwapPositions.Sum(s => s.SwapPositionValue);
@@ -2312,11 +2284,7 @@ namespace YLErp.Modules.SwapModule
///
public static decimal CalculateSwapRealizedPnl(eod_swap_position position)
{
- var interestRatio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;
- if (MarginModes.Contains(position.InterestMode))
- {
- interestRatio = -interestRatio;
- }
+ var interestRatio = DirectionRatio.InterestLegPnl(position.InterestDirection, position.InterestMode);
return position.RealizedMtmPnL
+ position.RealizedDividend
@@ -2336,15 +2304,11 @@ namespace YLErp.Modules.SwapModule
{
if (position.InterestDirection <= 0) return;
- var interestRatio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;
- if (MarginModes.Contains(position.InterestMode))
- {
- interestRatio = -interestRatio;
- }
- else if (position.InterestMode == (int)InterestModeEnum.标的期初全价)
+ if (position.InterestMode == (int)InterestModeEnum.标的期初全价)
{
return;
}
+ var interestRatio = DirectionRatio.InterestLegPnl(position.InterestDirection, position.InterestMode);
position.TdCloseInterest = Math.Abs(position.TdCloseInterest) * interestRatio;
position.RealizedInterest = Math.Abs(position.RealizedInterest) * interestRatio;
// 兼容修复前已落库的利息腿:当时只累计了明细字段,未同步写入 RealizedPnl。
@@ -2838,11 +2802,11 @@ namespace YLErp.Modules.SwapModule
var floatRateInterest = eodInterests.Where(x => !string.IsNullOrEmpty(x.FloatRateUnderlyingCode)).FirstOrDefault();
item.position.FloatRateUnderlyingCode = floatRateInterest?.FloatRateUnderlyingCode;
item.position.FloatRate = floatRateInterest?.FloatRate ?? 0;
- item.OpenMarginAmount = initialMargins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1));
+ item.OpenMarginAmount = initialMargins.Sum(s => s.InterestPrincipalFix * DirectionRatio.ReceivePay(s.InterestDirection));
item.OpenMarginRate = CalculateWeightedMarginRate(tradeMargins);
- item.AdditionalMarginAmount = additionalMargins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1));
+ item.AdditionalMarginAmount = additionalMargins.Sum(s => s.InterestPrincipalFix * DirectionRatio.ReceivePay(s.InterestDirection));
item.MarginInterestAmount = CalculateWeightedMarginInterest(eodMargins);
- item.InterestAmount = eodInterests.Sum(s => s.InterestIncomeSum * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? -1 : 1));
+ item.InterestAmount = eodInterests.Sum(s => s.InterestIncomeSum * (-DirectionRatio.ReceivePay(s.InterestDirection)));
item.InterestRate = eodInterests.Sum(s => s.InterestRateDefault);
// 到期轧差才把期间付息/分红并入净额结算;派息日支付已在现金流层独立结算,不能重复计入估值。
var nettingDividend = (tradeExtend?.ExtendObj?.DividendPayDate ?? 1) == 0 ? pendingDividend : 0m;
@@ -2885,7 +2849,7 @@ namespace YLErp.Modules.SwapModule
public static decimal CalculateWeightedMarginInterest(IEnumerable margins)
{
return margins.Sum(x =>
- x.InterestIncomeSum * (x.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1));
+ x.InterestIncomeSum * DirectionRatio.ReceivePay(x.InterestDirection));
}
///