Files
zszq-trs/YLErpDAL/Modules/SwapModule/SwapFlowEventService.cs
T
2025-10-15 15:08:37 +08:00

551 lines
33 KiB
C#

using BaseOUDAL;
using ClosedXML.Report.Utils;
using Confluent.Kafka;
using Microsoft.Office.Interop.Excel;
using MoreLinq;
using NPOI.OpenXmlFormats.Spreadsheet;
using System.Collections.Generic;
using YLErp.BLL.Calculation;
using YLErp.DBModels;
using YLErp.DBModels.Enums;
using YLErp.Model;
using YLErp.Modules.AppModule;
using YLErp.Modules.EodModule.QueryModule;
using YLErp.QdpModule;
using static YLErp.ConsGlobal;
namespace YLErp.Modules.SwapModule
{
/// <summary>
/// 互换流水开平仓事件服务
/// </summary>
public class SwapFlowEventService : SwapTradeBaseService
{
public SwapFlowEventService(OptUserInfo optUser) : base(optUser)
{
}
public SwapFlowEventService(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
/// 互换流水开平仓事件
/// </summary>
public void SwapFlowEvent(DateTime tradeDate)
{
new SysJobService(UserInfo).UpdateJob("互换流水合成持仓", 31, "互换流水开平仓事件进行中");
//同一交易代码、交易日期、标的、买卖方向 最多存在2条记录
var flowqueryGroup = DbContext.swap_flow_merge.Where(n => n.DataState == (int)SwapFlowDateStateEnum.等待完成 && n.OccurTime == tradeDate).AsEnumerable().GroupBy(g => g.SwapTradeId);
foreach (var flowMergeGroupItem in flowqueryGroup)
{
MergePageEvent(flowMergeGroupItem.Key ?? 0, flowMergeGroupItem.ToList(), tradeDate);
}
new SysJobService(UserInfo).UpdateJob("互换流水合成持仓", 32, "互换流水开平仓事件完成");
}
/// <summary>
/// 互换流水开平仓事件
/// </summary>
public List<swap_flow_event> SwapFlowEvent(List<swap_flow_merge> mergeList, DateTime tradeDate)
{
List<swap_flow_event> flowEvents = new List<swap_flow_event>();
new SysJobService(UserInfo).UpdateJob("互换流水合成持仓", 31, "互换流水开平仓事件进行中");
//同一交易代码、交易日期、标的、买卖方向 最多存在2条记录
var flowqueryGroup = mergeList.Where(n => n.DataState == (int)SwapFlowDateStateEnum.等待完成).GroupBy(g => g.SwapTradeId);
foreach (var flowMergeGroupItem in flowqueryGroup)
{
flowEvents.AddRange(MergePageEvent(flowMergeGroupItem.Key ?? 0, flowMergeGroupItem.ToList(), tradeDate, false));
}
new SysJobService(UserInfo).UpdateJob("互换流水合成持仓", 32, "互换流水开平仓事件完成");
return flowEvents;
}
/// <summary>
/// 分页处理互换流水开平仓事件,暂时只按加权平均处理
/// </summary>
/// <param name="pageSize"></param>
private List<swap_flow_event> MergePageEvent(int swapTradeId, List<swap_flow_merge> flowMergeList, DateTime tradeDate, bool needTrans = true)
{
List<swap_flow_event> flowEvents = new List<swap_flow_event>();
//按照同一互换编码、标的、买卖方向排序,一条买,一条卖//会存在买卖不在同一页
var flowquery = flowMergeList.OrderBy(o => o.SwapTradeId).ThenBy(o => o.UnderlyingCode).ThenBy(o => o.BsType).ToList();
if (flowquery.Count == 0)
{
return flowEvents;
}
var trade = DbContext.trade.Find(swapTradeId);
var tradeExtend = DbContext.trade_extend.First(x => x.TradeId == swapTradeId);
var trans = needTrans ? DbContext.Database.BeginTransaction() : null;
try
{
var eodPositions = DbContext.swap_position.Where(x => x.SwapTradeId == swapTradeId && !x.IsInitial && !x.Invalid).AsNoTracking().ToList();//上一日终持仓信息
var swapFlowEventOlds = DbContext.swap_flow_event.Where(x => x.EventDate > tradeDate && x.SwapTradeId == swapTradeId && x.DataState > 0);//废弃当前清算日期及之后的开平仓事件
swapFlowEventOlds.ForEach(x =>
{
x.DataState = (int)SwapFlowDateStateEnum.废弃;
});
var mergeUnderlyingGroup = flowquery.GroupBy(g => g.UnderlyingCode);
int direction = tradeExtend.ExtendObj.Direction;
foreach (var underlyingGroup in mergeUnderlyingGroup)
{
var mergeList = underlyingGroup.OrderByDescending(o => o.TradingQty).ToList();//先按数量最大的排序
var flowMerge = mergeList.First();
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(flowMerge.UnderlyingCode);
var matuirityDate = trade.ExerciseDate;
var positionId = GetMaxPositionId(flowMerge, matuirityDate.Value, direction, trade.TradeNumber);
var payPosition = eodPositions.FirstOrDefault(x => x.PositionId == positionId);//浮动腿 日终持仓信息
bool hasPayPosition = payPosition != null;//是否存在日终持仓
if (mergeList.Count == 1)//只有一条流水
{
if (!hasPayPosition)//无日终持仓
{
var flowEvent = InitEvent((int)SwapFlowEventTypeEnum.开仓, flowMerge, direction, positionId, flowMerge.BsType, flowMerge.TradingQty, flowMerge.TradingAmount, flowMerge.TradingFee, 0, 0, flowMerge.TradingAmountAvg, flowMerge.TradingAmountFeeAvg, flowMerge.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent);
}
else
{
if (flowMerge.BsType == payPosition.PositionType)//同向开仓
{
var qty = flowMerge.TradingQtyAbs;
var amount = flowMerge.TradingAmountAbs;
var flowEvent = InitEvent((int)SwapFlowEventTypeEnum.开仓, flowMerge, direction, positionId, flowMerge.BsType, qty, amount, flowMerge.TradingFeeAbs, 0, 0, flowMerge.TradingAmountAvg, flowMerge.TradingAmountFeeAvg, flowMerge.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent);
}
else//反向平仓
{
var qty = flowMerge.TradingQtyAbs - payPosition.PosiQuantity;//平仓剩余数量
var bsType = qty > 0 ? flowMerge.BsType : payPosition.PositionType;
var unwindQty = qty > 0 ? payPosition.PosiQuantity : flowMerge.TradingQtyAbs;//平仓数量
var fee = payPosition.PosiQuantity == 0 ? 0 : flowMerge.TradingFeeAbs * -1 + (unwindQty / payPosition.PosiQuantity) * payPosition.PosiTradingFee;//平仓费用=平仓流水的交易费用佣金+平仓数量/平仓前的数量*平仓对象的(交易佣金费用+后付费用)
var amount = (flowMerge.TradingAmountAvgAbs - payPosition.PosiGrossPrice) * unwindQty * flowMerge.ContractSize;//平仓剩余金额=(平仓流水的成交均价-平仓对象的期初价格不含费)*平仓流水的成交数量*合约乘数
var flowEvent = InitEvent((int)SwapFlowEventTypeEnum.平仓, flowMerge, direction, positionId, payPosition.PositionType, unwindQty, flowMerge.TradingAmountAbs, flowMerge.TradingFeeAbs, amount, fee, flowMerge.TradingAmountAvg, flowMerge.TradingAmountFeeAvg, flowMerge.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent);
if (qty > 0)//平仓有剩余,开仓
{
qty = Math.Abs(qty);
amount = flowMerge.TradingAmountAvgAbs * qty * flowMerge.ContractSize;
//positionId = GetPositionId(flowMerge, matuirityDate.Value, direction, trade.TradeNumber);
var flowEvent2 = InitEvent((int)SwapFlowEventTypeEnum.开仓, flowMerge, direction, positionId, bsType, qty, Math.Abs(amount), flowMerge.TradingFeeAbs, 0, 0, flowMerge.TradingAmountAvg, flowMerge.TradingAmountFeeAvg, flowMerge.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent2);
}
}
}
flowMerge.DataState = 100;
}
else
{
var flowMerge2 = mergeList.Last();
if (!hasPayPosition)//无日终持仓
{
//先将数量最大的开仓
var flowEvent = InitEvent((int)SwapFlowEventTypeEnum.开仓, flowMerge, direction, positionId, flowMerge.BsType, flowMerge.TradingQtyAbs, flowMerge.TradingAmountAbs, flowMerge.TradingFeeAbs, 0, 0, flowMerge.TradingAmountAvg, flowMerge.TradingAmountFeeAvg, flowMerge.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
//再将数量小的那条平仓
var qty = flowMerge.TradingQtyAbs - flowMerge2.TradingQtyAbs;//平仓剩余数量
var bsType = qty > 0 ? flowMerge.BsType : flowMerge2.BsType;
var unwindQty = qty > 0 ? flowMerge2.TradingQtyAbs : flowMerge.TradingQtyAbs;//平仓数量
var fee = flowMerge2.TradingFeeAbs * -1 + (unwindQty / flowMerge.TradingQtyAbs) * flowMerge.TradingFeeAbs * -1;//平仓费用=平仓流水的交易费用佣金+平仓数量/平仓前的数量*平仓对象的(交易佣金费用+后付费用)
var amount = (flowMerge2.TradingAmountAvgAbs - flowMerge.TradingAmountAvgAbs) * unwindQty * flowMerge2.ContractSize;//平仓剩余金额=(平仓流水的成交均价-平仓对象的期初价格不含费)*平仓流水的成交数量*合约乘数
var flowEvent2 = InitEvent((int)SwapFlowEventTypeEnum.平仓, flowMerge2, direction, positionId, flowMerge.BsType, unwindQty, flowMerge2.TradingAmountAbs, flowMerge2.TradingFeeAbs, amount, fee, flowMerge2.TradingAmountAvg, flowMerge2.TradingAmountFeeAvg, flowMerge2.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent);
flowEvents.Add(flowEvent2);
}
else//有日终持仓,先平仓方向相反的流水,再处理另一条流水
{
flowMerge = mergeList.First(x => x.BsType != payPosition.PositionType);//反向流水
flowMerge2 = mergeList.Last(x => x.BsType == payPosition.PositionType);//同向流水
var qty = flowMerge.TradingQtyAbs - payPosition.PosiQuantity;//平仓剩余数量
var bsType = qty > 0 ? flowMerge.BsType : payPosition.PositionType;
var unwindQty = qty > 0 ? payPosition.PosiQuantity : flowMerge.TradingQtyAbs;//平仓数量
var fee = payPosition.PosiQuantity == 0 ? 0 : flowMerge.TradingFeeAbs * -1 + (unwindQty / payPosition.PosiQuantity) * payPosition.PosiTradingFee;//平仓费用=平仓流水的交易费用佣金+平仓数量/平仓前的数量*平仓对象的(交易佣金费用+后付费用)
var amount = (flowMerge.TradingAmountAvgAbs - payPosition.PosiGrossPrice) * unwindQty * flowMerge.ContractSize;//平仓剩余金额=(平仓流水的成交均价-平仓对象的期初价格不含费)*平仓流水的成交数量*合约乘数
var flowEvent = InitEvent((int)SwapFlowEventTypeEnum.平仓, flowMerge, direction, positionId, payPosition.PositionType, unwindQty, flowMerge.TradingAmountAbs, flowMerge.TradingFeeAbs, amount, fee, flowMerge.TradingAmountAvg, flowMerge.TradingAmountFeeAvg, flowMerge.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent);
if (qty > 0)//反向流水平仓有剩余,开仓
{
//positionId = GetPositionId(flowMerge, matuirityDate.Value, direction, trade.TradeNumber);
amount = flowMerge.TradingAmountAvgAbs * qty * flowMerge.ContractSize;
var flowEvent2 = InitEvent((int)SwapFlowEventTypeEnum.开仓, flowMerge, direction, positionId, bsType, qty, amount, Math.Abs(fee), 0, 0, flowMerge.TradingAmountAvg, flowMerge.TradingAmountFeeAvg, flowMerge.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent2);
if (bsType == flowMerge2.BsType)//平仓剩余与第二条流水同向
{
var flowEvent3 = InitEvent((int)SwapFlowEventTypeEnum.开仓, flowMerge2, direction, positionId, bsType, flowMerge2.TradingQtyAbs, flowMerge2.TradingAmountAbs, flowMerge2.TradingFeeAbs, 0, 0, flowMerge2.TradingAmountAvg, flowMerge2.TradingAmountFeeAvg, flowMerge2.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent3);
}
else //方向相反,先平仓
{
var qty2 = qty - flowMerge2.TradingQtyAbs;
unwindQty = qty2 > 0 ? flowMerge2.TradingQtyAbs : qty;//平仓数量
bsType = qty2 > 0 ? bsType : flowMerge2.BsType;
var amount2 = (flowMerge2.TradingAmountAvgAbs - flowMerge.TradingAmountAvgAbs) * unwindQty * flowMerge2.ContractSize;
var fee2 = flowMerge2.TradingFeeAbs * -1 + (unwindQty / qty) * fee;
var flowEvent3 = InitEvent((int)SwapFlowEventTypeEnum.平仓, flowMerge2, direction, positionId, flowMerge2.BsType, unwindQty, flowMerge2.TradingAmountAbs, flowMerge2.TradingFeeAbs, amount2, fee2, flowMerge2.TradingAmountAvg, flowMerge2.TradingAmountFeeAvg, flowMerge2.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent3);
if (qty2 != 0)//平仓有剩余,开仓
{
qty2 = Math.Abs(qty2);
//positionId = GetPositionId(flowMerge2, matuirityDate.Value, direction, trade.TradeNumber);
amount2 = flowMerge2.TradingAmountAvgAbs * qty2 * flowMerge2.ContractSize;
var flowEvent4 = InitEvent((int)SwapFlowEventTypeEnum.开仓, flowMerge2, direction, positionId, bsType, qty2, amount2, Math.Abs(fee2), 0, 0, flowMerge2.TradingAmountAvg, flowMerge2.TradingAmountFeeAvg, flowMerge2.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent4);
}
}
}
else //无平仓剩余,开仓
{
var flowEvent2 = InitEvent((int)SwapFlowEventTypeEnum.开仓, flowMerge2, direction, positionId, flowMerge2.BsType, flowMerge2.TradingQtyAbs, flowMerge2.TradingAmountAbs, flowMerge2.TradingFeeAbs, 0, 0, flowMerge2.TradingAmountAvg, flowMerge2.TradingAmountFeeAvg, flowMerge2.TradingAmountNetFeeAvg, matuirityDate, underlying.UnderlyingInstrumentType, tradeExtend.ExtendObj.SettlementRules);
flowEvents.Add(flowEvent2);
}
}
flowMerge.DataState = (int)SwapFlowDateStateEnum.完成;
flowMerge2.DataState = (int)SwapFlowDateStateEnum.完成;
}
}
DbContext.SaveChanges();
trans?.Commit();
}
catch (Exception ex)
{
trans?.Rollback();
throw new Exception(ex.Message, ex);
}
finally
{
trans?.Dispose();
}
return flowEvents;
}
/// <summary>
/// 保存流水事件
/// </summary>
/// <param name="underlying">标的信息</param>
/// <param name="eventType">事件类型</param>
/// <param name="flow_merge">汇总流水</param>
/// <param name="direction">浮动端收支方向</param>
/// <param name="swapPositionId">持仓编码</param>
/// <param name="positionType">多空方向</param>
/// <param name="TradingQty">开平仓数量</param>
/// <param name="TradingAmount">开平仓金额</param>
/// <param name="TradingFee">开平仓费用</param>
/// <param name="PayMarkUnwindPnl">平仓浮动盈亏</param>
/// <param name="PayFeeUnwindPnl">平仓浮动费用</param>
/// <param name="allUnwind">是否完全平仓</param>
/// <param name="settleRules">0 T+0 1 T+1</param>
private swap_flow_event InitEvent(
int eventType,
swap_flow_merge flow_merge,
int direction,
long swapPositionId,
int positionType,
decimal TradingQty,
decimal TradingAmount,
decimal TradingFee,
decimal PayMarkUnwindPnl,
decimal PayFeeUnwindPnl,
decimal TradingAmountAvg,
decimal TradingAmountFeeAvg,
decimal? TradingAmountNetFeeAvg,
DateTime? matuirityDate,
string underlyingInstrumentType, int settleRules)
{
swap_flow_event flow_Event = new swap_flow_event()
{
EventReason = "交易",
EventType = eventType,
SwapTradeId = flow_merge.SwapTradeId ?? 0,
SwapTradeNo = flow_merge.SwapTradeNo,
ContractSize = flow_merge.ContractSize,
CountRatio = 1,
UnderlyingCode = flow_merge.UnderlyingCode,
UnderlyingInstrumentType = underlyingInstrumentType,
DataState = 1,
EventDate = flow_merge.OccurTime,
UnwindDate = QdpCalendarHelper.GetNonHoliday(flow_merge.OccurTime.AddDays(1)),
TradingAmountAvg = TradingAmountAvg,
TradingAmountFeeAvg = TradingAmountFeeAvg,
TradingAmountNetFeeAvg = TradingAmountNetFeeAvg,
TradingAmountNetAvg = flow_merge.TradingAmountNetAvg,
ClientId = flow_merge.ClientId,
TradingFeePending = flow_merge.TradingFeePending,
};
UpdateDbOption(flow_Event);
flow_Event.MatuirityDate = matuirityDate;
flow_Event.PayDirection = direction;
flow_Event.PositionType = positionType;
flow_Event.PositionId = swapPositionId;
flow_Event.PayDate = flow_Event.UnwindDate.Value.AddDays(settleRules); //.todo 支付日期
flow_Event.Quantity = TradingQty;
flow_Event.TradingAmount = TradingAmount;
flow_Event.TradingFee = TradingFee;//费用先按负数处理
flow_Event.MarkClosePnl = PayMarkUnwindPnl;
flow_Event.CloseFee = PayFeeUnwindPnl;
flow_Event.DataState = (int)SwapFlowDateStateEnum.等待完成;
DbContext.swap_flow_event.Add(flow_Event);
return flow_Event;
}
/// <summary>
/// 新增开平仓事件(实时持仓用)
/// </summary>
/// <param name="eventType"></param>
/// <param name="flow_merge"></param>
/// <param name="direction"></param>
/// <param name="positionType"></param>
/// <param name="TradingQty"></param>
/// <param name="TradingAmount"></param>
/// <param name="TradingFee"></param>
/// <param name="TradingAmountAvg"></param>
/// <param name="TradingAmountFeeAvg"></param>
/// <returns></returns>
public swap_flow_event AddEvent(int eventType, swap_flow_merge flow_merge, int direction,
int positionType,
decimal TradingQty,
decimal TradingAmount,
decimal TradingFee,
long positionId)
{
swap_flow_event flow_Event = new swap_flow_event()
{
EventReason = "交易",
EventType = eventType,
SwapTradeId = flow_merge.SwapTradeId ?? 0,
SwapTradeNo = flow_merge.SwapTradeNo,
ContractSize = flow_merge.ContractSize,
CountRatio = 1,
UnderlyingCode = flow_merge.UnderlyingCode,
DataState = 1,
EventDate = flow_merge.OccurTime,
UnwindDate = QdpCalendarHelper.GetNonHoliday(flow_merge.OccurTime.AddDays(1)),
TradingAmountAvg = flow_merge.TradingAmountAvg,
TradingAmountFeeAvg = flow_merge.TradingAmountFeeAvg,
TradingFeePending = flow_merge.TradingFeePending,
ClientId = flow_merge.ClientId
};
flow_Event.PayDirection = direction;
flow_Event.PositionType = positionType;
flow_Event.Quantity = TradingQty;
flow_Event.TradingAmount = TradingAmount;
flow_Event.TradingFee = TradingFee;//费用先按负数处理
flow_Event.PositionId = positionId;
return flow_Event;
}
/// <summary>
/// 确认交易开仓事件
/// </summary>
/// <param name="positions"></param>
/// <param name="td"></param>
public void InitEvent(List<swap_position> positions, trade td, string optLog)
{
foreach (swap_position position in positions)
{
swap_flow_event flow_Event = new swap_flow_event()
{
EventReason = "交易",
EventType = (int)SwapFlowEventTypeEnum.开仓,
SwapTradeId = position.SwapTradeId,
SwapTradeNo = td.TradeNumber,
ContractSize = position.ContractSize,
CountRatio = position.CountRatio,
UnderlyingCode = position.UnderlyingCode,
DataState = (int)SwapFlowDateStateEnum.完成,
EventDate = td.TradeDate.Value,
UnwindDate = td.StartDate.Value,
TradingAmountAvg = position.PosiGrossPrice,
TradingAmountFeeAvg = position.PosiNetPrice,
TradingAmountNetFeeAvg = position.PosiNetFeePrice,
TradingAmountNetAvg = position.PosiNetNoFeePrice,
TradingFeePending = position.PosiTradingFeePending,
OptLog = optLog
};
UpdateDbOption(flow_Event);
flow_Event.ClientId = td.ClientId;
flow_Event.MatuirityDate = td.ExerciseDate;
flow_Event.PayDirection = position.PosiDirection;
flow_Event.PositionType = position.PositionType;
flow_Event.PositionId = position.id;
flow_Event.Quantity = position.PosiQuantity;
flow_Event.PositionQty = flow_Event.Quantity;
flow_Event.TradingAmount = position.PosiNotionalValue;
flow_Event.TradingFee = position.PosiTradingFee;
flow_Event.MarkClosePnl = 0;
flow_Event.CloseFee = 0;
flow_Event.InterestDirection = position.InterestDirection;
flow_Event.InterestRate = position.InterestRateDefault;
flow_Event.InterestPrincipal = position.InterestPrincipalFix;
flow_Event.InterestSwapInterval = position.InterestSwapInterval;
flow_Event.InterestMode = position.InterestMode;
flow_Event.UnderlyingInstrumentType = position.UnderlyingInstrumentType;
flow_Event.PayDate = flow_Event.UnwindDate.Value;
DbContext.swap_flow_event.Add(flow_Event);
}
}
/// <summary>
/// 确认交易开仓事件
/// </summary>
/// <param name="flowMerge"></param>
/// <param name="td"></param>
/// <param name="realPosition"></param>
/// <param name="underlyingInstrumentType"></param>
/// <returns></returns>
public swap_flow_event InitEvent(swap_flow_merge flowMerge, trade td, swap_position realPosition, string underlyingInstrumentType)
{
swap_flow_event flow_Event = new swap_flow_event()
{
EventReason = "交易",
EventType = (int)SwapFlowEventTypeEnum.开仓,
SwapTradeId = td.id,
SwapTradeNo = td.TradeNumber,
ContractSize = flowMerge.ContractSize,
CountRatio = 1,
UnderlyingCode = flowMerge.UnderlyingCode,
DataState = 100,
EventDate = td.TradeDate.Value,
UnwindDate = QdpCalendarHelper.GetNonHoliday(td.TradeDate.Value.AddDays(1)),
TradingAmountAvg = flowMerge.TradingAmountAvg,
TradingAmountFeeAvg = flowMerge.TradingAmountFeeAvg,
TradingAmountNetFeeAvg = flowMerge.TradingAmountNetFeeAvg,
TradingAmountNetAvg = flowMerge.TradingAmountNetAvg,
TradingFeePending = flowMerge.TradingFeePending,
};
UpdateDbOption(flow_Event);
flow_Event.ClientId = td.ClientId;
flow_Event.MatuirityDate = td.ExerciseDate;
flow_Event.PayDirection = 2;
flow_Event.PositionType = flowMerge.BsType;
flow_Event.PositionId = realPosition.PositionId;
flow_Event.Quantity = flowMerge.TradingQty;
flow_Event.PositionQty = realPosition.PosiQuantity;
flow_Event.TradingAmount = realPosition.PosiNotionalValue;
flow_Event.MarkClosePnl = 0;
flow_Event.CloseFee = 0;
flow_Event.UnderlyingInstrumentType = underlyingInstrumentType;
DbContext.swap_flow_event.Add(flow_Event);
DbContext.SaveChanges();
return flow_Event;
}
/// <summary>
/// 互换交易流水查询
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
public SearchListResult<ClientSwapPositionResponse> SearchPositionFlowEvent(ClientSwapPositionRequest req)
{
var retListResult = GetSearchPositionEventList(req);
var clientDataSource = DataCacheProvider.GetClientDataSource();
foreach (var item in retListResult.rows)
{
var client = clientDataSource.GetData(item.ClientId);
item.ClientNumber = client.Number;
}
return retListResult;
}
/// <summary>
/// 互换交易流水查询
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
private SearchListResult<ClientSwapPositionResponse> GetSearchPositionEventList(ClientSwapPositionRequest req)
{
// List<int> eventTyps = new List<int>() { (int)SwapEventTypeEnum.平仓, (int)SwapEventTypeEnum.互换, (int)SwapEventTypeEnum.自动互换 };
var predicate = PredicateBuilder.Create<swap_flow_event>(n => n.DataState == (int)SwapFlowDateStateEnum.完成 );
var tradePredicate = PredicateBuilder.Create<trade>(n => n.TradeType == "收益互换"
&& n.ValidState == ConsGlobal.Valid);
if (req.ClientId > 0)
{
tradePredicate = tradePredicate.And(x => x.ClientId == req.ClientId);
}
if (req.ValueDateFrom != null)
{
predicate = predicate.And(x => x.EventDate >= req.ValueDateFrom);
}
if (req.ValueDate != null)
{
predicate = predicate.And(x => x.EventDate <= req.ValueDate);
}
DbContext.SetDebugLog();
var positionQuery = DbContext.swap_flow_event.Where(predicate);
var tradeQuery = DbContext.trade.Where(tradePredicate);
var query = from td in tradeQuery
//join posi in DbContext.swap_position.Where(s=>!s.Invalid&&s.IsInitial) on td.id equals posi.SwapTradeId
join flow in positionQuery on td.id equals flow.SwapTradeId
join tr in DbContext.trade_contract_r.Where(x=>x.IsValid&&x.Type=="交易确认书") on td.id equals tr.TradeId into tradeContractGroup
from tradeContract in tradeContractGroup.DefaultIfEmpty()
select new ClientSwapPositionResponse
{
FlowEvent = flow,
SwapTradeNo = td.TradeNumber,
StructureType = td.StructureType,
ClientName = td.ClientName,
ClientId = td.ClientId,
ContractCode = tradeContract.ContractCode,
// FloatRateUnderlyingCode=posi.FloatRateUnderlyingCode,
StartDate = td.StartDate.Value,
InitYtm = td.InitYtm,
};
if (string.IsNullOrEmpty(req.sidx))
{
req.sidx = "FlowEvent.EventDate,SwapTradeNo";
req.sord = "asc";
}
var retListResult = query.ToSearchList(req);
var tds= retListResult.rows.Select(x => x.FlowEvent.SwapTradeId).Distinct().ToList();
var posiList = DbContext.swap_position.Where(s => !s.Invalid && s.IsInitial && tds.Contains(s.SwapTradeId) && !string.IsNullOrEmpty(s.FloatRateUnderlyingCode)).ToList();
// 查询成交收益率
Dictionary<int, decimal?> ytmMap = DbContext.trade.AsNoTracking().Where(p => tds.Contains(p.id)).ToList().ToDictionary(t => t.id, t => t.InitYtm);
foreach (var item in retListResult.rows)
{
item.FlowEvent.DividendPending = -item.FlowEvent.DividendPending;
item.FlowEvent.MarkClosePnl = -item.FlowEvent.MarkClosePnl;
item.FlowEvent.DividendIn = -item.FlowEvent.DividendIn;
item.FlowEvent.CloseFee = -item.FlowEvent.CloseFee;
item.FlowEvent.InterestFee = -item.FlowEvent.InterestFee;
item.FlowEvent.TradingFee = -item.FlowEvent.TradingFee;
item.FlowEvent.TradingFeePending = -item.FlowEvent.TradingFeePending;
item.FlowEvent.InterestClosePnL = -item.FlowEvent.InterestClosePnL;
item.FlowEvent.InitYtm = ytmMap.GetValueOrDefault(item.FlowEvent.SwapTradeId);
var posi= posiList.FirstOrDefault(s => s.id == item.FlowEvent.PositionId);
item.FloatRateUnderlyingCode= posi?.FloatRateUnderlyingCode;
if (item.FlowEvent.EventType==(int)SwapFlowEventTypeEnum.开仓)
{
item.TradeFee = 0;
item.TradingFee= item.FlowEvent.TradingFeePending;
}
else
{
item.TradeFee = item.FlowEvent.TradingFee;
item.TradingFee = item.FlowEvent.TradingFeePending;
item.PosiPnl= item.FlowEvent.MarkClosePnl- item.TradeFee-item.FlowEvent.DividendIn - item.TradingFee;
item.NetSettmentAmount = item.FlowEvent.MarkClosePnl + item.FlowEvent.InterestClosePnL;
item.Days = (item.FlowEvent.UnwindDate - item.StartDate).Value.Days;
}
}
return retListResult;
}
private void SetPosiPrice(swap_flow_event position)
{
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(position.UnderlyingCode);
if (um != null && um.IsBond())
{
position.PosiNetPrice *= 100;
position.TradingAmountAvg *= 100;
position.TradingAmountFeeAvg *= 100;
position.PosiGrossPrice *= 100;
return;
}
}
}
}