#EQD-6196 国联民生-收益互换期间付息支持自动支付
This commit is contained in:
@@ -144,7 +144,7 @@ namespace YLErp.Modules.SwapModule
|
||||
if (autoInterval != null)
|
||||
break;
|
||||
}
|
||||
DealAutoInterests(autoInterests, td, settleDate, preDealDate, posiLongNotional + posiShortNotional, autoInterval);
|
||||
DealAutoInterests(autoInterests, td, settleDate, preDealDate, posiLongNotional + posiShortNotional, autoInterval, curEodPosis, tradeExtend);
|
||||
//多空组合判断是否已到到期日且无持仓信息
|
||||
if (longShort && td.ExerciseDate.Value == settleDate && allPositionQty == 0)
|
||||
{
|
||||
@@ -370,9 +370,11 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <param name="settleDate"></param>
|
||||
/// <param name="swapDeals"></param>
|
||||
/// <param name="interval">自动互换观察日信息,用于获取结算日期</param>
|
||||
private void DealAutoInterests(List<swap_flow_event> autoInterests, trade td, DateTime settleDate, DateTime? preDealDate, decimal StockEqvNotional, IntervalModel interval)
|
||||
/// <param name="curEodPositions">当日浮动端EOD持仓</param>
|
||||
/// <param name="tradeExtend">交易扩展信息</param>
|
||||
private void DealAutoInterests(List<swap_flow_event> autoInterests, trade td, DateTime settleDate, DateTime? preDealDate, decimal StockEqvNotional, IntervalModel interval, List<eod_swap_position> curEodPositions, trade_extend tradeExtend)
|
||||
{
|
||||
if (autoInterests.Count == 0)
|
||||
if (autoInterests.Count == 0 && (curEodPositions == null || curEodPositions.All(x => x.PosiDividendSum == 0)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -391,6 +393,16 @@ namespace YLErp.Modules.SwapModule
|
||||
unwindData.NotionalValue = Convert.ToDecimal(td.OriginalStockEqvNotional ?? 0);
|
||||
unwindData.PosiNotionalValue = StockEqvNotional;
|
||||
|
||||
// PayDate 统一用派息金额支付日 + 日历调整
|
||||
var dividendPayDateOffset = tradeExtend?.ExtendObj?.DividendPayDate ?? 1;
|
||||
// 0到期结算日 1派息日+0 2派息日+1 3派息日+2
|
||||
var payDays = dividendPayDateOffset > 0 ? dividendPayDateOffset - 1 : 0;
|
||||
var autoSwapPayDate = QdpCalendarHelper.GetNonHoliday(settleDate.AddDays(payDays));
|
||||
unwindData.PayDate = autoSwapPayDate;
|
||||
|
||||
// 给已有利息腿统一赋 PayDate
|
||||
autoInterests.ForEach(x => x.PayDate = autoSwapPayDate);
|
||||
|
||||
// 预付金腿类型列表:初始预付金、追加预付金
|
||||
var premiumModes = new List<int>() { (int)InterestModeEnum.初始预付金, (int)InterestModeEnum.追加预付金 };
|
||||
|
||||
@@ -416,10 +428,58 @@ namespace YLErp.Modules.SwapModule
|
||||
});
|
||||
unwindData.SwapCloseAmount = interestTotal; // 利息腿金额
|
||||
|
||||
// 总实现盈亏
|
||||
unwindData.SwapRealizedPnL = unwindData.SwapCloseAmount + unwindData.SwapMarginRebatePnl;
|
||||
// 处理浮动端待实现分红:将其转为已实现(到期结算日不处理)
|
||||
List<swap_flow_event> dividendEvents = new List<swap_flow_event>();
|
||||
decimal dividendTotal = 0;
|
||||
if (curEodPositions != null && dividendPayDateOffset > 0)
|
||||
{
|
||||
foreach (var eodPosi in curEodPositions.Where(x => x.PosiDividendSum != 0))
|
||||
{
|
||||
var dividendEvent = new swap_flow_event
|
||||
{
|
||||
SwapTradeId = td.id,
|
||||
SwapTradeNo = td.TradeNumber,
|
||||
EventType = (int)SwapEventTypeEnum.自动互换,
|
||||
EventReason = "系统操作-自动互换",
|
||||
EventDate = settleDate,
|
||||
UnwindDate = settleDate,
|
||||
PayDate = autoSwapPayDate,
|
||||
PositionId = eodPosi.PositionId,
|
||||
UnderlyingCode = eodPosi.UnderlyingCode,
|
||||
PayDirection = eodPosi.PosiDirection,
|
||||
PositionType = eodPosi.PositionType,
|
||||
PositionQty = eodPosi.PosiQuantity,
|
||||
Quantity = 0,
|
||||
ContractSize = eodPosi.ContractSize,
|
||||
TradingAmountAvg = eodPosi.PosiNetPrice,
|
||||
PosiGrossPrice = eodPosi.PosiGrossPrice,
|
||||
PosiNetPrice = eodPosi.PosiNetPrice,
|
||||
MarkClosePnl = eodPosi.PosiDividendSum,
|
||||
DividendIn = eodPosi.PosiDividendSum,
|
||||
CloseFee = 0,
|
||||
TradingFee = 0,
|
||||
TradingFeePending = 0,
|
||||
ClientId = td.ClientId,
|
||||
DataState = (int)SwapFlowDateStateEnum.完成,
|
||||
};
|
||||
dividendEvents.Add(dividendEvent);
|
||||
dividendTotal += eodPosi.PosiDividendSum;
|
||||
|
||||
SaveAutoSwapDeal(td, autoInterests, unwindData, interval);
|
||||
// 将EOD持仓的待实现分红转为已实现
|
||||
eodPosi.TdCloseDividend += eodPosi.PosiDividendSum;
|
||||
eodPosi.TdPosiDividend = 0;
|
||||
eodPosi.RealizedDividend += eodPosi.PosiDividendSum;
|
||||
eodPosi.PosiDividendSum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 分红收支加入总实现盈亏
|
||||
unwindData.SwapDividendPnl = dividendTotal;
|
||||
|
||||
// 总实现盈亏
|
||||
unwindData.SwapRealizedPnL = unwindData.SwapCloseAmount + unwindData.SwapMarginRebatePnl + dividendTotal;
|
||||
|
||||
SaveAutoSwapDeal(td, autoInterests, unwindData, interval, dividendEvents);
|
||||
}
|
||||
/// <summary>
|
||||
/// 保存自动互换数据信息
|
||||
@@ -427,7 +487,7 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <param name="td"></param>
|
||||
/// <param name="swap_Deal"></param>
|
||||
/// <param name="interval">自动互换观察日信息,用于获取结算日期</param>
|
||||
private long SaveAutoSwapDeal(trade td, List<swap_flow_event> flowEvents, UnwindData unwindData, IntervalModel interval)
|
||||
private long SaveAutoSwapDeal(trade td, List<swap_flow_event> flowEvents, UnwindData unwindData, IntervalModel interval, List<swap_flow_event> dividendEvents = null)
|
||||
{
|
||||
//td.UnWindDate = unwindData.ValueDate;
|
||||
//优先使用 interval.SettlementDate 作为资金记录发生日期,如果没有则使用 ValueDate
|
||||
@@ -446,6 +506,15 @@ namespace YLErp.Modules.SwapModule
|
||||
AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapMarginRebatePnl), ClientCashInCashOut.系统操作_预付金返息, unwindData.ValueDate);
|
||||
}
|
||||
|
||||
// 分红:使用派息支付日偏移记录资金记录
|
||||
if (unwindData.SwapDividendPnl != 0)
|
||||
{
|
||||
var dividendPayDate = (dividendEvents != null && dividendEvents.Count > 0)
|
||||
? dividendEvents.First().PayDate.Value
|
||||
: unwindData.ValueDate;
|
||||
AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapDividendPnl), ClientCashInCashOut.系统操作_互换, dividendPayDate);
|
||||
}
|
||||
|
||||
string data = JsonConvert.SerializeObject(unwindData);
|
||||
var swapEvent = new SwapEventService(this).AddSwapEventDate(unwindData.ValueDate, unwindData.SwapTradeId, (int)SwapEventTypeEnum.自动互换, data, clientCashId, true, "系统操作-自动互换");//将互换总额存入事件
|
||||
flowEvents.ForEach(x =>
|
||||
@@ -453,6 +522,15 @@ namespace YLErp.Modules.SwapModule
|
||||
x.EventId = swapEvent.id;
|
||||
DbContext.swap_flow_event.Add(x);
|
||||
});
|
||||
// 保存分红事件
|
||||
if (dividendEvents != null)
|
||||
{
|
||||
dividendEvents.ForEach(x =>
|
||||
{
|
||||
x.EventId = swapEvent.id;
|
||||
DbContext.swap_flow_event.Add(x);
|
||||
});
|
||||
}
|
||||
UpdateInitalPostion(flowEvents, td.id);
|
||||
return swapEvent.id;
|
||||
}
|
||||
@@ -979,7 +1057,7 @@ namespace YLErp.Modules.SwapModule
|
||||
newEodPayPosition.TdInterestFee = flowEvents.Sum(s => s.InterestFee);
|
||||
newEodPayPosition.TdCloseInterestFee = newEodPayPosition.TdInterestFee;
|
||||
newEodPayPosition.TdCloseInterest = flowEvents.Sum(s => s.InterestClosePnL);
|
||||
var intersetAcmount = newEodPayPosition.TdInterestPrincipal*(newEodPayPosition.TdInterestRate + newEodPayPosition.FloatRate);
|
||||
var intersetAcmount = newEodPayPosition.TdInterestPrincipal * (newEodPayPosition.TdInterestRate + newEodPayPosition.FloatRate);
|
||||
if (position.IsAnnualized)
|
||||
{
|
||||
intersetAcmount /= tradeExtend.AnnualDays;
|
||||
@@ -1368,7 +1446,9 @@ namespace YLErp.Modules.SwapModule
|
||||
curretEod.UnderlyingMarketValue = curretEod.UnderlyingPrice * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio;
|
||||
curretEod.PosiMtmPnL = (curretEod.UnderlyingPrice - curretEod.PosiGrossPrice) * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio * directionRatio;
|
||||
curretEod.TdPosiDividend = 0;
|
||||
if (valueDate > td.StartDate.Value && (curretEod.PosiQuantity > 0))
|
||||
// 有互换事件时,分红已全量结算,不再查分红,TdPosiDividend和PosiDividendSum都归0
|
||||
var hasSwapEvent = unwindEvents.Any(e => e.EventType == (int)SwapFlowEventTypeEnum.互换 || e.EventType == (int)SwapFlowEventTypeEnum.自动互换);
|
||||
if (!hasSwapEvent && valueDate > td.StartDate.Value && (curretEod.PosiQuantity > 0))
|
||||
{
|
||||
decimal tax = um.ValueAddedTax ?? 0;
|
||||
BondPaymentService bondPaymentService = new BondPaymentService(UserInfo);
|
||||
@@ -1382,12 +1462,26 @@ namespace YLErp.Modules.SwapModule
|
||||
curretEod.RealizedPnl = eod.RealizedPnl + curretEod.TdCloseMtmPnl;
|
||||
curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0;
|
||||
var closeQty = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.平仓).ToList().Sum(s => s.Quantity);
|
||||
// 当日浮动端平仓盈亏·分红 = 平仓数量/昨天剩余平仓数量 * 昨日浮动端待实现收益·分红
|
||||
// 当日浮动端平仓盈亏·分红
|
||||
curretEod.TdCloseDividend = unwindEvents.Sum(e => e.DividendIn);
|
||||
curretEod.RealizedDividend = curretEod.RealizedDividend + curretEod.TdCloseDividend;
|
||||
|
||||
// 浮动端待实现收益·分红 = 昨日 + 当日浮动端分红 - 当日浮动端平仓盈亏·分红
|
||||
curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend - curretEod.TdCloseDividend;
|
||||
// 浮动端待实现收益·分红(有互换事件时全量结算归0;否则用当前持仓从起始日重算)
|
||||
if (hasSwapEvent)
|
||||
{
|
||||
curretEod.PosiDividendSum = 0;
|
||||
}
|
||||
else if (curretEod.PosiQuantity > 0)
|
||||
{
|
||||
decimal tax = um.ValueAddedTax ?? 0;
|
||||
BondPaymentService bondPaymentService = new BondPaymentService(UserInfo);
|
||||
decimal totalPayment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, td.StartDate.Value, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio);
|
||||
curretEod.PosiDividendSum = totalPayment / (1 + tax) * (1 - tax);
|
||||
}
|
||||
else
|
||||
{
|
||||
curretEod.PosiDividendSum = 0;
|
||||
}
|
||||
curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending;
|
||||
if (curretEod.PosiStatus == 1)
|
||||
{
|
||||
@@ -1464,7 +1558,7 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
curretEod.PosiNotionalValue = curretEod.PosiGrossPrice * curretEod.PosiQuantity * curretEod.ContractSize;
|
||||
curretEod.PosiNotionalValue = Math.Round(curretEod.PosiNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
|
||||
curretEod.TdPosiDividend = unwindEvents.Sum(x => x.DividendIn) * directionRatio;
|
||||
curretEod.TdCloseDividend = unwindEvents.Sum(x => x.DividendIn);
|
||||
curretEod.TdCloseFee = unwindFlowEvents.Sum(x => x.TradingFee + x.TradingFeePending);
|
||||
curretEod.TdCloseQty = unwindQty;
|
||||
curretEod.TdCloseMtmPnl = unwindEvents.Sum(x => x.MarkClosePnl);
|
||||
@@ -1526,7 +1620,21 @@ namespace YLErp.Modules.SwapModule
|
||||
// //curretEod.TdCloseMtmPnl = 0;
|
||||
// //curretEod.TdCloseFee = 0;
|
||||
//}
|
||||
curretEod.TdCloseDividend = curretEod.TdPosiDividend;
|
||||
// TdCloseDividend 已由 SetPriceInfoByFlowEvent 设置
|
||||
|
||||
// 当日新增分红及待实现分红(有互换全量归0,开仓首日两者相同)
|
||||
curretEod.TdPosiDividend = 0;
|
||||
var hasSwapEvent = unwindEvents.Any(e => e.EventType == (int)SwapFlowEventTypeEnum.互换 || e.EventType == (int)SwapFlowEventTypeEnum.自动互换);
|
||||
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);
|
||||
payment = payment / (1 + tax) * (1 - tax);
|
||||
curretEod.TdPosiDividend = payment;
|
||||
curretEod.PosiDividendSum = payment;
|
||||
}
|
||||
|
||||
curretEod.UnderlyingMarketValue = curretEod.UnderlyingPrice * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio;
|
||||
curretEod.PosiMtmPnL = (curretEod.UnderlyingPrice - curretEod.PosiGrossPrice) * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio * directionRatio;
|
||||
curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending;
|
||||
|
||||
Reference in New Issue
Block a user