refactor(swap): DealFloatPositions外部依赖虚方法接缝(分红场景准备)

加3个protected virtual虚方法:
- GetUnderlyingPrice: 标的市场价格(原UnderlyingCodePrice)
- GetUnderlyingData: 标的缓存数据(原DataCacheProvider)
- CalcBondPayment: 债券付息(原new BondPaymentService)

替换CopyEodPosition/UpdateEodPosition/SaveCurrentEodInitalPosi
内部的外部调用为调虚方法,生产代码行为不变。

这3个接缝使浮动腿归档的分红计算可测(TdPosiDividend/PosiDividendSum)。
验证: 108个测试全通过。
This commit is contained in:
hjhan
2026-07-02 08:57:55 +08:00
parent fee2203d6e
commit 7c993f7bb2
@@ -153,6 +153,24 @@ namespace YLErp.Modules.SwapModule
ClearSwapPositions(td, tradeDate, eventTypes, false);
}
/// <summary>获取标的市场价格(生产: UnderlyingCodePrice查缓存+中债估值;测试: 返回固定值)</summary>
protected virtual decimal GetUnderlyingPrice(string code, DateTime settleDate, out decimal vobp)
{
return UnderlyingCodePrice(code, settleDate, out vobp);
}
/// <summary>获取标的缓存数据(生产: DataCacheProvider;测试: 返回内存对象)</summary>
protected virtual underlying_manager GetUnderlyingData(string underlyingCode)
{
return DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
}
/// <summary>计算债券付息(生产: BondPaymentService;测试: 返回固定值)</summary>
protected virtual decimal CalcBondPayment(string underlyingCode, DateTime fromDate, DateTime toDate, decimal qty, int shortRatio, int directionRatio)
{
return new BondPaymentService(UserInfo).CalcPayment(underlyingCode, fromDate, toDate, qty, shortRatio, directionRatio);
}
#endregion
/// <summary>
@@ -1488,7 +1506,7 @@ namespace YLErp.Modules.SwapModule
curretEod.id = 0;
curretEod.ValueDate = valueDate;
}
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(eod.UnderlyingCode);
var um = GetUnderlyingData(eod.UnderlyingCode);
if (um == null)
{
return curretEod;
@@ -1497,13 +1515,12 @@ namespace YLErp.Modules.SwapModule
int shortRatio = eod.PositionType == (int)PositionTypeFlag.Long ? 1 : -1;
int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum. ? 1 : -1;
curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0;
var price = UnderlyingCodePrice(eod.UnderlyingCode, dealDate, out decimal vobp);
var price = GetUnderlyingPrice(eod.UnderlyingCode, dealDate, out decimal vobp);
curretEod.dv01 = Dv01Helper.CalcDv01(eod.UnderlyingCode, curretEod.PosiQuantity, eod.PosiDirection, eod.PositionType, vobp);
decimal tax = um.ValueAddedTax ?? 0;
BondPaymentService bondPaymentService = new BondPaymentService(UserInfo);
if (valueDate > td.StartDate.Value && curretEod.PosiQuantity > 0)
{
decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio);
decimal payment = CalcBondPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio);
// 考虑增值税
curretEod.TdPosiDividend = Math.Round(payment / (1 + tax) * (1 - tax), 2);
}
@@ -1570,7 +1587,7 @@ namespace YLErp.Modules.SwapModule
curretEod.ValueDate = valueDate;
}
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(eod.UnderlyingCode);
var um = GetUnderlyingData(eod.UnderlyingCode);
if (um == null)
{
return curretEod;
@@ -1578,11 +1595,10 @@ namespace YLErp.Modules.SwapModule
var dealDate = curretEod.ValueDate;
int shortRatio = eod.PositionType == (int)PositionTypeFlag.Long ? 1 : -1;
int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum. ? 1 : -1;
var price = UnderlyingCodePrice(eod.UnderlyingCode, dealDate, out decimal vobp);
var price = GetUnderlyingPrice(eod.UnderlyingCode, dealDate, out decimal vobp);
var todayConsumedDividend = CalcConsumedDividend(curretEod, unwindEvents);
var originNotional = (decimal)td.OriginalStockEqvNotional / swapPosition.PosiNetPrice;
BondPaymentService bondPaymentService = new BondPaymentService(UserInfo);
decimal totalPayment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, td.StartDate.Value, valueDate, (decimal)originNotional, shortRatio, directionRatio);
decimal totalPayment = CalcBondPayment(curretEod.UnderlyingCode, td.StartDate.Value, valueDate, (decimal)originNotional, shortRatio, directionRatio);
decimal tax = um.ValueAddedTax ?? 0;
decimal totalInterest = totalPayment / (1 + tax) * (1 - tax);
SetPriceInfoByFlowEvent(eod, curretEod, unwindEvents, swapPosition);
@@ -1595,7 +1611,7 @@ namespace YLErp.Modules.SwapModule
// 修改,互换事件会影响待实现的分红的,现在要算上
if (valueDate > td.StartDate.Value && (curretEod.PosiQuantity > 0))
{
decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio);
decimal payment = CalcBondPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio);
curretEod.TdPosiDividend = Math.Round(payment / (1 + tax) * (1 - tax), 2);
}
curretEod.RealizedMtmPnL = eod.RealizedMtmPnL + curretEod.TdCloseMtmPnl;
@@ -1737,7 +1753,7 @@ namespace YLErp.Modules.SwapModule
protected eod_swap_position SaveCurrentEodInitalPosi(swap_position position, trade td, DateTime settleDate, DateTime preSettleDate, List<swap_flow_event> unwindEvents)
{
eod_swap_position curretEod = new eod_swap_position();
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(position.UnderlyingCode);
var um = GetUnderlyingData(position.UnderlyingCode);
if (um == null)
{
return curretEod;
@@ -1770,7 +1786,7 @@ namespace YLErp.Modules.SwapModule
curretEod.ContractSize = position.ContractSize;
curretEod.CountRatio = position.CountRatio;
curretEod.PosiTradingFee = position.PosiTradingFee;
curretEod.UnderlyingPrice = UnderlyingCodePrice(position.UnderlyingCode, dealDate, out decimal vobp);
curretEod.UnderlyingPrice = GetUnderlyingPrice(position.UnderlyingCode, dealDate, out decimal vobp);
SetPriceInfoByFlowEvent(eod, curretEod, unwindEvents, position);
curretEod.dv01 = Dv01Helper.CalcDv01(curretEod.UnderlyingCode, curretEod.PosiQuantity, curretEod.PosiDirection, curretEod.PositionType, vobp);
//if (settleDate == td.TradeDate)
@@ -1787,8 +1803,7 @@ namespace YLErp.Modules.SwapModule
if (!hasSwapEvent && settleDate > td.StartDate.Value && curretEod.PosiQuantity > 0)
{
decimal tax = um.ValueAddedTax ?? 0;
BondPaymentService bondPaymentService = new BondPaymentService(UserInfo);
decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, td.StartDate.Value, settleDate, curretEod.PosiQuantity, shortRatio, directionRatio);
decimal payment = CalcBondPayment(curretEod.UnderlyingCode, td.StartDate.Value, settleDate, curretEod.PosiQuantity, shortRatio, directionRatio);
payment = Math.Round(payment / (1 + tax) * (1 - tax), 2);
//var consumedDividend = CalcConsumedDividend(curretEod, unwindEvents); 首日应该没有分红
curretEod.TdPosiDividend = payment;