refactor(swap): InterestCalcRequest 参数对象——GetInterests 双显式入口收敛为单参数
新增 InterestCalcRequest(SwapModule 根): - 承载 GetInterests 全部有效入参(needPrice/grossPrice 死参数不承载),私有构造; - 仅两个场景工厂可构造:IntradayUnwind(平仓前剩余/实际平掉额/B语义比例)、 EodPostCloseSettle(平仓后剩余/实际平掉额/恒1全额结息)——工厂形参名即场景语义, 物理上防止两套名义本金语义混传(6fdc7d80 错账的温床); - GetIntradayUnwindInterests / CalcEodPostCloseSettleInterests 签名收敛为单参数 req, 生产调用点(GetUnwindInterests / SaveAutoEodWithCloseInterestPosition)改工厂构造; - 原 20 参 GetInterests / 19 参 CalcSwapInterests 保留为底层实现与测试兼容层(十余处测试直调,不动)。 验证:定向 140 测试通过;全量 902(+3 字符化测试)= 145失败/745通过/12跳过, 与基线逐位一致,零回归。
This commit is contained in:
@@ -140,9 +140,10 @@ namespace YLErp.Modules.SwapModule
|
||||
var eodPositions = new List<eod_swap_position> { preEod };
|
||||
var positions = new List<swap_position> { position };
|
||||
|
||||
var intraday = CreateService().GetIntradayUnwindInterests(td, td.trade_extend, UnwindDate, UnwindDate,
|
||||
eodPositions, positions, PreClose, PreClose, 0m, Closed, ClosePercent,
|
||||
(int)SwapEventTypeEnum.平仓, tdClose: true, orginPv: PreClose, add: true, newCalcLast: false, closeList: null);
|
||||
var intraday = CreateService().GetIntradayUnwindInterests(InterestCalcRequest.IntradayUnwind(
|
||||
td, td.trade_extend, UnwindDate, UnwindDate, eodPositions, positions,
|
||||
PreClose, PreClose, 0m, Closed, ClosePercent,
|
||||
(int)SwapEventTypeEnum.平仓, tdClose: true, orginPv: PreClose, add: true, newCalcLast: false, closeList: null));
|
||||
|
||||
var eodPostClose = CreateService().GetInterests(td, td.trade_extend, UnwindDate, UnwindDate,
|
||||
eodPositions, positions, Remaining, Remaining, 0m, Closed, 1m,
|
||||
@@ -174,9 +175,10 @@ namespace YLErp.Modules.SwapModule
|
||||
var eodPositions = new List<eod_swap_position> { preEod };
|
||||
var positions = new List<swap_position> { position };
|
||||
|
||||
var intraday = CreateService().GetIntradayUnwindInterests(td, td.trade_extend, UnwindDate, UnwindDate,
|
||||
eodPositions, positions, PreClose, PreClose, 0m, Closed, ClosePercent,
|
||||
(int)SwapEventTypeEnum.平仓, tdClose: true, orginPv: PreClose, add: true, newCalcLast: false, closeList: null);
|
||||
var intraday = CreateService().GetIntradayUnwindInterests(InterestCalcRequest.IntradayUnwind(
|
||||
td, td.trade_extend, UnwindDate, UnwindDate, eodPositions, positions,
|
||||
PreClose, PreClose, 0m, Closed, ClosePercent,
|
||||
(int)SwapEventTypeEnum.平仓, tdClose: true, orginPv: PreClose, add: true, newCalcLast: false, closeList: null));
|
||||
|
||||
var eodPostClose = CreateService().GetInterests(td, td.trade_extend, UnwindDate, UnwindDate,
|
||||
eodPositions, positions, Remaining, Remaining, 0m, Closed, 1m,
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
namespace YLErp.Modules.SwapModule;
|
||||
|
||||
/// <summary>
|
||||
/// GetInterests 参数对象(2026-08 参数显式化)。
|
||||
///
|
||||
/// 动机:原 GetInterests 20 个位置参数中,名义本金簇(posiNotionalValue/closePosiNotionalValue/closePercent)
|
||||
/// 在【盘中平仓】与【EOD 平仓后收盘】两类场景下语义相反(详见 GetInterests "根因位置"注释与
|
||||
/// GetInterestsEntrySemanticsTest 的口径留档),位置参数无法表达该约束。
|
||||
///
|
||||
/// 用法:只能经两个场景工厂构造——工厂形参名即该场景语义(平仓前剩余 / 平仓后剩余 / 实际平掉额),
|
||||
/// 物理上防止两套语义混传。needPrice/grossPrice 为原方法死参数(体内零消费),本对象不承载。
|
||||
/// </summary>
|
||||
public sealed class InterestCalcRequest
|
||||
{
|
||||
public trade Td { get; }
|
||||
public trade_extend TradeExtend { get; }
|
||||
public DateTime ValueDate { get; }
|
||||
public DateTime UnwindDate { get; }
|
||||
public List<eod_swap_position> EodPositions { get; }
|
||||
public List<swap_position> Positions { get; }
|
||||
|
||||
/// <summary>当日适用名义本金。语义随场景:盘中=平仓【前】剩余;EOD平仓后收盘=平仓【后】剩余;EOD增量=当前剩余。</summary>
|
||||
public decimal PosiNotionalValue { get; }
|
||||
public decimal PosiLongNotionalValue { get; }
|
||||
public decimal PosiShortNotionalValue { get; }
|
||||
|
||||
/// <summary>本次实际平掉本金(两场景恒同义)。mode2 无条件覆盖 / mode9 全平兜底的输入。</summary>
|
||||
public decimal ClosePosiNotionalValue { get; }
|
||||
|
||||
/// <summary>平仓比例。语义随场景:盘中=实际比例(B 占剩余);EOD平仓后收盘=恒1(全额结息)。</summary>
|
||||
public decimal ClosePercent { get; }
|
||||
|
||||
public int EventType { get; }
|
||||
public bool TdClose { get; }
|
||||
public decimal OrginPv { get; }
|
||||
public bool Add { get; }
|
||||
public bool NewCalcLast { get; }
|
||||
public List<swap_flow_event> CloseList { get; }
|
||||
|
||||
private InterestCalcRequest(
|
||||
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 closePercent,
|
||||
int eventType, bool tdClose, decimal orginPv,
|
||||
bool add, bool newCalcLast, List<swap_flow_event> closeList)
|
||||
{
|
||||
Td = td; TradeExtend = tradeExtend; ValueDate = valueDate; UnwindDate = unwindDate;
|
||||
EodPositions = eodPositions; Positions = positions;
|
||||
PosiNotionalValue = posiNotionalValue; PosiLongNotionalValue = posiLongNotionalValue;
|
||||
PosiShortNotionalValue = posiShortNotionalValue; ClosePosiNotionalValue = closePosiNotionalValue;
|
||||
ClosePercent = closePercent; EventType = eventType; TdClose = tdClose; OrginPv = orginPv;
|
||||
Add = add; NewCalcLast = newCalcLast; CloseList = closeList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 【盘中平仓/互换结息】场景(→ GetIntradayUnwindInterests,settment:false 盘中重放)。
|
||||
/// </summary>
|
||||
/// <param name="preCloseNotional">平仓【前】实时剩余本金(原 GetUnwindInterests.stockEqvNotional)。</param>
|
||||
/// <param name="closedNotional">本次实际平掉本金(= preCloseNotional × closePercentRemaining)。</param>
|
||||
/// <param name="closePercentRemaining">平仓比例,B 语义【占剩余】(前端传 A 占期初须先经 ToRemainingClosePercent 转换)。</param>
|
||||
public static InterestCalcRequest IntradayUnwind(
|
||||
trade td, trade_extend tradeExtend, DateTime valueDate, DateTime unwindDate,
|
||||
List<eod_swap_position> eodPositions, List<swap_position> positions,
|
||||
decimal preCloseNotional, decimal preCloseLongNotional, decimal preCloseShortNotional,
|
||||
decimal closedNotional, decimal closePercentRemaining,
|
||||
int eventType, bool tdClose, decimal orginPv,
|
||||
bool add, bool newCalcLast, List<swap_flow_event> closeList)
|
||||
=> new(td, tradeExtend, valueDate, unwindDate, eodPositions, positions,
|
||||
preCloseNotional, preCloseLongNotional, preCloseShortNotional,
|
||||
closedNotional, closePercentRemaining,
|
||||
eventType, tdClose, orginPv, add, newCalcLast, closeList);
|
||||
|
||||
/// <summary>
|
||||
/// 【EOD 当日有平仓后的收盘结息】场景(→ CalcEodPostCloseSettleInterests,settment:false 全额结息)。
|
||||
/// 该场景触发 GetInterests 内 mode2 无条件覆盖 / mode9 全平兜底(见其"根因位置"注释,勿删)。
|
||||
/// </summary>
|
||||
/// <param name="remainingNotionalAfterClose">平仓【后】剩余本金(GetInterests.posiNotionalValue 形参位)。</param>
|
||||
/// <param name="closedNotional">本次实际平掉本金。</param>
|
||||
public static InterestCalcRequest EodPostCloseSettle(
|
||||
trade td, trade_extend tradeExtend, DateTime valueDate, DateTime unwindDate,
|
||||
List<eod_swap_position> eodPositions, List<swap_position> positions,
|
||||
decimal remainingNotionalAfterClose, decimal remainingLongNotional, decimal remainingShortNotional,
|
||||
decimal closedNotional,
|
||||
int eventType, bool tdClose, decimal orginPv,
|
||||
bool add, bool newCalcLast)
|
||||
=> new(td, tradeExtend, valueDate, unwindDate, eodPositions, positions,
|
||||
remainingNotionalAfterClose, remainingLongNotional, remainingShortNotional,
|
||||
closedNotional, 1m, // 恒1:本次事件全额结息(非 closeNational / 期初比例)
|
||||
eventType, tdClose, orginPv, add, newCalcLast, closeList: null);
|
||||
}
|
||||
@@ -486,10 +486,11 @@ namespace YLErp.Modules.SwapModule
|
||||
&& eventTypes.Contains(x.EventType)
|
||||
&& x.DataState == (int)SwapFlowDateStateEnum.完成).ToList();
|
||||
bool tdClose = closeList.Count > 0;
|
||||
// 显式入口(语义见 GetIntradayUnwindInterests 注释):平仓前剩余本金 + 实际平掉额 + B语义比例,盘中重放
|
||||
interests = GetIntradayUnwindInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions,
|
||||
// 显式入口:平仓前剩余本金 + 实际平掉额 + B语义比例,盘中重放(语义见 InterestCalcRequest.IntradayUnwind)
|
||||
interests = GetIntradayUnwindInterests(InterestCalcRequest.IntradayUnwind(
|
||||
td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions,
|
||||
stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue,
|
||||
closePercent, eventType, tdClose, orginPv, add: true, newCalcLast: false, closeList);
|
||||
closePercent, eventType, tdClose, orginPv, add: true, newCalcLast: false, closeList));
|
||||
return interests;
|
||||
}
|
||||
|
||||
@@ -621,37 +622,13 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// 【盘中平仓/互换结息】显式入口——GetInterests(settment:false) 盘中语义的具名封装(2026-08 显式化重构)。
|
||||
///
|
||||
/// 语义契约(与 EOD 平仓后收盘的 CalcEodPostCloseSettleInterests 相反,勿混用):
|
||||
/// preCloseNotional = 平仓【前】实时剩余本金(原 GetUnwindInterests 的 stockEqvNotional);
|
||||
/// closedNotional = 本次实际平掉本金(= preCloseNotional × closePercentRemaining);
|
||||
/// closePercentRemaining = 平仓比例,B 语义【占剩余】(前端传 A 占期初,须先经 ToRemainingClosePercent 转换);
|
||||
/// 计息走 CalcUnwindInterest 全区间重放(orginPv 参与保证金腿差分)。
|
||||
///
|
||||
/// needPrice/grossPrice 为 GetInterests 的历史死参数(方法体内无消费),本入口不再暴露。
|
||||
/// 语义契约见 InterestCalcRequest.IntradayUnwind 工厂注释;计息走 CalcUnwindInterest 全区间重放。
|
||||
/// </summary>
|
||||
public List<swap_flow_event> GetIntradayUnwindInterests(
|
||||
trade td,
|
||||
trade_extend tradeExtend,
|
||||
DateTime valueDate,
|
||||
DateTime unwindDate,
|
||||
List<eod_swap_position> eodPositions,
|
||||
List<swap_position> positions,
|
||||
decimal preCloseNotional,
|
||||
decimal preCloseLongNotional,
|
||||
decimal preCloseShortNotional,
|
||||
decimal closedNotional,
|
||||
decimal closePercentRemaining,
|
||||
int eventType,
|
||||
bool tdClose,
|
||||
decimal orginPv,
|
||||
bool add,
|
||||
bool newCalcLast,
|
||||
List<swap_flow_event> closeList)
|
||||
=> GetInterests(td, tradeExtend, valueDate, unwindDate, eodPositions, positions,
|
||||
preCloseNotional, preCloseLongNotional, preCloseShortNotional, closedNotional,
|
||||
closePercentRemaining, eventType, tdClose, needPrice: false, grossPrice: 0m,
|
||||
orginPv, add, settment: false, newCalcLast, closeList);
|
||||
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.OrginPv, req.Add, settment: false, req.NewCalcLast, req.CloseList);
|
||||
|
||||
public List<swap_flow_event> GetInterests(
|
||||
trade td,
|
||||
|
||||
@@ -105,29 +105,15 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <summary>
|
||||
/// 【EOD 当日有平仓后的收盘结息】显式入口——原 SaveAutoEodWithCloseInterestPosition 直调
|
||||
/// CalcSwapInterests(settment:false) 的具名封装(2026-08 显式化重构)。
|
||||
///
|
||||
/// 语义契约(与盘中 SwapDealService.GetIntradayUnwindInterests 相反,勿混用):
|
||||
/// remainingNotionalAfterClose = 平仓【后】剩余本金(GetInterests.posiNotionalValue 形参位);
|
||||
/// closedNotional = 本次实际平掉本金(GetInterests.closePosiNotionalValue 形参位);
|
||||
/// 结息比例恒 1(本次事件全额结息)。该组合会触发 GetInterests 内 mode2 无条件覆盖 /
|
||||
/// mode9 全平兜底(见其"根因位置"注释,勿删)。
|
||||
/// 计息走 CalcUnwindInterest 全区间重放(settment:false)。
|
||||
///
|
||||
/// 语义契约见 InterestCalcRequest.EodPostCloseSettle 工厂注释(平仓后剩余 + 实际平掉额 + 恒1全额结息,
|
||||
/// 触发 GetInterests 内 mode2/mode9 本金修正)。计息走 CalcUnwindInterest 全区间重放。
|
||||
/// 默认实现仍经 CalcSwapInterests 转发,保持既有测试替身对该虚接缝的拦截不变。
|
||||
/// </summary>
|
||||
protected virtual List<swap_flow_event> CalcEodPostCloseSettleInterests(
|
||||
trade td, trade_extend tradeExtend,
|
||||
DateTime valueDate, DateTime unwindDate,
|
||||
List<eod_swap_position> eodPositions, List<swap_position> positions,
|
||||
decimal remainingNotionalAfterClose, decimal remainingLongNotional, decimal remainingShortNotional,
|
||||
decimal closedNotional,
|
||||
int eventType, bool tdClose,
|
||||
decimal grossPrice, decimal orginPv,
|
||||
bool add, bool newCalcLast)
|
||||
=> CalcSwapInterests(td, tradeExtend, valueDate, unwindDate, eodPositions, positions,
|
||||
remainingNotionalAfterClose, remainingLongNotional, remainingShortNotional,
|
||||
closedNotional, 1m, eventType, tdClose, needPrice: true, grossPrice, orginPv,
|
||||
add, settment: false, newCalcLast, closeList: null);
|
||||
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);
|
||||
|
||||
// FindTrade 已上提到基类 SwapTradeBaseService(三子类实现一致,消除重复)
|
||||
|
||||
@@ -1333,11 +1319,12 @@ namespace YLErp.Modules.SwapModule
|
||||
List<eod_swap_position> preEodPositions = new List<eod_swap_position>();
|
||||
preEodPositions.Add(eodPayPosition);
|
||||
var calcLast = tradeExtend?.InterestCalcMode?.EndsWith("1") ?? true;
|
||||
// 显式入口(语义见 CalcEodPostCloseSettleInterests 注释):平仓后剩余本金 + 实际平掉额 + 恒1全额结息。
|
||||
// 该组合会触发 GetInterests 内共享计息器的模式2/9本金修正(见其"根因位置"注释,勿删)。
|
||||
var interests = CalcEodPostCloseSettleInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions,
|
||||
// 显式入口:平仓后剩余本金 + 实际平掉额 + 恒1全额结息(语义见 InterestCalcRequest.EodPostCloseSettle)。
|
||||
// 该组合触发 GetInterests 内共享计息器的模式2/9本金修正(见其"根因位置"注释,勿删)。
|
||||
var interests = CalcEodPostCloseSettleInterests(InterestCalcRequest.EodPostCloseSettle(
|
||||
td, td.trade_extend, valueDate, valueDate, preEodPositions, positions,
|
||||
posiNotionalValue, posiLongNotional, posiShortNational, closeNational,
|
||||
eventType, tdClose: false, grossPrice, orginPv, add: true, newCalcLast: autoSwap || calcLast);
|
||||
eventType, tdClose: false, orginPv, add: true, newCalcLast: autoSwap || calcLast));
|
||||
// TdInterestAmount:计息器返回的全腿当日/累计参考值,用于拆出 EOD 的当日新增。
|
||||
// interestAmountBeforeSettlement:本次事件发生前理论应结的高精度利息。
|
||||
// manualSettledInterestAmount:swap_flow_event 实际落库的手工结息,金额已按分处理。
|
||||
|
||||
Reference in New Issue
Block a user