diff --git a/UnitTestProject/Modules/SwapModule/GLMS20260105GoldenTest.cs b/UnitTestProject/Modules/SwapModule/GLMS20260105GoldenTest.cs
index b694f6fa..b70cdb0a 100644
--- a/UnitTestProject/Modules/SwapModule/GLMS20260105GoldenTest.cs
+++ b/UnitTestProject/Modules/SwapModule/GLMS20260105GoldenTest.cs
@@ -58,6 +58,11 @@ namespace YLErp.Modules.SwapModule
var keyDates = new[] { swapDate.AddDays(-1), swapDate, swapDate.AddDays(1) };
var keyFloatEods = floatEods.Where(x => keyDates.Contains(x.ValueDate)).ToList();
+ // 录制 UpdateEodPosition 的输入(互换前日eod + 互换flow_event + 持仓 + 交易)
+ var preSwapEod = floatEods.FirstOrDefault(x => x.ValueDate == swapDate.AddDays(-1));
+ var swapFlowEvents = flows.Where(x => x.EventDate == swapDate && x.PositionId == preSwapEod?.PositionId).ToList();
+ var swapPosition = positions.FirstOrDefault(x => x.id == preSwapEod?.PositionId);
+
var golden = new JObject
{
["TradeNumber"] = TradeNumber,
@@ -98,6 +103,19 @@ namespace YLErp.Modules.SwapModule
}
golden["AllFloatEodDividends"] = allArray;
+ // 录制回放所需的输入数据(用于重新调 UpdateEodPosition)
+ if (preSwapEod != null && swapPosition != null)
+ {
+ var settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
+ golden["ReplayInput"] = new JObject
+ {
+ ["Trade"] = JObject.FromObject(td, JsonSerializer.Create(settings)),
+ ["Position"] = JObject.FromObject(swapPosition, JsonSerializer.Create(settings)),
+ ["PreSwapEod"] = JObject.FromObject(preSwapEod, JsonSerializer.Create(settings)),
+ ["SwapFlowEvents"] = JArray.FromObject(swapFlowEvents, JsonSerializer.Create(settings))
+ };
+ }
+
string json = JsonConvert.SerializeObject(golden, Formatting.Indented);
string path = Path.Combine(GoldenDir, $"golden_{TradeNumber}.json");
File.WriteAllText(path, json);
@@ -131,9 +149,10 @@ namespace YLErp.Modules.SwapModule
#region 回放:读 golden 验证精度差异
///
- /// 回放 golden,验证互换后 PosiDividendSum 的精度差异。
- /// 当前代码会失败(差异=0.36),这就是红灯。
- /// 修复后(cs:1635 改为递增模式)应通过。
+ /// 回放 golden:用真实数据重新调 UpdateEodPosition,验证修复后 PosiDividendSum 正确。
+ ///
+ /// 红灯(修复前):从头重算产生 0.36 差异
+ /// 绿灯(修复后):递增模式,PosiDividendSum = 前日 + 新计 - 实现 = -90000
///
[TestMethod]
public void Replay_VerifyPrecisionDiff()
@@ -152,41 +171,82 @@ namespace YLErp.Modules.SwapModule
var json = File.ReadAllText(files[0]);
var golden = JObject.Parse(json);
- var keyEods = golden["KeyFloatEodPositions"] as JArray;
- Assert.IsNotNull(keyEods, "KeyFloatEodPositions 缺失");
- Assert.IsTrue(keyEods.Count >= 2, "应至少有互换前+互换日两条eod");
-
- var swapDateStr = golden["SwapDate"]?.Value();
- Console.WriteLine($"SwapDate = {swapDateStr}");
-
- JObject preSwap = null, swapDay = null;
- var swapDate = DateTime.Parse(swapDateStr);
- foreach (var e in keyEods)
+ var replayInput = golden["ReplayInput"];
+ if (replayInput == null)
{
- var dateStr = e["ValueDate"]?.Value();
- if (dateStr == swapDate.AddDays(-1).ToString("yyyy-MM-dd")) preSwap = e as JObject;
- if (dateStr == swapDateStr) swapDay = e as JObject;
+ Assert.Inconclusive("golden 缺少 ReplayInput(请重新录制)");
+ return;
}
- Assert.IsNotNull(preSwap, "找不到互换前eod");
- Assert.IsNotNull(swapDay, "找不到互换日eod");
+ var settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
+ var td = replayInput["Trade"]!.ToObject(JsonSerializer.Create(settings));
+ var position = replayInput["Position"]!.ToObject(JsonSerializer.Create(settings));
+ var preSwapEod = replayInput["PreSwapEod"]!.ToObject(JsonSerializer.Create(settings));
+ var swapFlowEvents = replayInput["SwapFlowEvents"]!.ToObject>(JsonSerializer.Create(settings));
- decimal preDividendSum = preSwap["PosiDividendSum"]!.Value();
- decimal swapCloseDividend = swapDay["TdCloseDividend"]!.Value();
- decimal actualDividendSum = swapDay["PosiDividendSum"]!.Value();
- decimal expectedDividendSum = preDividendSum - swapCloseDividend;
+ var swapDateStr = golden["SwapDate"]!.Value();
+ var swapDate = DateTime.Parse(swapDateStr);
+ Console.WriteLine($"SwapDate = {swapDateStr}");
+ Console.WriteLine($"互换前 PosiDividendSum = {preSwapEod.PosiDividendSum}");
+ Console.WriteLine($"互换 DividendIn = {string.Join(",", swapFlowEvents.Select(x => x.DividendIn))}");
- Console.WriteLine($"互换前 PosiDividendSum = {preDividendSum}");
- Console.WriteLine($"互换实现 TdCloseDividend = {swapCloseDividend}");
- Console.WriteLine($"期望 PosiDividendSum = {preDividendSum} - ({swapCloseDividend}) = {expectedDividendSum}");
- Console.WriteLine($"实际 PosiDividendSum = {actualDividendSum}");
- Console.WriteLine($"差异 = {actualDividendSum - expectedDividendSum}");
+ // 用修复后的代码重新调 UpdateEodPosition
+ var service = new ReplayStubService(preSwapEod.UnderlyingCode);
+ var result = service.ExecuteUpdateEodPosition(
+ position, preSwapEod, td, swapDate, swapDate.AddDays(-1), swapFlowEvents);
- // 核心断言:互换后 PosiDividendSum 应精确 = 前日 - 实现
- // 当前代码会失败(差异=0.36),这就是红灯
- Assert.AreEqual(expectedDividendSum, actualDividendSum,
- $"互换后 PosiDividendSum 应精确={expectedDividendSum},实际={actualDividendSum}," +
- $"差异={actualDividendSum - expectedDividendSum}(从头重算 vs 递增的舍入累积)");
+ // 期望:PosiDividendSum = 前日 + 当天新计 - 实现
+ decimal expected = preSwapEod.PosiDividendSum + result.TdPosiDividend - result.TdCloseDividend;
+ Console.WriteLine($"\n修复后结果:");
+ Console.WriteLine($" TdPosiDividend = {result.TdPosiDividend}");
+ Console.WriteLine($" TdCloseDividend = {result.TdCloseDividend}");
+ Console.WriteLine($" PosiDividendSum = {result.PosiDividendSum}");
+ Console.WriteLine($" 期望 = {preSwapEod.PosiDividendSum} + {result.TdPosiDividend} - ({result.TdCloseDividend}) = {expected}");
+
+ Assert.AreEqual(expected, result.PosiDividendSum,
+ $"修复后 PosiDividendSum 应=前日+新计-实现={expected},实际={result.PosiDividendSum}");
+ Console.WriteLine($"\n✅ 修复验证通过:PosiDividendSum={result.PosiDividendSum} = {expected}");
+ }
+
+ #endregion
+
+ #region 回放用 Stub
+
+ private sealed class ReplayStubService : SwapEodPositionService
+ {
+ private readonly string _underlyingCode;
+ public ReplayStubService(string underlyingCode) : base(new OptUserInfo(0, "Replay", OptUserFrom.UnitTest))
+ {
+ _underlyingCode = underlyingCode;
+ }
+
+ protected override underlying_manager GetUnderlyingData(string underlyingCode)
+ {
+ // 返回最小可用数据(增值税=0)
+ return new underlying_manager { ValueAddedTax = 0m };
+ }
+
+ protected override decimal GetUnderlyingPrice(string code, DateTime settleDate, out decimal vobp)
+ {
+ vobp = 0m;
+ return 1.01m; // 固定价格
+ }
+
+ protected override decimal CalcBondPayment(string underlyingCode, DateTime fromDate, DateTime toDate, decimal qty, int shortRatio, int directionRatio)
+ {
+ // 返回0:互换日的 TdPosiDividend=0(无新增分红),聚焦验证 PosiDividendSum 的递增逻辑
+ return 0m;
+ }
+
+ protected override void SaveAllChanges() { }
+ protected override double GetCurrencyRate(string q, string s, DateTime d, bool p, CurrencyRateType t) => 1.0;
+
+ public eod_swap_position ExecuteUpdateEodPosition(
+ swap_position swapPosition, eod_swap_position eod, trade td,
+ DateTime valueDate, DateTime preSettleDate, List unwindEvents)
+ {
+ return UpdateEodPosition(swapPosition, eod, null, td, valueDate, preSettleDate, unwindEvents);
+ }
}
#endregion
diff --git a/UnitTestProject/Resources/GoldenFiles/GLMS20260105/golden_GLMS-20260105-0007.json b/UnitTestProject/Resources/GoldenFiles/GLMS20260105/golden_GLMS-20260105-0007.json
index cc5d8ee7..c617a192 100644
--- a/UnitTestProject/Resources/GoldenFiles/GLMS20260105/golden_GLMS-20260105-0007.json
+++ b/UnitTestProject/Resources/GoldenFiles/GLMS20260105/golden_GLMS-20260105-0007.json
@@ -390,5 +390,891 @@
"TdPosiDividend": 0.0,
"RealizedDividend": -400.000000
}
- ]
+ ],
+ "ReplayInput": {
+ "Trade": {
+ "SubTrades": null,
+ "YesterDayTradeSavedVol": null,
+ "PV": null,
+ "RealizedPnl": null,
+ "PositionPnl": null,
+ "MaturityWorkDay": 124,
+ "PairTradeNumber": null,
+ "ShowNotional": -50000000.0,
+ "MaturityDay": 182,
+ "TradeOpenVolatilityString": "0.00%",
+ "InitialSpotPriceOriginal": null,
+ "TradeOriginalAmount": null,
+ "ExerciseDateString": "2026-12-31",
+ "ActualStrike": null,
+ "StrikeString": "0.000000000",
+ "TradeSinglePriceString": "0.00%",
+ "TradeDateString": "2026-01-05",
+ "LotsNewInfo": null,
+ "UnWindPrice": null,
+ "StockEqvNotionalToShow": 50500000.0,
+ "SettlementTypeDesc": "收盘价",
+ "SettlementDesc": null,
+ "VarietyId": null,
+ "SyntheticUnderlyingTipsInfo": null,
+ "StrikeToShow": "0.000000000",
+ "CurNotional": 0.0,
+ "LastDayNotional": 0.0,
+ "Amount": null,
+ "ContractCode": null,
+ "InitialMarginRatio": null,
+ "UnderlyingPrice": null,
+ "UnderlyingName": null,
+ "DeltaInLots": null,
+ "ValueStatus": null,
+ "UnWindUnderlyingPrice": null,
+ "UnWindTradePrice": null,
+ "UnWindTotalAmount": null,
+ "UnWindFee": null,
+ "UnWindTimes": 0,
+ "KnockInOutStatusObservation": null,
+ "DividendRatio": 0.0,
+ "InitYtm": 0.025000,
+ "CalcId": null,
+ "TTMDays": null,
+ "UnderlyingInstrumentTypeCn": "利率债",
+ "ExerciseModeCn": "",
+ "ClientNumber": null,
+ "SummaryType": "收益互换",
+ "QuoteUnitSingle": null,
+ "QuoteUnit": null,
+ "trade_forward": {
+ "id": 0,
+ "TradeId": 0,
+ "OpenCommission": 0.0,
+ "AnnualMarginRate": 0.0,
+ "AnnualStoragePrice": 0.0,
+ "ForwardValue": 0.0,
+ "ObservationStart": null,
+ "ObservationDates": null,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_asian_option": {
+ "StrikeType": null,
+ "PayoffType": null,
+ "SettleMode": null,
+ "StrikeGearingFactor": 1.0,
+ "AveragingPeriodStartDate": null,
+ "ObservationDates": null,
+ "EnhancedPrice": 0.0,
+ "StrikeTypeCn": "",
+ "PayoffTypeCn": "",
+ "Fixings": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_rainbow_option": {
+ "UnderlyingAssetCode": null,
+ "Strike": null,
+ "UnderlyingMaturityDate": null,
+ "UnderlyingId1": null,
+ "UnderlyingId2": null,
+ "Strike2": null,
+ "SpotPrice1": null,
+ "SpotPrice2": null,
+ "RainbowType": null,
+ "UnderlyingAssetCode2": null,
+ "CorRelation": null,
+ "CashAmount": null,
+ "Vol2": 0.0,
+ "UnderlyingCodes": [
+ null,
+ null
+ ],
+ "Strikes": [
+ 0.0,
+ 0.0
+ ],
+ "SpotPrices": [
+ 0.0,
+ 0.0
+ ],
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_barrier_option": {
+ "KnockInOutStatus": null,
+ "KnockInOutStatusCn": "观察中",
+ "KnockInOutDate": null,
+ "KnockInOutNotional": null,
+ "BarrierShift": null,
+ "BarrierTypeEn": null,
+ "IsDiscrete": false,
+ "BarrierPrice": null,
+ "UpperBarrierPrice": null,
+ "Discrete": null,
+ "BarrierType": null,
+ "Rebate": null,
+ "RebateRate": null,
+ "RebateHigh": null,
+ "RebateHighRate": null,
+ "RebateAnnualizedAtKO": false,
+ "RebateDayCount": null,
+ "ObservationDates": null,
+ "LatestObservationDate": null,
+ "RebateType": null,
+ "RebateTypeCn": "",
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_risky_option": {
+ "Strike1": null,
+ "Strike2": null,
+ "Strike3": null,
+ "ParticipationRate1": null,
+ "ParticipationRate2": null,
+ "ParticipationRate3": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_binary_option": {
+ "RebateType": null,
+ "RebateTypeCn": "",
+ "CashOrNothingAmount": null,
+ "CashOrNothingAmountHigh": null,
+ "CashOrNothingAmountRate": null,
+ "CashOrNothingAmountHighRate": null,
+ "PayoffType": "",
+ "UpperBarrier": null,
+ "RebateDayCount": null,
+ "RebateAnnualizedAtKO": false,
+ "ObservationDates": null,
+ "LatestObservationDate": null,
+ "UpperBarrierRelative": "0",
+ "MonitorType": null,
+ "IsDiscreteMonitored": false,
+ "Offset": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_spread_option": {
+ "UnderlyingMaturityDate2": null,
+ "UnderlyingMaturityDate3": null,
+ "UnderlyingMaturityDate4": null,
+ "Payoff": "S1-S2",
+ "UnderlyingId1": null,
+ "UnderlyingId2": null,
+ "UnderlyingId3": null,
+ "UnderlyingId4": null,
+ "UnderlyingAssetClass1": null,
+ "UnderlyingAssetClass2": null,
+ "UnderlyingAssetClass3": null,
+ "UnderlyingAssetClass4": null,
+ "UnderlyingAssetCode1": null,
+ "UnderlyingAssetCode2": null,
+ "UnderlyingAssetCode3": null,
+ "UnderlyingAssetCode4": null,
+ "UnderlyingAssetName1": null,
+ "UnderlyingAssetName2": null,
+ "UnderlyingAssetName3": null,
+ "UnderlyingAssetName4": null,
+ "TradeCloseVolatility1": null,
+ "TradeCloseVolatility2": null,
+ "TradeCloseVolatility3": null,
+ "TradeCloseVolatility4": null,
+ "TradeOpenVolatility1": null,
+ "TradeOpenVolatility2": null,
+ "TradeOpenVolatility3": null,
+ "TradeOpenVolatility4": null,
+ "NumOfSmoothingDays1": null,
+ "NumOfSmoothingDays2": null,
+ "NumOfSmoothingDays3": null,
+ "NumOfSmoothingDays4": null,
+ "Vol1": null,
+ "Vol2": null,
+ "Vol3": null,
+ "Vol4": null,
+ "Correlation12": null,
+ "Correlation13": null,
+ "Correlation14": null,
+ "Correlation23": null,
+ "Correlation24": null,
+ "Correlation34": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_double_sharkfin_option": {
+ "KnockInOutStatus": null,
+ "KnockInOutStatusCn": "观察中",
+ "KnockInOutDate": null,
+ "IsDiscrete": false,
+ "BarrierHigh": 0.0,
+ "BarrierLow": 0.0,
+ "StrikeHigh": null,
+ "StrikeLow": null,
+ "CallParticipationRate": null,
+ "PutParticipationRate": null,
+ "Discrete": null,
+ "Rebate": null,
+ "RebateRate": null,
+ "RebateHigh": null,
+ "RebateHighRate": null,
+ "RebateType": null,
+ "ObservationDates": null,
+ "LatestObservationDate": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_autocall": {
+ "KnockInOutStatus": null,
+ "KnockInOutStatusCn": "观察中",
+ "KnockInOutDate": null,
+ "KOBarrier": 0.0,
+ "KIBarrier": 0.0,
+ "CouponBarrier": 0.0,
+ "Coupon": 0.0,
+ "IsFixedCoupon": false,
+ "CouponPayType": 0,
+ "SpreadStrike1": null,
+ "SpreadStrike": null,
+ "CouponPayAtMaturity": false,
+ "IncludeCouponAfterKI": false,
+ "KOObservationDates": null,
+ "CouponObservation": null,
+ "LatestKOObservationDate": null,
+ "LatestKOBarrier": null,
+ "ObservationDates": null,
+ "LatestObservationDate": null,
+ "IsAnnualized2": false,
+ "AnnualizeFactor2": null,
+ "CouponDayCount": "Act365",
+ "HappenedObservations": null,
+ "KIPayoffType": 0,
+ "CouponIncludeStartDate": null,
+ "CouponUsePaymentDate": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_snowball": {
+ "IsInitialKnockedIn": false,
+ "KnockInOutStatus": null,
+ "KnockInOutStatusCn": "观察中",
+ "KnockInOutDate": null,
+ "KOBarrier": 0.0,
+ "KIBarrier": 0.0,
+ "Coupon": 0.0,
+ "KOObservationDates": null,
+ "KOObservationSettleDates": null,
+ "LatestKOObservationDate": null,
+ "LatestKOBarrier": null,
+ "ObservationDates": null,
+ "LatestObservationDate": null,
+ "KORebate": 0.0,
+ "KORebateType": 0,
+ "IsFixedCoupon": false,
+ "SpreadStrikeAtKO": null,
+ "SpreadStrikeAtKO1": null,
+ "SpreadStrikeAtMaturity1": null,
+ "SpreadStrikeAtMaturity": null,
+ "KOPayoffType": 0,
+ "KIPayoffType": 0,
+ "AnnualizedPremiumRate": null,
+ "IsAnnualized2": false,
+ "AnnualizeFactor2": null,
+ "InitialAdvance": null,
+ "PeriodAdvance": null,
+ "FontEarning": null,
+ "ConfirmedLine": null,
+ "ConfirmedFloor": null,
+ "CouponDayCount": null,
+ "PrepaymentUsed": false,
+ "PrepaymentRatio": null,
+ "PrepaymentInterestRate": null,
+ "PrepaymentConvertCashRate": null,
+ "CouponIncludeEndDate": null,
+ "EnhancedParticipationRate": null,
+ "KIParticipationRate": null,
+ "PrincipalProtectionRate": null,
+ "KIObservationType": 0,
+ "KOBarrierAdjustStep": 0.0,
+ "CouponIncludeStartDate": null,
+ "CouponUsePaymentDate": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_rangeaccrual": {
+ "LowerRange": 0.0,
+ "UpperRange": 0.0,
+ "BonusRate": 0.0,
+ "ObservationDates": null,
+ "LatestObservationDate": null,
+ "HappenedObservations": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_airbag": {
+ "KnockInOutStatus": null,
+ "KnockInOutStatusCn": "观察中",
+ "KnockInOutDate": null,
+ "KnockInOutNotional": null,
+ "HighStrike": 0.0,
+ "HasPayoffLimit": false,
+ "Barrier": 0.0,
+ "KIParticipationRate": 0.0,
+ "NotKIParticipationRate": null,
+ "IsDiscreteMonitored": false,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_accumulator_option": {
+ "KOBarrier": null,
+ "KOObservationDates": null,
+ "KOObservationSettleDates": null,
+ "AccumuTradeAmount": 0.0,
+ "OriginalAccumuTradeAmount": 0.0,
+ "AccumuType": "",
+ "PayoffType": null,
+ "Coupon": 0.0,
+ "CouponPercent": false,
+ "IsFixedCoupon": false,
+ "CouponDayCount": null,
+ "PutMultiplier": 1.0,
+ "CallMultiplier": 1.0,
+ "EarlyTerminate": false,
+ "SettlementMode": null,
+ "SettlementMode2": null,
+ "SettlementMode3": null,
+ "KnockOutDate": null,
+ "ForwardDateType": null,
+ "ForwardPriceType": null,
+ "AccumulatorStructureType": 0,
+ "Coupon2": null,
+ "Strike2": null,
+ "Strike3": null,
+ "Multiplier": null,
+ "Multiplier2": null,
+ "Multiplier3": null,
+ "KnockInOutStatusCn": "观察中",
+ "LatestObservationDate": null,
+ "StrikeGearingFactor": 1.0,
+ "LatestKOBarrier": null,
+ "latestCoupon": null,
+ "ForwardPriceType2": null,
+ "ForwardDateType2": null,
+ "ForwardPriceType3": null,
+ "ForwardDateType3": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_swap": {
+ "AnnualDays": null,
+ "IsGetFloatingProfit": false,
+ "GetVarietyId": null,
+ "GetUnderlyingId": null,
+ "GetUnderlyingCode": null,
+ "GetLongShort": null,
+ "GetSpotPrice": null,
+ "GetOpenPrice": null,
+ "GetTradePrice": null,
+ "GetSwapTimeAndRate": null,
+ "GetSwapRate": 0.0,
+ "GetFixedProfit": null,
+ "GetSingleFee": null,
+ "GetUnAnnualRate": null,
+ "GetMarginRate": 0.0,
+ "GetFinalPrice": null,
+ "GetNotional": null,
+ "GetTradeAmount": null,
+ "GetLot": null,
+ "IsPayFloatingProfit": false,
+ "PayVarietyId": null,
+ "PayUnderlyingId": null,
+ "PayUnderlyingCode": null,
+ "PayLongShort": null,
+ "PaySpotPrice": null,
+ "PayOpenPrice": null,
+ "PayTradePrice": null,
+ "PaySwapTimeAndRate": null,
+ "PaySwapRate": 0.0,
+ "PayFixedProfit": null,
+ "PaySingleFee": null,
+ "RateCalcMode": "11",
+ "IncludeFirstDay": true,
+ "PayUnAnnualRate": null,
+ "PayMarginRate": 0.0,
+ "PayFinalPrice": null,
+ "PayNotional": null,
+ "PayTradeAmount": null,
+ "PayLot": null,
+ "FlowId": null,
+ "AnnualVarIncome": false,
+ "SwapType": null,
+ "SettlementPayType": 0,
+ "IsTradePriceWhenOpen": false,
+ "IsShare": false,
+ "OriginalTradeId": null,
+ "GetCountRatio": 0.0,
+ "PayCountRatio": 0.0,
+ "GetContractSize": 0.0,
+ "PayContractSize": 0.0,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "get_trade_swap_details": [],
+ "pay_trade_swap_details": [],
+ "trade_underlying_enhance": {
+ "AnnualizedEnhanceRate": 0.0,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_cashflow": {
+ "ProfitRate": 0.0,
+ "RateType": 0,
+ "DepositType": 0,
+ "PrepayRatio": 0.0,
+ "ProfitDayCount": "Act365",
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_custom": {
+ "ObservationDates": null,
+ "LatestObservationDate": null,
+ "id": 0,
+ "TradeId": 0,
+ "OptId": null,
+ "OptName": null,
+ "OptDate": null,
+ "EncryptId": "93JNozbumCxdv7dwztjpOg"
+ },
+ "trade_extend": {
+ "TradeId": 0,
+ "ExtendJson": null,
+ "CompanyJson": null,
+ "ExtendObj": {
+ "FlowBookMode": 0,
+ "FloatingPnlAnnualized": false,
+ "NeedOpenFee": false,
+ "OpenFeeType": 0,
+ "AnnualDays": 365,
+ "InterestCalcMode": "11",
+ "Direction": 0,
+ "SettlementRules": 0,
+ "DividendPayDate": 1
+ }
+ },
+ "swap_positions": [],
+ "inital_eod_swap_positions": [],
+ "eod_swap_positions": [],
+ "trade_Initial_Margin": {
+ "TradeId": 0,
+ "Direction": 1,
+ "MarginType": 0,
+ "MarginValue": 0.0
+ },
+ "swap_Flow_Events": [],
+ "swap_Events": [],
+ "eod_swaps": [],
+ "ClientCashInCashOutList": [],
+ "SalesCommission": null,
+ "trade_cash": null,
+ "RemarkInfo": "到期付息(手动付息后次日部分平仓)",
+ "eod_trade": null,
+ "SettlementAmount": null,
+ "ActualExerciseDate": null,
+ "trade_swap_gj": {
+ "LongShort": null,
+ "OpenPrice": null,
+ "OpenCurrencyRate": null,
+ "TradeCommission": null,
+ "PricingOriginalStockEqvNotional": null,
+ "PricingStockEqvNotional": null,
+ "SwapTimeAndRate": null
+ },
+ "Tags": null,
+ "OutputTags": null,
+ "SaveExt": null,
+ "TradeType": "收益互换",
+ "TradeSavedVol": null,
+ "CreatorId": null,
+ "CreatorName": null,
+ "CreateDate": "2026-07-01T20:58:14",
+ "PairTrade": "",
+ "TradeSinglePrice": null,
+ "GroupId": null,
+ "GroupName": "",
+ "NumOfSmoothingDays": null,
+ "ParentTradeId": 0,
+ "TradeCloseVolatility": null,
+ "TradeOpenVolatility": null,
+ "UnWindDate": "2026-03-03T00:00:00",
+ "UnWindNotional": null,
+ "CheckStatus": 0,
+ "CheckTradeUpdate": 1,
+ "InitialSpotPrice": 1.000004,
+ "IsMoneynessOption": null,
+ "TradeAmount": 50000000.0,
+ "TradeUnit": "",
+ "StockEqvNotional": 50500000.0,
+ "StockEqvNotionalMax": null,
+ "StockEqvNotionalReal": 50500000.0,
+ "VolType": null,
+ "UnderlyingInstrumentType": "TBonds",
+ "ExerciseDate": "2026-12-31T00:00:00",
+ "TraderName": "唐善洁",
+ "TraderId": 164,
+ "Vol": null,
+ "Day1Pnl": null,
+ "MidVol": null,
+ "ExchangeRate": null,
+ "Strike": null,
+ "UnderlyingId": 140677,
+ "BasisUnderlyingId": null,
+ "BasisUnderlyingCode": null,
+ "BasisGap": null,
+ "ExchangeOptionCode": null,
+ "AssetBookName": "测试簿记",
+ "AssetId": 40,
+ "Notional": 50000000.0,
+ "OptionType": null,
+ "PricingModel": null,
+ "ExerciseMode": null,
+ "NoRiskRate": null,
+ "SpotPrice": 1.000004,
+ "TradeNumber": "GLMS-20260105-0007",
+ "ClientId": 43,
+ "ClientName": "善洁测试用产品二号",
+ "UnderlyingCode": "230004.IB",
+ "UnderlyingAssetClass": "其他市场债券",
+ "TradeDate": "2026-01-05T00:00:00",
+ "BuySell": "卖出",
+ "StartDate": "2026-01-05T00:00:00",
+ "MaturityDate": null,
+ "ObservationDateStr": null,
+ "TradePrice": 0.0,
+ "AccurateTradePrice": null,
+ "TradeStatus": "确认成交",
+ "ProcessStatus": "通过审批",
+ "ProcessOrderId": -2,
+ "ProcessOrderBranch": 0,
+ "ProcessOptDate": "2026-07-01T23:36:20",
+ "SettlementType": 0,
+ "ValidState": "Valid",
+ "Comments": "到期付息(手动付息后次日部分平仓)",
+ "SentMailCount": null,
+ "Lots": null,
+ "HasPartialUnWind": 1,
+ "OriginalNotional": 0.0,
+ "TradeSource": "系统交易",
+ "OriginalStockEqvNotional": 50500000.0,
+ "OriginalStockEqvNotionalV2": 50500000.0,
+ "IsUsePremiumRate": true,
+ "IsTradePricePayType": true,
+ "IsAnnualized": false,
+ "AnnualizeFactor": null,
+ "DividendRate": null,
+ "ParticipationRate": 1.0,
+ "PrincipalRate": null,
+ "OriginalPrincipalSum": null,
+ "PrincipalRateWrite": null,
+ "SinglePrincipalWrite": null,
+ "SettlementDate": null,
+ "SettlementFlag": 0,
+ "SettlementFlagStr": "否",
+ "SettlementFlagDate": null,
+ "SettlementFlagOptId": null,
+ "SettlementFlagOptName": null,
+ "CalcFlag": 0,
+ "IsSingleContract": null,
+ "PremiumPayDate": null,
+ "PremiumRate": null,
+ "UnderlyingAssetName": "23附息国债04",
+ "UnderlyingVariety": null,
+ "ContractVersion": null,
+ "FinalPrice": null,
+ "OpponentRole": "乙方",
+ "DurationDays": null,
+ "StructureType": "普通债券类收益互换",
+ "InitialMargin": 0.0,
+ "StructureIntroduction": null,
+ "MarginTemplateName": "系统默认",
+ "MarginType": 0,
+ "MarginRate": 0.0,
+ "PositionMarginRate": 0.0,
+ "QuoteCurrency": null,
+ "SettlementCurrency": null,
+ "IsGroup": 0,
+ "ExtendInfo": null,
+ "IsNight": false,
+ "Propertys": [],
+ "ExtendOptionTypeInfo": null,
+ "AccumulatorOptionId": null,
+ "OptId": 164,
+ "OptName": "唐善洁",
+ "OptDate": "2026-07-01T23:36:20",
+ "IsApproval": false,
+ "IsAutoGenerate": null,
+ "HTStatus": null,
+ "Warning": false,
+ "DividendDate": "2000-01-01T00:00:00",
+ "CountRatio": 1,
+ "CallPut": "",
+ "IsMoneynessOptionData": false,
+ "MetaDic": {},
+ "TradeExtendJson": null,
+ "TradeMultipleType": "收益互换",
+ "Fixing": null,
+ "id": 1924,
+ "EncryptId": "LKPDwn1OC-Vzkg-aD-cnDA"
+ },
+ "Position": {
+ "PositionId": 0,
+ "SwapTradeId": 1924,
+ "PosiDirection": 2,
+ "PositionType": 1,
+ "UnderlyingCode": "230004.IB",
+ "underlying": null,
+ "CountRatio": 1.000000,
+ "ContractSize": 1.000000,
+ "PosiNetPrice": 1.01000400000,
+ "PosiGrossPrice": 1.01000000000,
+ "PosiNetFeePrice": 1.00000400000,
+ "PosiNetNoFeePrice": 1.00000000000,
+ "PosiNotionalValue": 50500000.000000,
+ "PosiQuantity": 50000000.000000,
+ "PosiTradingFee": 0.0,
+ "PosiTradingFeeUnit": 0.0,
+ "PosiStartDate": "2026-01-05T00:00:00",
+ "PosiMatuirityDate": "2026-12-31T00:00:00",
+ "PosiDividendIncome": 0.0,
+ "PosiTradingFeePending": 200.000000,
+ "InterestDirection": 0,
+ "InterestRateDefault": 0.0,
+ "FloatRate": 0.0,
+ "FloatRateUnderlyingCode": null,
+ "InterestMode": 0,
+ "InterestModeStr": "Unknown",
+ "InterestType": 0,
+ "InterestPrincipalFix": 0.0,
+ "InterestSwapInterval": null,
+ "InterestFeePending": 0.0,
+ "InterestAmount": 0.0,
+ "IsInitial": true,
+ "IsAnnualized": false,
+ "HappenDate": null,
+ "Currency": "CNY",
+ "PosiNumber": "GLMS-20260105-0007-35148",
+ "UnderlyingInstrumentType": "TBonds",
+ "InitYtm": 0.025000,
+ "Invalid": false,
+ "interest_rest_days": 7,
+ "interest_rule": null,
+ "SwapIntervalList": [],
+ "Obervation": null,
+ "PositionIdPadding": "00000000",
+ "id": 35148,
+ "EncryptId": "bwG1iqm2wVDuqrh3JW4jCg",
+ "OptId": 164,
+ "OptName": "唐善洁",
+ "OptTime": "2026-07-01T21:20:32"
+ },
+ "PreSwapEod": {
+ "ValueDate": "2026-03-02T00:00:00",
+ "ClientId": 43,
+ "SwapTradeId": 1924,
+ "PositionId": 35148,
+ "PosiDirection": 2,
+ "PosiDirectionStr": "支付",
+ "PositionType": 1,
+ "PositionTypeStr": "B",
+ "UnderlyingCode": "230004.IB",
+ "UnderlyingName": null,
+ "ContractSize": 1.000000,
+ "CountRatio": 1.000000,
+ "PosiNetPrice": 1.01000400000,
+ "PosiGrossPrice": 1.01000000000,
+ "PosiQuantity": 50000000.000000,
+ "PosiNotionalValue": 50500000.000000,
+ "PosiTradingFee": 0.0,
+ "PosiStartDate": "2026-01-05T00:00:00",
+ "PosiMatuirityDate": "2026-12-31T00:00:00",
+ "UnderlyingPrice": 1.02000000000,
+ "UnderlyingMarketValue": 51000000.000000,
+ "TdPosiDividend": -90400.000000,
+ "PosiMtmPnL": -500000.000000,
+ "PosiDividendSum": -90400.000000,
+ "PosiFeePending": 200.000000,
+ "PosiProfitSum": -590200.000000,
+ "InterestDirection": 0,
+ "InterestMode": 0,
+ "InterestType": 0,
+ "InterestPrincipalFix": 0.0,
+ "InterestRateDefault": 0.0,
+ "InterestSwapInterval": null,
+ "InterestFeePending": 0.0,
+ "TdInterestPrincipal": 0.0,
+ "TdInterestRate": 0.0,
+ "TdInterestIncome": 0.0,
+ "TdInterestFee": 0.0,
+ "InterestIncomeSum": 0.0,
+ "InterestFeeSum": 0.0,
+ "InterestProfitSum": 0.0,
+ "SwapPositionValue": -590200.000000,
+ "TdCloseQty": 0.0,
+ "TdChangedQty": 0.0,
+ "TdCloseMtmPnl": 0.0,
+ "TdCloseDividend": 0.0,
+ "TdCloseFee": 0.0,
+ "TdCloseInterest": 0.0,
+ "TdCloseInterestFee": 0.0,
+ "RealizedMtmPnL": 0.0,
+ "RealizedDividend": 0.0,
+ "RealizedFee": 0.0,
+ "RealizedInterest": 0.0,
+ "RealizedInterestFee": 0.0,
+ "RealizedPnl": 0.0,
+ "TdCurrency": 1.000000,
+ "PosiStatus": 0,
+ "Invalid": false,
+ "FloatRate": 0.0,
+ "FloatRateUnderlyingCode": null,
+ "IsAnnualized": false,
+ "HappenDate": null,
+ "Currency": null,
+ "UnderlyingInstrumentType": "TBonds",
+ "PosiNetFeePrice": 1.00000400000,
+ "PosiNetNoFeePrice": 1.00000000000,
+ "VTradingFee": 400.000000,
+ "interest_rest_days": null,
+ "interest_rule": null,
+ "dv01": 0.0,
+ "PositionIdPadding": "00035148",
+ "id": 403417,
+ "EncryptId": "2LJcLhCf_19_0FHneAgs2Q",
+ "OptId": 164,
+ "OptName": "唐善洁",
+ "OptTime": "2026-07-02T00:17:55"
+ },
+ "SwapFlowEvents": [
+ {
+ "EventDate": "2026-03-03T00:00:00",
+ "SwapTradeId": 1924,
+ "SwapTradeNo": null,
+ "SwapPositionIdPadding": "00035148",
+ "EventType": 3,
+ "EventTypeStr": "互换",
+ "EventReason": "交易",
+ "PayDirection": 2,
+ "PayDirectionStr": "支付",
+ "PositionType": 1,
+ "PositionTypeStr": "B",
+ "UnderlyingCode": "230004.IB",
+ "MatuirityDate": null,
+ "Quantity": 0.0,
+ "PositionQty": 0.0,
+ "CountRatio": 0.0,
+ "ContractSize": 1.000000,
+ "PosiNetPrice": 0.0,
+ "PosiGrossPrice": 0.0,
+ "TradingAmount": 51005202.000000,
+ "TradingAmountAvg": 1.01000400000,
+ "TradingAmountFeeAvg": 1.01000400000,
+ "TradingFee": 0.0,
+ "TradingFeePending": 0.0,
+ "DividendPending": 0.0,
+ "MarkClosePnl": 0.0,
+ "DividendIn": -400.000000,
+ "CloseFee": 0.0,
+ "BeforeCloseFee": 0.0,
+ "PositionId": 35148,
+ "DataState": 100,
+ "ClientCashId": 0,
+ "InterestDirection": 0,
+ "InterestDirectionStr": "",
+ "InterestMode": 0,
+ "UnderlyingInstrumentType": "TBonds",
+ "InterestModeStr": "",
+ "InterestPrincipal": 0.0,
+ "InterestRate": 0.0,
+ "InterestSwapInterval": null,
+ "InterestAmount": 0.0,
+ "TdInterestAmount": 0.0,
+ "InterestFee": 0.0,
+ "InterestClosePnL": 0.0,
+ "EventId": 20929,
+ "ClientId": 43,
+ "FloatRate": null,
+ "PayDate": "2026-03-03T00:00:00",
+ "TradingAmountNetFeeAvg": 1.00000400000,
+ "TradingAmountNetAvg": 1.00000000000,
+ "UnwindDate": "2026-03-03T00:00:00",
+ "OptLog": null,
+ "SwapIntervalList": [],
+ "FloatPnlSum": -400.000000,
+ "InitYtm": null,
+ "id": 16219,
+ "EncryptId": "63o4MwWpLrn3ImiMTmCuXQ",
+ "OptId": 0,
+ "OptName": null,
+ "OptTime": "0001-01-01T00:00:00"
+ }
+ ]
+ }
}
\ No newline at end of file
diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
index e2864304..454b5a5c 100644
--- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
+++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs
@@ -1624,15 +1624,11 @@ namespace YLErp.Modules.SwapModule
curretEod.RealizedDividend = curretEod.RealizedDividend + curretEod.TdCloseDividend;
- // 分红与互换解耦:持仓>0时从起始日重算待实现分红,不再受互换事件影响
- // 修改,互换事件会影响待实现的分红的,现在要算上
+ // 分红与互换解耦:持仓>0时待实现分红用递增模式(前日+当天新计-当天实现),
+ // 与 CopyEodPosition 的逐天递增口径一致,避免从头重算的舍入累积差异。
if (curretEod.PosiQuantity > 0)
{
- //decimal tax = um.ValueAddedTax ?? 0;
- //BondPaymentService bondPaymentService = new BondPaymentService(UserInfo);
- //decimal totalPayment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, td.StartDate.Value, valueDate, (decimal)originNotional, shortRatio, directionRatio);
- //var totalInterest = totalPayment / (1 + tax) * (1 - tax);
- curretEod.PosiDividendSum = Math.Round(totalInterest,2) - curretEod.RealizedDividend;
+ curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend - curretEod.TdCloseDividend;
}
else
{