fix(swap): 修复浮动端已实现盈亏计算逻辑
- 添加了SetFloatingRealizedPnl方法统一计算已实现盈亏 - 已实现盈亏现在正确包含盯市、分红和费用三个组成部分 - 修复了多处RealizedPnl计算错误,确保数值准确性 - 为DF_008测试场景添加了专门的单元测试验证 - 移除了重复的盈亏计算代码,提高代码可维护性
This commit is contained in:
@@ -378,6 +378,39 @@ namespace YLErp.Modules.SwapModule
|
||||
Console.WriteLine($"分红增值税调整: 付息100, 税率6% → TdPosiDividend={result.TdPosiDividend}(期望{expected})✅");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DF_008_CopyBranch_RealizedPnlIncludesRealizedFee()
|
||||
{
|
||||
var service = new StubEodService
|
||||
{
|
||||
UnderlyingPrice = 1.002m,
|
||||
TaxRate = 0m,
|
||||
BondPayment = 0m
|
||||
};
|
||||
var preEod = new eod_swap_position
|
||||
{
|
||||
id = 5001,
|
||||
SwapTradeId = SwapTradeId,
|
||||
PositionId = 3001,
|
||||
ValueDate = PreSettleDate,
|
||||
PosiQuantity = 10000m,
|
||||
PosiGrossPrice = 1.002m,
|
||||
PosiNetPrice = 1.005m,
|
||||
UnderlyingCode = "210210.IB",
|
||||
ContractSize = 1m,
|
||||
PositionType = (int)PositionTypeFlag.Long,
|
||||
PosiDirection = (int)SwapDirectionEnum.收取,
|
||||
RealizedMtmPnL = 98000000m,
|
||||
RealizedDividend = 0m,
|
||||
RealizedFee = 100m,
|
||||
RealizedPnl = 98000000m
|
||||
};
|
||||
|
||||
var result = service.ExecuteCopyEodPosition(preEod, null, CreateTrade(), TradeDate, PreSettleDate);
|
||||
|
||||
Assert.AreEqual(98000100m, result.RealizedPnl);
|
||||
}
|
||||
|
||||
private static void AssertDecimalEqual(decimal expected, decimal actual, decimal tolerance, string message = "")
|
||||
{
|
||||
Assert.IsTrue(Math.Abs(expected - actual) <= tolerance,
|
||||
|
||||
@@ -1510,7 +1510,7 @@ namespace YLErp.Modules.SwapModule
|
||||
newEodPayPosition.RealizedFee = closeFee;
|
||||
newEodPayPosition.RealizedMtmPnL = newEodPayPosition.TdCloseMtmPnl;
|
||||
newEodPayPosition.RealizedDividend = newEodPayPosition.TdCloseDividend;
|
||||
newEodPayPosition.RealizedPnl = newEodPayPosition.TdCloseMtmPnl;
|
||||
SetFloatingRealizedPnl(newEodPayPosition);
|
||||
|
||||
newEodPayPosition.PosiStatus = payQty == 0 ? 1 : 0;
|
||||
UpdateDbOption(newEodPayPosition);
|
||||
@@ -1585,7 +1585,7 @@ namespace YLErp.Modules.SwapModule
|
||||
curretEod.RealizedMtmPnL = eod.RealizedMtmPnL + curretEod.TdCloseMtmPnl;
|
||||
curretEod.RealizedDividend = eod.RealizedDividend + curretEod.TdCloseDividend;
|
||||
curretEod.RealizedFee = eod.RealizedFee + curretEod.TdCloseFee;
|
||||
curretEod.RealizedPnl = eod.RealizedPnl + curretEod.TdCloseMtmPnl;
|
||||
SetFloatingRealizedPnl(curretEod);
|
||||
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.StartDate.Value
|
||||
, seekPreday: true, currencyRateType: curretEod.PosiDirection == (int)SwapDirectionEnum.收取 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
||||
curretEod.TdCurrency = Convert.ToDecimal(currencyRate);
|
||||
@@ -1599,6 +1599,18 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
return curretEod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 浮动腿累计已实现盈亏由盯市、分红和费用三个已实现组成项汇总。
|
||||
/// 各组成项已经按本方视角落库,此处不再额外转换方向。
|
||||
/// </summary>
|
||||
private static void SetFloatingRealizedPnl(eod_swap_position position)
|
||||
{
|
||||
position.RealizedPnl = position.RealizedMtmPnL
|
||||
+ position.RealizedDividend
|
||||
+ position.RealizedFee;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新虚拟交易费用
|
||||
/// </summary>
|
||||
@@ -1659,7 +1671,6 @@ namespace YLErp.Modules.SwapModule
|
||||
// 当日浮动端平仓盈亏·分红(仅来自平仓事件 和 互换 中已实现的分红)
|
||||
curretEod.TdCloseDividend = unwindEvents.Sum(e => e.DividendIn);
|
||||
curretEod.RealizedFee = eod.RealizedFee + curretEod.TdCloseFee;
|
||||
curretEod.RealizedPnl = eod.RealizedPnl + curretEod.TdCloseMtmPnl;
|
||||
curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0;
|
||||
var closeQty = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.平仓).ToList().Sum(s => s.Quantity);
|
||||
|
||||
@@ -1675,7 +1686,7 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
curretEod.PosiDividendSum = 0;
|
||||
}
|
||||
curretEod.RealizedPnl += curretEod.TdCloseDividend;
|
||||
SetFloatingRealizedPnl(curretEod);
|
||||
curretEod.SwapPositionValue -= curretEod.TdCloseDividend;
|
||||
|
||||
curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending;
|
||||
@@ -1853,7 +1864,7 @@ namespace YLErp.Modules.SwapModule
|
||||
curretEod.RealizedMtmPnL = curretEod.TdCloseMtmPnl;
|
||||
curretEod.RealizedDividend = curretEod.TdCloseDividend;
|
||||
curretEod.RealizedFee = curretEod.TdCloseFee;
|
||||
curretEod.RealizedPnl = curretEod.TdCloseMtmPnl;
|
||||
SetFloatingRealizedPnl(curretEod);
|
||||
curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0;
|
||||
if (curretEod.PosiStatus == 1)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user