refactor(swap)+test: 删 GetInterests/CalcSwapInterests 死参数 needPrice/grossPrice;补工厂→接缝映射钉子

死参数收口(另一半):
- SwapDealService.GetInterests 删 needPrice/grossPrice(体内零消费,2026-08 验证);
  InitSwapDealInterest.needPrice 同为死参数一并删
- SwapEodPositionService.CalcSwapInterests 签名+转发同步;两个 EOD 生产调用点
  (SaveAutoEodInterestPosition/SaveEodInterestPositionCopy) 重排实参;
  CalcEodPostCloseSettleInterests/GetIntradayUnwindInterests 委托同步
- 14 个测试文件 ~44 处直调点机械更新(8 处 override 签名 + 36 处调用实参)
- 注意:EOD 编排链(DealInterests→Save*家族)的 grossPrice(期初不含费价)有真实用途,保留未动

新增钉子:CalcEodPostCloseSettleInterests 工厂→接缝参数映射测试——
CalcSwapInterestsCapture 捕获 stub 断言 EodPostCloseSettle 的完整转发契约
(posi=平仓后剩余/closePosi=平掉额/恒1/settment:false/orginPv 等 11 项)。
该段位置转发含三个相邻同型 decimal,编译器不查错位,此测试兜底。

验证:定向 241 测试通过(含 T0/T1 Excel 验证期望值、EntrySemantics 精确值钉子——
任何 decimal 错位即红);全量 903=145失败/746通过/12跳过,与基线逐位一致。
This commit is contained in:
hjhan
2026-08-14 16:57:56 +08:00
parent 018d7e777f
commit 4a3fee9292
20 changed files with 172 additions and 89 deletions
@@ -146,8 +146,8 @@ namespace YLErp.Modules.SwapModule
trade td, trade_extend tradeExtend, DateTime valueDate, DateTime unwindDate,
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose, bool needPrice,
decimal grossPrice, decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose,
decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
return positions.Select(p => new swap_flow_event
@@ -126,7 +126,7 @@ namespace YLErp.Modules.SwapModule
var interests = service.GetInterests(td, td.trade_extend, unwindDate, unwindDate,
new List<eod_swap_position>(), new List<swap_position> { position },
Principal, Principal, Principal, Principal, closePercent,
(int)SwapEventTypeEnum., false, false, Principal, Principal,
(int)SwapEventTypeEnum., false, Principal,
add: false, settment: false, newCalcLast: false);
Assert.AreEqual(1, interests.Count);
return interests[0];
@@ -357,7 +357,7 @@ namespace YLErp.Modules.SwapModule
var interests = ServiceByDate().GetInterests(td, td.trade_extend, unwindDate, unwindDate,
new List<eod_swap_position>(), new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum., false, false, Principal, Principal,
(int)SwapEventTypeEnum., false, Principal,
add: false, settment: false, newCalcLast: false);
Assert.AreEqual(1, interests.Count);
@@ -421,7 +421,7 @@ namespace YLErp.Modules.SwapModule
var result = service.GetInterests(td, td.trade_extend, resetDate, resetDate,
new List<eod_swap_position> { preEod }, new List<swap_position> { position },
remainingPrincipal, remainingPrincipal, 0m, remainingPrincipal, 1m,
(int)SwapEventTypeEnum., true, false, 0m, remainingPrincipal,
(int)SwapEventTypeEnum., true, remainingPrincipal,
add: false, settment: false, newCalcLast: false).Single();
var remainingInterest = previousInterest * remainingPrincipal / previousPrincipal;
@@ -467,7 +467,7 @@ namespace YLErp.Modules.SwapModule
var result = service.GetInterests(td, td.trade_extend, unwindDate, unwindDate,
new List<eod_swap_position> { preEod }, new List<swap_position> { position },
remainingPrincipal, remainingPrincipal, 0m, remainingPrincipal, 1m,
(int)SwapEventTypeEnum., false, false, 0m, remainingPrincipal,
(int)SwapEventTypeEnum., false, remainingPrincipal,
add: false, settment: false, newCalcLast: false).Single();
AssertDecimal(pendingInterest, result.InterestAmount,
@@ -65,8 +65,8 @@ namespace YLErp.Modules.SwapModule
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent,
int eventType, bool tdClose, bool needPrice,
decimal grossPrice, decimal orginPv,
int eventType, bool tdClose,
decimal orginPv,
bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
@@ -78,8 +78,8 @@ namespace YLErp.Modules.SwapModule
return (DealService ?? new SwapDealService(this)).GetInterests(td, tradeExtend, valueDate, unwindDate,
eodPositions, positions, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue,
closePosiNotionalValue, closePrecent, eventType, tdClose, needPrice,
grossPrice, orginPv, add, settment, newCalcLast, closeList);
closePosiNotionalValue, closePrecent, eventType, tdClose,
orginPv, add, settment, newCalcLast, closeList);
}
// public 包装:让测试能调用 protected 方法
@@ -1230,7 +1230,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, closeDate, closeDate,
new List<eod_swap_position> { previousEod }, new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 1m, orginPv,
(int)SwapEventTypeEnum., false, orginPv,
false, settment: false, newCalcLast: false, closeList: null).Single();
AssertDecimal(remainingNotional, result.InterestPrincipal,
@@ -1269,7 +1269,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, firstCloseDate, firstCloseDate,
new List<eod_swap_position>(), new List<swap_position> { position },
originalNotional, originalNotional, 0m, remainingNotional, 0.5m,
(int)SwapEventTypeEnum., false, false, 1m, originalNotional,
(int)SwapEventTypeEnum., false, originalNotional,
settment: false).Single();
var firstCloseCash = Math.Round(firstCloseInterest.InterestAmount, ConsGlobal.MoneyRound,
MidpointRounding.AwayFromZero);
@@ -1287,13 +1287,13 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, firstCloseDate, firstCloseDate,
new List<eod_swap_position>(), new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 1m, originalNotional,
(int)SwapEventTypeEnum., false, originalNotional,
settment: false).Single();
var replayAtFinalClose = dealService.GetInterests(
td, td.trade_extend, finalCloseDate, finalCloseDate,
new List<eod_swap_position>(), new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 1m, originalNotional,
(int)SwapEventTypeEnum., false, originalNotional,
settment: false).Single();
var expectedFinalInterest = firstCloseEod.InterestIncomeSum
+ replayAtFinalClose.InterestAmount - replayAtPreviousEod.InterestAmount;
@@ -1307,7 +1307,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, finalCloseDate, finalCloseDate,
new List<eod_swap_position> { firstCloseEod }, new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 1m, originalNotional,
(int)SwapEventTypeEnum., false, originalNotional,
settment: false).Single();
var finalCloseCash = Math.Round(finalCloseInterest.InterestAmount, ConsGlobal.MoneyRound,
MidpointRounding.AwayFromZero);
@@ -1435,7 +1435,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, partialCloseDate, partialCloseDate,
new List<eod_swap_position> { previousEod }, new List<swap_position> { position },
notional, notional, 0m, partialNotional, partialPercent,
(int)SwapEventTypeEnum., false, false, 0m, notional,
(int)SwapEventTypeEnum., false, notional,
settment: false).Single();
AssertDecimal(84090.95m, Math.Round(partial.InterestAmount, ConsGlobal.MoneyRound,
MidpointRounding.AwayFromZero),
@@ -1445,7 +1445,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, maturityDate, maturityDate,
new List<eod_swap_position>(), new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 0m, remainingNotional,
(int)SwapEventTypeEnum., false, remainingNotional,
settment: false, newCalcLast: true).Single();
AssertDecimal(268428.73m, Math.Round(final.InterestAmount, ConsGlobal.MoneyRound,
MidpointRounding.AwayFromZero),
@@ -1576,7 +1576,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, intermediateDate, intermediateDate,
new List<eod_swap_position> { partialEod }, new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 0m, originalNotional,
(int)SwapEventTypeEnum., false, originalNotional,
settment: false, newCalcLast: true).Single();
Assert.IsTrue(Math.Abs(259348.386714765m - intermediateInterest.InterestAmount) <= 0.01m,
$"5/18 复利平仓应承接 5/11 日终剩余本金的累计利息 Expected approximately 259348.386714765, Actual: {intermediateInterest.InterestAmount}");
@@ -1707,7 +1707,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, intermediateDate, intermediateDate,
new List<eod_swap_position> { partialEod }, new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 0m, originalNotional,
(int)SwapEventTypeEnum., false, originalNotional,
settment: false, newCalcLast: true).Single();
Assert.IsTrue(Math.Abs(259348.386714765m - intermediateInterest.InterestAmount) <= 0.01m,
$"0005 5/18 复利应承接部分平仓后的累计利息 Expected approximately 259348.386714765, Actual: {intermediateInterest.InterestAmount}");
@@ -1740,7 +1740,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, finalCloseDate, finalCloseDate,
new List<eod_swap_position> { intermediateEod }, new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 0m, originalNotional,
(int)SwapEventTypeEnum., false, originalNotional,
settment: false, newCalcLast: false).Single();
AssertDecimal(expectedFinalInterest, finalInterest.InterestAmount,
"0005 最终全平重放时,历史5/18终点必须包含当日利息后再做差额");
@@ -1830,7 +1830,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, finalCloseDate, finalCloseDate,
new List<eod_swap_position> { previousEod }, new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 0m, remainingNotional,
(int)SwapEventTypeEnum., false, remainingNotional,
settment: false).Single();
AssertDecimal(expectedInterest, result.InterestAmount,
@@ -1928,7 +1928,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, partialCloseDate, partialCloseDate,
new List<eod_swap_position> { preCloseEod }, new List<swap_position> { position },
originalNotional, originalNotional, 0m, partialNotional, partialClosePercent,
(int)SwapEventTypeEnum., false, false, 1m, originalNotional,
(int)SwapEventTypeEnum., false, originalNotional,
settment: false).Single();
AssertExcelMoney(scenario.ExpectedPartialInterest, partialInterest.InterestAmount,
$"{scenario.TradeNumber} 5/11 部分平仓利息应匹配 Excel BL 列");
@@ -1977,7 +1977,7 @@ namespace YLErp.Modules.SwapModule
td, td.trade_extend, finalCloseDate, finalCloseDate,
new List<eod_swap_position> { finalPreEod }, new List<swap_position> { position },
remainingNotional, remainingNotional, 0m, remainingNotional, 1m,
(int)SwapEventTypeEnum., false, false, 1m, remainingNotional,
(int)SwapEventTypeEnum., false, remainingNotional,
settment: false).Single();
AssertExcelMoney(scenario.ExpectedFinalInterest, finalInterest.InterestAmount,
$"{scenario.TradeNumber} 5/19 全部平仓利息应匹配 Excel BN 列");
@@ -212,7 +212,7 @@ namespace YLErp.Modules.SwapModule
Notional, Notional, Notional, Notional, // posiNotional / long / short / closePosiNotional
1m, // closePercent
(int)SwapEventTypeEnum.,
false, false, 0m, Notional, // tdClose / needPrice / grossPrice / orginPv
false, Notional, // tdClose / orginPv
false, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, interests.Count);
return interests[0];
@@ -147,7 +147,7 @@ namespace YLErp.Modules.SwapModule
var eodPostClose = CreateService().GetInterests(td, td.trade_extend, UnwindDate, UnwindDate,
eodPositions, positions, Remaining, Remaining, 0m, Closed, 1m,
(int)SwapEventTypeEnum., tdClose: false, needPrice: true, grossPrice: 1m, orginPv: PreClose,
(int)SwapEventTypeEnum., tdClose: false, orginPv: PreClose,
add: true, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, intraday.Count);
@@ -182,7 +182,7 @@ namespace YLErp.Modules.SwapModule
var eodPostClose = CreateService().GetInterests(td, td.trade_extend, UnwindDate, UnwindDate,
eodPositions, positions, Remaining, Remaining, 0m, Closed, 1m,
(int)SwapEventTypeEnum., tdClose: false, needPrice: true, grossPrice: 1m, orginPv: PreClose,
(int)SwapEventTypeEnum., tdClose: false, orginPv: PreClose,
add: true, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, intraday.Count);
@@ -210,7 +210,7 @@ namespace YLErp.Modules.SwapModule
// 全平:剩余=0,平掉=全部 1000
var result = CreateService().GetInterests(td, td.trade_extend, UnwindDate, UnwindDate,
eodPositions, positions, 0m, 0m, 0m, PreClose, 1m,
(int)SwapEventTypeEnum., tdClose: false, needPrice: true, grossPrice: 1m, orginPv: PreClose,
(int)SwapEventTypeEnum., tdClose: false, orginPv: PreClose,
add: true, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, result.Count);
@@ -218,5 +218,90 @@ namespace YLErp.Modules.SwapModule
Assert.IsTrue(result[0].InterestAmount != 0m,
"mode9 全平时 posi=0,兜底必须以 closePosiNotionalValue(实际平掉额) 为结息本金,结息额非零(兜底钉子)");
}
#region CalcEodPostCloseSettleInterests
/// <summary>
/// 参数捕获 stub:拦下 CalcSwapInterests 的全部实参,不触库、不真算。
/// </summary>
private sealed class CalcSwapInterestsCapture : TestableSwapEodPositionService
{
public CalcSwapInterestsCapture() : base(nameof(GetInterestsEntrySemanticsTest)) { }
public List<swap_flow_event> CapturedCloseList = null;
public bool CapturedTdClose;
public int CapturedEventType;
public decimal CapturedPosiNotional;
public decimal CapturedClosePosiNotional;
public decimal CapturedClosePercent;
public decimal CapturedOrginPv;
public bool CapturedAdd;
public bool CapturedSettment;
public bool CapturedNewCalcLast;
public int CallCount;
protected override List<swap_flow_event> CalcSwapInterests(
trade td, trade_extend tradeExtend,
DateTime valueDate, DateTime unwindDate,
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent,
int eventType, bool tdClose,
decimal orginPv,
bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
CallCount++;
CapturedTdClose = tdClose; CapturedEventType = eventType;
CapturedPosiNotional = posiNotionalValue; CapturedClosePosiNotional = closePosiNotionalValue;
CapturedClosePercent = closePrecent; CapturedOrginPv = orginPv;
CapturedAdd = add; CapturedSettment = settment; CapturedNewCalcLast = newCalcLast;
CapturedCloseList = closeList;
return new List<swap_flow_event>();
}
public List<swap_flow_event> ExposedEodPostCloseSettle(InterestCalcRequest req)
=> CalcEodPostCloseSettleInterests(req);
}
/// <summary>
/// 钉死 InterestCalcRequest.EodPostCloseSettle 工厂 → CalcEodPostCloseSettleInterests →
/// CalcSwapInterests 的位置参数转发契约。这段转发是位置传参最易错位的环节
/// posiNotionalValue/closePosiNotionalValue/orginPv 三个相邻同型 decimal,编译器不查错位),
/// 任何映射改动(含将来删 needPrice/grossPrice 死参数)都必须保持本断言绿。
/// </summary>
[TestMethod]
public void EOD平仓后收盘_工厂到接缝_参数映射钉死()
{
var td = CreateTrade();
var position = CreatePosition(InterestModeEnum., InterestTypeEnum.);
var preEod = CreatePreEod(interestSum: 0.05m, principal: PreClose);
var positions = new List<swap_position> { position };
var stub = new CalcSwapInterestsCapture();
var req = InterestCalcRequest.EodPostCloseSettle(
td, td.trade_extend, UnwindDate, UnwindDate,
new List<eod_swap_position> { preEod }, positions,
remainingNotionalAfterClose: Remaining, remainingLongNotional: Remaining, remainingShortNotional: 0m,
closedNotional: Closed,
eventType: (int)SwapEventTypeEnum., tdClose: false,
orginPv: PreClose, add: true, newCalcLast: false);
stub.ExposedEodPostCloseSettle(req);
Assert.AreEqual(1, stub.CallCount, "默认实现应恰好调用一次 CalcSwapInterests(虚接缝兼容既有测试替身)");
Assert.AreEqual(Remaining, stub.CapturedPosiNotional, "posiNotionalValue 位 = 平仓后剩余(700)——语义核心,错位即红");
Assert.AreEqual(Closed, stub.CapturedClosePosiNotional, "closePosiNotionalValue 位 = 实际平掉额(300)");
Assert.AreEqual(1m, stub.CapturedClosePercent, "closePrecent 恒 1(全额结息)");
Assert.AreEqual((int)SwapEventTypeEnum., stub.CapturedEventType);
Assert.IsFalse(stub.CapturedTdClose);
Assert.AreEqual(PreClose, stub.CapturedOrginPv, "orginPv 位 = 上一日终本金——与相邻 decimal 最易错位处");
Assert.IsTrue(stub.CapturedAdd);
Assert.IsFalse(stub.CapturedSettment, "settment=false:走盘中重放算法(EOD平仓后收盘复用重放)");
Assert.IsFalse(stub.CapturedNewCalcLast);
Assert.IsNull(stub.CapturedCloseList, "该场景不传 closeList");
}
#endregion
}
}
@@ -230,7 +230,7 @@ namespace YLErp.Modules.SwapModule
eodPositions, new List<swap_position> { position },
posiNotional, posiNotional, posiNotional, posiNotional, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
}
@@ -246,7 +246,7 @@ namespace YLErp.Modules.SwapModule
eodPositions, new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum.,
false, false, 0, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
false, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
}
@@ -265,7 +265,7 @@ namespace YLErp.Modules.SwapModule
eodPositions, new List<swap_position> { position },
posiNotional, posiNotional, posiNotional, posiNotional, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
}
@@ -281,7 +281,7 @@ namespace YLErp.Modules.SwapModule
eodPositions, new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum.,
false, false, 0, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
false, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
}
@@ -324,7 +324,7 @@ namespace YLErp.Modules.SwapModule
new List<swap_position> { position },
posiNotional, posiNotional, posiNotional, posiNotional, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
@@ -348,7 +348,7 @@ namespace YLErp.Modules.SwapModule
new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum.,
false, false, 0, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
false, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
@@ -373,7 +373,7 @@ namespace YLErp.Modules.SwapModule
new List<swap_position> { position },
Principal, Principal, Principal, Principal, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, Principal, false, settment: false, newCalcLast: false, closeList: closeList);
false, Principal, false, settment: false, newCalcLast: false, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
@@ -409,7 +409,7 @@ namespace YLErp.Modules.SwapModule
new List<swap_position> { position },
posiNotional, posiNotional, posiNotional, posiNotional, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
@@ -432,7 +432,7 @@ namespace YLErp.Modules.SwapModule
new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum.,
false, false, 0, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
false, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
@@ -1718,7 +1718,7 @@ namespace YLErp.Modules.SwapModule
new List<swap_position> { position },
posiNotional, posiNotional, posiNotional, posiNotional, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
@@ -1749,7 +1749,7 @@ namespace YLErp.Modules.SwapModule
new List<swap_position> { position },
posiNotional, posiNotional, posiNotional, posiNotional, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
@@ -100,8 +100,8 @@ namespace UnitTestProject.Modules.SwapModule.Margin
oldList = svc.GetInterests(td, extend, valueDate, valueDate,
preEods, marginPositions,
0m, 0m, 0m, 0m, 1.0m,
(int)SwapEventTypeEnum., tdClose: false, needPrice: false,
grossPrice: 0m, orginPv: 0m,
(int)SwapEventTypeEnum., tdClose: false,
orginPv: 0m,
add: false, settment: true, newCalcLast: false, closeList: null);
}
catch (Exception ex)
@@ -120,7 +120,7 @@ namespace YLErp.Modules.SwapModule
var interests = service.GetInterests(td, td.trade_extend, unwindDate, unwindDate,
new List<eod_swap_position>(), new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum., false, false, Principal, Principal,
(int)SwapEventTypeEnum., false, Principal,
add: false, settment: false, newCalcLast: false);
return interests.Count > 0 ? interests[0].InterestAmount : 0m;
}
@@ -143,7 +143,7 @@ namespace YLErp.Modules.SwapModule
var interests = service.GetInterests(td, td.trade_extend, valueDate, valueDate,
new List<eod_swap_position> { preEod }, new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum., false, false, Principal, Principal,
(int)SwapEventTypeEnum., false, Principal,
add: false, settment: true, newCalcLast: false);
if (interests.Count == 0) return (0m, 0m);
return (interests[0].TdInterestAmount, interests[0].InterestAmount);
@@ -314,7 +314,7 @@ namespace YLErp.Modules.SwapModule
var i5 = svc5.GetInterests(td, td.trade_extend, day5, day5,
new List<eod_swap_position>(), new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum., false, false, Principal, Principal,
(int)SwapEventTypeEnum., false, Principal,
settment: false);
decimal swap1 = i5.Count > 0 ? i5[0].InterestAmount : 0m;
@@ -323,7 +323,7 @@ namespace YLErp.Modules.SwapModule
var i10 = svc10.GetInterests(td, td.trade_extend, day10, day10,
new List<eod_swap_position>(), new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum., false, false, Principal, Principal,
(int)SwapEventTypeEnum., false, Principal,
settment: false);
decimal swap2 = i10.Count > 0 ? i10[0].InterestAmount : 0m;
@@ -333,7 +333,7 @@ namespace YLErp.Modules.SwapModule
var i15 = svc15.GetInterests(td, td.trade_extend, day15, day15,
new List<eod_swap_position>(), new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum., false, false, Principal, Principal,
(int)SwapEventTypeEnum., false, Principal,
settment: false);
decimal finalUnwind = i15.Count > 0 ? i15[0].InterestAmount : 0m;
@@ -363,7 +363,7 @@ namespace YLErp.Modules.SwapModule
var interests = svc.GetInterests(td, td.trade_extend, unwindDate, unwindDate,
new List<eod_swap_position>(), new List<swap_position> { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum., false, false, Principal, Principal,
(int)SwapEventTypeEnum., false, Principal,
settment: false);
return interests.Count > 0 ? interests[0].InterestAmount : 0m;
}
@@ -104,7 +104,7 @@ namespace YLErp.Modules.SwapModule
var eod = new List<eod_swap_position> { MakeEod(valueDate, PrepayRemaining, 0m) };
var fe = _svc.GetInterests(td, td.trade_extend, FullDate, FullDate, eod,
new List<swap_position> { pos }, PrepayFix, PrepayFix, PrepayFix, PrepayFix, 1m,
(int)SwapEventTypeEnum., false, false, 0, PrepayFix, false,
(int)SwapEventTypeEnum., false, PrepayFix, false,
settment: false, newCalcLast: calcLast, closeList: null)[0];
var trace = SwapCalcTrace.Dump();
Console.WriteLine(trace);
@@ -102,8 +102,8 @@ namespace YLErp.Modules.SwapModule
trade td, trade_extend tradeExtend, DateTime valueDate, DateTime unwindDate,
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose, bool needPrice,
decimal grossPrice, decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose,
decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
return positions.Select(p => new swap_flow_event
@@ -82,7 +82,7 @@ namespace YLErp.Modules.SwapModule
new List<eod_swap_position> { previousEod }, new List<swap_position> { position },
closeCase.RemainingNotional, closeCase.RemainingNotional, 0m,
closeCase.RemainingNotional, 1m, (int)SwapEventTypeEnum.,
false, false, 0m,
false,
closeCase.InterestType == 0 ? closeCase.RemainingNotional : closeCase.OriginalNotional,
add: false, settment: false, newCalcLast: false).Single();
@@ -57,16 +57,16 @@ namespace UnitTestProject.Modules.SwapModule
trade td, trade_extend tradeExtend, DateTime valueDate, DateTime unwindDate,
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose, bool needPrice,
decimal grossPrice, decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose,
decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
var svc = new StubSwapDealService(
new OptUserInfo(0, nameof(SwapInterestScenario1And2Test), OptUserFrom.UnitTest), _floatRates);
return svc.GetInterests(td, tradeExtend, valueDate, unwindDate,
eodPositions, positions, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue,
closePosiNotionalValue, closePrecent, eventType, tdClose, needPrice,
grossPrice, orginPv, add, settment, newCalcLast, closeList);
closePosiNotionalValue, closePrecent, eventType, tdClose,
orginPv, add, settment, newCalcLast, closeList);
}
public eod_swap_position ExecuteClose(trade td, swap_position position, DateTime valueDate,
@@ -213,7 +213,7 @@ namespace UnitTestProject.Modules.SwapModule
prevEod, new List<swap_position> { position },
closeNotional, closeNotional, 0m, closeNotional, 1m,
(int)SwapEventTypeEnum.,
false, false, 0m, closeNotional, false, settment: false, newCalcLast: isMaturity);
false, closeNotional, false, settment: false, newCalcLast: isMaturity);
Assert.AreEqual(1, interests.Count);
return interests[0];
}
@@ -179,16 +179,16 @@ namespace UnitTestProject.Modules.SwapModule
trade td, trade_extend tradeExtend, DateTime valueDate, DateTime unwindDate,
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose, bool needPrice,
decimal grossPrice, decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose,
decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
var svc = new RealSwapDealService(
new OptUserInfo(0, nameof(SwapInterestScenario3And4FloatingTest), OptUserFrom.UnitTest), _floatRates, FlowEvents);
var interests = svc.GetInterests(td, tradeExtend, valueDate, unwindDate,
eodPositions, positions, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue,
closePosiNotionalValue, closePrecent, eventType, tdClose, needPrice,
grossPrice, orginPv, add, settment, newCalcLast, closeList);
closePosiNotionalValue, closePrecent, eventType, tdClose,
orginPv, add, settment, newCalcLast, closeList);
// 捕获 base InterestPrincipal= EOD:1406 行赋给 TdInterestPrincipal 的值,反推前),供 TdInterestPrincipal 断言镜像分叉。
LastBaseInterestPrincipal = interests.Count > 0 ? interests[0].InterestPrincipal : 0m;
return interests;
@@ -396,7 +396,7 @@ namespace UnitTestProject.Modules.SwapModule
prevEod, new List<swap_position> { position },
closeNotional, closeNotional, 0m, closeNotional, 1m,
(int)SwapEventTypeEnum.,
false, false, 0m, closeNotional, false, settment: false, newCalcLast: isMaturity);
false, closeNotional, false, settment: false, newCalcLast: isMaturity);
Assert.AreEqual(1, interests.Count);
return interests[0];
}
@@ -80,15 +80,15 @@ namespace YLErp.Modules.SwapModule
trade td, trade_extend tradeExtend, DateTime valueDate, DateTime unwindDate,
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose, bool needPrice,
decimal grossPrice, decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose,
decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
LastInterestCalculationPositions = positions;
return base.CalcSwapInterests(td, tradeExtend, valueDate, unwindDate,
eodPositions, positions, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue,
closePosiNotionalValue, closePrecent, eventType, tdClose, needPrice,
grossPrice, orginPv, add, settment, newCalcLast, closeList);
closePosiNotionalValue, closePrecent, eventType, tdClose,
orginPv, add, settment, newCalcLast, closeList);
}
public void ExecuteSwapPositionCompose(DateTime settleDate, DateTime preSettleDate)
@@ -60,16 +60,16 @@ namespace UnitTestProject.Modules.SwapModule
trade td, trade_extend tradeExtend, DateTime valueDate, DateTime unwindDate,
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose, bool needPrice,
decimal grossPrice, decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
decimal closePosiNotionalValue, decimal closePrecent, int eventType, bool tdClose,
decimal orginPv, bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
var svc = new StubSwapDealService(
new OptUserInfo(0, nameof(SwapSingleTradeVerificationTest), OptUserFrom.UnitTest), _floatRates);
return svc.GetInterests(td, tradeExtend, valueDate, unwindDate,
eodPositions, positions, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue,
closePosiNotionalValue, closePrecent, eventType, tdClose, needPrice,
grossPrice, orginPv, add, settment, newCalcLast, closeList);
closePosiNotionalValue, closePrecent, eventType, tdClose,
orginPv, add, settment, newCalcLast, closeList);
}
public eod_swap_position ExecuteClose(trade td, swap_position position, DateTime valueDate,
@@ -215,7 +215,7 @@ namespace UnitTestProject.Modules.SwapModule
prevEod, new List<swap_position> { position },
closeNotional, closeNotional, 0m, closeNotional, 1m,
(int)SwapEventTypeEnum.,
false, false, 0m, closeNotional, false, settment: false, newCalcLast: isMaturity);
false, closeNotional, false, settment: false, newCalcLast: isMaturity);
Assert.AreEqual(1, interests.Count);
return interests[0];
}
@@ -95,7 +95,7 @@ namespace YLErp.Modules.SwapModule
eodPositions, new List<swap_position> { position },
UnderlyingNotional, UnderlyingNotional, UnderlyingNotional, UnderlyingNotional, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, UnderlyingNotional, false, settment: false, newCalcLast: false, closeList: null);
false, UnderlyingNotional, false, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, interests.Count, "预付金腿应生成 1 条 flow_event");
return interests[0];
}
@@ -113,7 +113,7 @@ namespace YLErp.Modules.SwapModule
eodPositions, new List<swap_position> { position },
notional, notional, notional, notional, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, notional, false, settment: false, newCalcLast: false, closeList: null);
false, notional, false, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, interests.Count, "预付金腿应生成 1 条 flow_event");
return interests[0];
}
@@ -281,7 +281,7 @@ namespace YLErp.Modules.SwapModule
eod, new List<swap_position> { position },
fix, fix, fix, fix, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, fix, false, settment: false, newCalcLast: false, closeList: null);
false, fix, false, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, interests.Count, "预付金腿应生成 1 条 flow_event");
return interests[0];
}
@@ -375,7 +375,7 @@ namespace YLErp.Modules.SwapModule
eod, new List<swap_position> { position },
notional, notional, notional, notional * closePercent, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, notional, false, settment: false, newCalcLast: false, closeList: null);
false, notional, false, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, interests.Count, "非预付金腿应生成 1 条 flow_event");
return interests[0];
}
@@ -490,7 +490,7 @@ namespace YLErp.Modules.SwapModule
eodPos, new List<swap_position> { position },
baseP, baseP, baseP, baseP * closePercent, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, baseP, false, settment: eodPath, newCalcLast: false, closeList: null);
false, baseP, false, settment: eodPath, newCalcLast: false, closeList: null);
Assert.AreEqual(1, interests.Count, $"mode={mode} 应生成 1 条 flow_event");
return interests[0];
}
@@ -123,7 +123,7 @@ namespace YLErp.Modules.SwapModule
MakeLastEod(), new List<swap_position> { position },
currentNotional, currentNotional, currentNotional, currentNotional * closePercent, closePercent,
(int)SwapEventTypeEnum.,
false, false, 0, N, false, settment: false, newCalcLast: false, closeList: null);
false, N, false, settment: false, newCalcLast: false, closeList: null);
Assert.AreEqual(1, interests.Count, "标的期初全价腿应生成 1 条 flow_event");
return interests[0];
}
@@ -627,7 +627,7 @@ namespace YLErp.Modules.SwapModule
public List<swap_flow_event> GetIntradayUnwindInterests(InterestCalcRequest req)
=> GetInterests(req.Td, req.TradeExtend, req.ValueDate, req.UnwindDate, req.EodPositions, req.Positions,
req.PosiNotionalValue, req.PosiLongNotionalValue, req.PosiShortNotionalValue, req.ClosePosiNotionalValue,
req.ClosePercent, req.EventType, req.TdClose, needPrice: false, grossPrice: 0m,
req.ClosePercent, req.EventType, req.TdClose,
req.OrginPv, req.Add, settment: false, req.NewCalcLast, req.CloseList);
public List<swap_flow_event> GetInterests(
@@ -644,8 +644,6 @@ namespace YLErp.Modules.SwapModule
decimal closePrecent,
int eventType,
bool tdClose,
bool needPrice,
decimal grossPrice,
decimal orginPv,
bool add = false,
bool settment = true,
@@ -1110,7 +1108,7 @@ namespace YLErp.Modules.SwapModule
}
return InitSwapDealInterest(td, valueDate, endDate, rate, position, add, swap, posiPrincipal,
closePrincipal, closePercent, annualDays, eventType, preEod, false,
closePrincipal, closePercent, annualDays, eventType, preEod,
orginPv, calcFirst, calcLast, consumedInterest);
}
/// <summary>
@@ -1165,7 +1163,6 @@ namespace YLErp.Modules.SwapModule
int annualDays,
int eventType,
eod_swap_position preEodPosition,
bool needPrice,
decimal orginPv,
bool calcFirst,
bool calcLast,
@@ -82,8 +82,9 @@ namespace YLErp.Modules.SwapModule
}
/// <summary>
/// 计算利息腿利息明细(生产: new SwapDealService(this).GetInterests;测试: 用StubSwapDealService内存算)
/// 计算利息腿利息明细(生产: new SwapDealService(this).GetInterests;测试: 用StubSwapDealService内存算)
/// 参数与 SwapDealService.GetInterests 完全一致,保证行为不变。
/// needPrice/grossPrice 死参数已随 2026-08 收口删除,两侧同步。)
/// </summary>
protected virtual List<swap_flow_event> CalcSwapInterests(
trade td, trade_extend tradeExtend,
@@ -91,15 +92,15 @@ namespace YLErp.Modules.SwapModule
List<eod_swap_position> eodPositions, List<swap_position> positions,
decimal posiNotionalValue, decimal posiLongNotionalValue, decimal posiShortNotionalValue,
decimal closePosiNotionalValue, decimal closePrecent,
int eventType, bool tdClose, bool needPrice,
decimal grossPrice, decimal orginPv,
int eventType, bool tdClose,
decimal orginPv,
bool add = false, bool settment = true, bool newCalcLast = false,
List<swap_flow_event> closeList = null)
{
return new SwapDealService(this).GetInterests(td, tradeExtend, valueDate, unwindDate,
eodPositions, positions, posiNotionalValue, posiLongNotionalValue, posiShortNotionalValue,
closePosiNotionalValue, closePrecent, eventType, tdClose, needPrice,
grossPrice, orginPv, add, settment, newCalcLast, closeList);
closePosiNotionalValue, closePrecent, eventType, tdClose,
orginPv, add, settment, newCalcLast, closeList);
}
/// <summary>
@@ -112,8 +113,8 @@ namespace YLErp.Modules.SwapModule
protected virtual List<swap_flow_event> CalcEodPostCloseSettleInterests(InterestCalcRequest req)
=> CalcSwapInterests(req.Td, req.TradeExtend, req.ValueDate, req.UnwindDate, req.EodPositions, req.Positions,
req.PosiNotionalValue, req.PosiLongNotionalValue, req.PosiShortNotionalValue,
req.ClosePosiNotionalValue, req.ClosePercent, req.EventType, req.TdClose, needPrice: true,
grossPrice: 0m, req.OrginPv, req.Add, settment: false, req.NewCalcLast, req.CloseList);
req.ClosePosiNotionalValue, req.ClosePercent, req.EventType, req.TdClose,
req.OrginPv, req.Add, settment: false, req.NewCalcLast, req.CloseList);
// FindTrade 已上提到基类 SwapTradeBaseService(三子类实现一致,消除重复)
@@ -1158,7 +1159,7 @@ namespace YLErp.Modules.SwapModule
{
orginPv = eodPayPosition.InterestPrincipalFix;
}
var interests = CalcSwapInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNotional, posiShortNational, posiNotionalValue, closePercent, (int)SwapEventTypeEnum., false, true, grossPrice, orginPv, true);
var interests = CalcSwapInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNotional, posiShortNational, posiNotionalValue, closePercent, (int)SwapEventTypeEnum., false, orginPv, true);
decimal interestAmountBeforeSettlement = interests.Sum(x => x.InterestAmount);
decimal tdInterestAmount = interests.Sum(x => x.TdInterestAmount);
@@ -1576,7 +1577,7 @@ namespace YLErp.Modules.SwapModule
{
preEodPositions.Add(eodPayPosition);
}
var interests = CalcSwapInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNational, posiShortNational, posiNotionalValue, closePercent, 0, false, needPrice, grossPrice, orginPv);
var interests = CalcSwapInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNational, posiShortNational, posiNotionalValue, closePercent, 0, false, orginPv);
UpdateDbOption(newEodPayPosition);
newEodPayPosition.PosiStatus = 0;