519 lines
31 KiB
C#
519 lines
31 KiB
C#
using BaseOUDAL;
|
|
using ClosedXML.Report.Utils;
|
|
using Confluent.Kafka;
|
|
using Microsoft.Office.Interop.Excel;
|
|
using MoreLinq;
|
|
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;
|
|
|
|
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).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.PosiQuantity * position.ContractSize;
|
|
flow_Event.TradingFee = position.PosiTradingFee * -1;//费用先按负数处理
|
|
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.完成 && eventTyps.Contains(n.EventType));
|
|
var tradePredicate = PredicateBuilder.Create<trade>(n => n.TradeType == "收益互换"
|
|
&& n.ValidState != "InValid");
|
|
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);
|
|
}
|
|
var positionQuery = DbContext.swap_flow_event.Where(predicate);
|
|
var tradeQuery = DbContext.trade.Where(tradePredicate);
|
|
var query = from flow in positionQuery
|
|
join td in tradeQuery on flow.SwapTradeId equals td.id
|
|
select new ClientSwapPositionResponse
|
|
{
|
|
FlowEvent = flow,
|
|
SwapTradeNo = td.TradeNumber,
|
|
StructureType = td.StructureType,
|
|
ClientName = td.ClientName,
|
|
ClientId = td.ClientId
|
|
};
|
|
if (string.IsNullOrEmpty(req.sidx))
|
|
{
|
|
req.sidx = "SwapTradeNo,FlowEvent.id";
|
|
req.sord = "asc";
|
|
}
|
|
var retListResult = query.ToSearchList(req);
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|