Files
zszq-trs/YLErpDAL/Modules/SwapModule/SwapTradeBaseService.cs
T
2024-06-12 10:28:49 +08:00

476 lines
22 KiB
C#

using CsvHelper;
using DocumentFormat.OpenXml.Drawing.Diagrams;
using DocumentFormat.OpenXml.Office2010.PowerPoint;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using Qdp.Pricing.Base.Enums;
using System.Linq.Expressions;
using YLErp.BLL;
using YLErp.Commons;
namespace YLErp.Modules.SwapModule
{
public class SwapTradeBaseService : YLBaseService
{
public SwapTradeBaseService(OptUserInfo optUser) : base(optUser)
{
}
public SwapTradeBaseService(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
/// 校验标的是否存在
/// </summary>
/// <param name="underlyingCode"></param>
/// <returns>不存在返回空</returns>
public bool GetUnderlyingCode(string underlyingCode)
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
return underlying == null ? false : true;
}
/// <summary>
///新增日终归档信息时 修改 持仓腿信息
/// </summary>
/// <param name="eodPayPosition"></param>
public void UpdateSwapPosition(eod_swap_position eodPayPosition, string tradeNumber)
{
var position = DbContext.swap_position.Find(eodPayPosition.PositionId);
position.ContractSize = eodPayPosition.ContractSize;
position.PositionType = eodPayPosition.PositionType;
position.PosiTradingFee = eodPayPosition.PosiTradingFee;
position.PosiTradingFeePending = eodPayPosition.PosiFeePending;
position.PosiTradingFeeUnit = eodPayPosition.PosiQuantity == 0 ? 0 : eodPayPosition.PosiTradingFee / eodPayPosition.PosiQuantity;
position.UnderlyingCode = eodPayPosition.UnderlyingCode;
position.UnderlyingInstrumentType = eodPayPosition.UnderlyingInstrumentType;
position.PosiDirection = eodPayPosition.PosiDirection;
position.PosiNetPrice = eodPayPosition.PosiNetPrice;
position.PosiGrossPrice = eodPayPosition.PosiGrossPrice;
position.PosiNetFeePrice = eodPayPosition.PosiNetFeePrice;
position.PosiNetNoFeePrice = eodPayPosition.PosiNetNoFeePrice;
position.PosiNotionalValue = eodPayPosition.PosiNotionalValue;
position.PosiQuantity = eodPayPosition.PosiQuantity;
position.PosiStartDate = eodPayPosition.PosiStartDate;
position.OptTime = DateTime.Now;
position.OptId = UserInfo.UserId;
position.OptName = UserInfo.UserName;
position.PosiNumber = $"{tradeNumber}-{position.id}";
}
/// <summary>
/// 平仓后更新持仓
/// </summary>
/// <param name="eodPayPosition"></param>
public void UpdateSwapPositionWithRealTime(eod_swap_position eodPayPosition)
{
var position = DbContext.swap_position.FirstOrDefault(x => x.PositionId == eodPayPosition.PositionId);
if (position != null)
{
position.PosiQuantity = eodPayPosition.PosiQuantity;
position.PosiTradingFee = eodPayPosition.PosiTradingFee;
position.PosiNetPrice = eodPayPosition.PosiNetPrice;
position.PosiGrossPrice = eodPayPosition.PosiGrossPrice;
position.PosiNetFeePrice = eodPayPosition.PosiNetFeePrice;
position.PosiNetNoFeePrice = eodPayPosition.PosiNetNoFeePrice;
position.PosiNotionalValue = eodPayPosition.PosiNotionalValue;
position.PosiTradingFeePending = eodPayPosition.PosiFeePending;
position.PosiQuantity = eodPayPosition.PosiQuantity;
position.PosiDirection = eodPayPosition.PosiDirection;
position.PositionType = eodPayPosition.PositionType;
position.OptTime = DateTime.Now;
position.OptId = UserInfo.UserId;
position.OptName = UserInfo.UserName;
}
else
{
position = DbContext.swap_position.FirstOrDefault(x => x.id == eodPayPosition.PositionId);
var posi = position.Clone();
posi.id = 0;
posi.PositionId = position.id;
posi.IsInitial = false;
DbContext.swap_position.Add(posi);
}
}
/// <summary>
/// 获取同一互换编码,标的 持仓id
/// </summary>
/// <param name="swapTradeId">互换框架合约id</param>
/// <param name="underlyingCode">标的代码</param>
/// <returns></returns>
public long GetMaxPositionId(swap_flow_merge swap_Flow_Summary, DateTime matuirityDate, int direction, string tradeNumber)
{
long max = 0;
var position = DbContext.swap_position.FirstOrDefault(x => x.SwapTradeId == swap_Flow_Summary.SwapTradeId && x.UnderlyingCode == swap_Flow_Summary.UnderlyingCode && x.PosiQuantity != 0 && !x.IsInitial&&!x.Invalid);
if (position != null)
{
max = position.PositionId;
}
else
{
swap_position swap_Position = new swap_position();
swap_Position.PosiDirection = direction;
swap_Position.PositionType = swap_Flow_Summary.BsType;
swap_Position.SwapTradeId = swap_Flow_Summary.SwapTradeId ?? 0;
swap_Position.UnderlyingCode = swap_Flow_Summary.UnderlyingCode;
swap_Position.PosiQuantity = swap_Flow_Summary.TradingQty;
swap_Position.PosiTradingFee = swap_Flow_Summary.TradingFee;
swap_Position.ContractSize = swap_Flow_Summary.ContractSize;
swap_Position.IsInitial = true;
swap_Position.PosiStartDate = swap_Flow_Summary.OccurTime;
swap_Position.PosiMatuirityDate = matuirityDate;
swap_Position.OptId = UserId;
swap_Position.OptName = UserName;
swap_Position.OptTime = DateTime.Now;
DbContext.swap_position.Add(swap_Position);
DbContext.SaveChanges();
max = swap_Position.id;
swap_Position.PosiNumber = $"{tradeNumber}-{max}";
}
return max;
}
public long GetPositionId(swap_flow_merge swap_Flow_Summary, DateTime matuirityDate, int direction, string tradeNumber)
{
long max = 0;
swap_position swap_Position = new swap_position();
swap_Position.PosiDirection = direction;
swap_Position.PositionType = swap_Flow_Summary.BsType;
swap_Position.SwapTradeId = swap_Flow_Summary.SwapTradeId ?? 0;
swap_Position.UnderlyingCode = swap_Flow_Summary.UnderlyingCode;
swap_Position.PosiQuantity = swap_Flow_Summary.TradingQty;
swap_Position.PosiTradingFee = swap_Flow_Summary.TradingFee;
swap_Position.ContractSize = swap_Flow_Summary.ContractSize;
swap_Position.IsInitial = true;
swap_Position.PosiStartDate = swap_Flow_Summary.OccurTime;
swap_Position.PosiMatuirityDate = matuirityDate;
swap_Position.OptId = UserId;
swap_Position.OptName = UserName;
swap_Position.OptTime = DateTime.Now;
DbContext.swap_position.Add(swap_Position);
DbContext.SaveChanges();
max = swap_Position.id;
swap_Position.PosiNumber = $"{tradeNumber}-{max}";
return max;
}
/// <summary>
/// 添加交易操作日志
/// </summary>
public void AddTradeOperationHistory(bool saveChanges, OtcTradeBase trade, string optType, string comments = null)
{
DbContext.TradeAuditLog.Add(new TradeAuditLog
{
TradeId = trade.id,
AuditFlag = TradeAuditFlag.operation,
OptType = optType,
Changes = comments ?? string.Empty,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = OptDate
});
if (saveChanges)
{
DbContext.SaveChanges();
}
}
/// <summary>
/// 获取平仓/互换记录
/// </summary>
/// <param name="tradeId">交易编码</param>
/// <param name="valueDate">日期</param>
/// <param name="eventTypes">互换事件类型</param>
/// <param name="lessValueDate">是否查询小于日期</param>
/// <returns></returns>
public List<swap_flow_event> GetSwapFlowEvents(int tradeId, DateTime? valueDate, List<int> eventTypes)
{
Expression<Func<swap_flow_event, bool>> eventExpression = x => x.SwapTradeId == tradeId && x.DataState == (int)SwapFlowDateStateEnum.完成 && eventTypes.Contains(x.EventType);
if (valueDate.HasValue)
{
eventExpression = eventExpression.And(x => x.UnwindDate == valueDate);
}
List<swap_flow_event> swapFlowEvents = DbContext.swap_flow_event.Where(eventExpression).ToList();
return swapFlowEvents;
}
/// <summary>
/// 获取交易平仓/互换事件所有信息
/// </summary>
/// <param name="tradeId"></param>
/// <param name="eventTypes"></param>
/// <returns></returns>
public List<swap_event> GetSwapEvents(int tradeId, List<int> eventTypes)
{
Expression<Func<swap_event, bool>> eventExpression = x => x.SwapTradeId == tradeId && !x.Invalid && eventTypes.Contains(x.EventType) && x.ClientCashId > 0;
var swapEvents = DbContext.swap_event.Where(eventExpression).ToList();
var swapFlowEvents = DbContext.swap_flow_event.Where(x => x.SwapTradeId == tradeId && x.DataState == (int)SwapFlowDateStateEnum.完成);
var swapPositions = DbContext.swap_position.Where(x => x.SwapTradeId == tradeId && !string.IsNullOrEmpty(x.UnderlyingCode) && !x.Invalid).ToList();
foreach (var item in swapEvents)
{
item.unwindData = JsonConvert.DeserializeObject<UnwindData>(item.EventData);
item.unwindData.FlowEvents = swapFlowEvents.Where(x => x.EventId == item.id).ToList();
item.unwindData.FlowEvents.ForEach(x =>
{
var position = swapPositions.FirstOrDefault(n => n.id == x.PositionId && n.IsInitial);
var positionReal = swapPositions.FirstOrDefault(n => n.PositionId == x.PositionId && !n.IsInitial);
if (position != null)
{
x.PosiGrossPrice = position.PosiGrossPrice;
x.PosiNetPrice = position.PosiNetPrice;
}
//if (positionReal!=null)
//{
// x.PositionQty = positionReal.PosiQuantity;
//}
});
}
return swapEvents;
}
/// <summary>
/// 获取平仓/互换信息
/// </summary>
/// <param name="tradeId"></param>
/// <param name="eventType"></param>
/// <returns></returns>
public swap_event GetSwapEvent(int tradeId, int eventType)
{
Expression<Func<swap_event, bool>> eventExpression = x => x.SwapTradeId == tradeId && !x.Invalid && x.EventType == eventType && x.ClientCashId == 0;
var swapEvent = DbContext.swap_event.Where(eventExpression).OrderByDescending(o => o.id).FirstOrDefault();
var swapFlowEvents = DbContext.swap_flow_event.Where(x => x.EventId == swapEvent.id);
var swapPositions = DbContext.swap_position.Where(x => x.SwapTradeId == tradeId && !string.IsNullOrEmpty(x.UnderlyingCode) && !x.Invalid).ToList();
if (swapEvent != null)
{
swapEvent.unwindData = JsonConvert.DeserializeObject<UnwindData>(swapEvent.EventData);
swapEvent.unwindData.FlowEvents = swapFlowEvents.Where(x => x.EventDate == swapEvent.ValueDate).ToList();
swapEvent.unwindData.FlowEvents.ForEach(x =>
{
var position = swapPositions.FirstOrDefault(n => n.id == x.PositionId && n.IsInitial);
if (position != null)
{
x.PosiGrossPrice = position.PosiGrossPrice;
x.PosiNetPrice = position.PosiNetPrice;
//if (eventType==(int)SwapEventTypeEnum.互换)
//{
// x.TradingAmountAvg = x.TradingAmount / (x.PositionQty*x.ContractSize);
//}
//else
//{
// x.TradingAmountAvg = x.TradingAmount / (swapEvent.unwindData.CloseQty * x.ContractSize);
//}
}
});
}
return swapEvent;
}
/// <summary>
/// 获取上一互换交易事件处理日期
/// </summary>
/// <param name="tradeId"></param>
/// <param name="valueDate"></param>
/// <param name="eventTypes"></param>
/// <returns></returns>
public DateTime? GetPreDealDate(int tradeId, DateTime valueDate, List<int> eventTypes)
{
Expression<Func<swap_event, bool>> eventExpression = x => x.SwapTradeId == tradeId && x.ValueDate <= valueDate && !x.Invalid && eventTypes.Contains(x.EventType);
var swapEvent = DbContext.swap_event.Where(eventExpression).OrderByDescending(o => o.ValueDate).FirstOrDefault();
if (swapEvent == null)
{
return null;
}
return swapEvent.ValueDate;
}
/// <summary>
/// 收益互换 客户资金记录保存
/// </summary>
/// <param name="td">主交易信息</param>
/// <param name="amount">平仓盈亏</param>
/// <param name="action">操作类型</param>
/// <param name="valueDate">操作日期</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public int CloseTrade_ClientCashInCashOut(OtcTradeBase td, double amount, string action, DateTime valueDate)
{
var cl = DataCacheProvider.GetClientDataSource().GetData(td.ClientId);
if (cl == null)
{
throw new Exception("客户信息未找到,交易编号:" + td.TradeNumber);
}
var ee = DbContext.ClientCashInCashOut.FirstOrDefault(x => x.TradeId == td.id && x.Action == action && x.HappenDate == valueDate);
if (ee == null)
{
//增加出入金记录
ee = new ClientCashInCashOut();
ee.CreateDate = DateTime.Now;
ee.CreatorId = UserId;
ee.CreatorName = UserName;
}
ee.Direction = "应收";
ee.Number = UniqueTimeId.GetStr();
ee.ClientId = cl.id;
ee.ClientNumber = cl.Number;
ee.ClientName = cl.Name;
ee.Money = amount;
ee.CurrencyCode = td.SettlementCurrency;
ee.HappenDate = valueDate;
ee.State = ClientCashInCashOut.已确认;
ee.OptId = UserId;
ee.OptName = UserName;
ee.OptDate = DateTime.Now;
ee.TradeId = td.id;
ee.Action = action;
ee.ValidState = "Valid";
ee.TradeNumber = td.TradeNumber;
ee.CurrencyCode = "CNY";
if (ee.id == 0)
{
DbContext.ClientCashInCashOut.Add(ee);
}
DbContext.SaveChanges();
return ee.id;
}
public void AddClientCashInCashOut(OtcTradeBase td, double amount, string action, DateTime valueDate)
{
var cl = DataCacheProvider.GetClientDataSource().GetData(td.ClientId);
if (cl == null)
{
throw new Exception("客户信息未找到,交易编号:" + td.TradeNumber);
}
//增加出入金记录
var ee = new ClientCashInCashOut();
ee.CreateDate = DateTime.Now;
ee.CreatorId = UserId;
ee.CreatorName = UserName;
ee.Direction = "应收";
ee.Number = UniqueTimeId.GetStr();
ee.ClientId = cl.id;
ee.ClientNumber = cl.Number;
ee.ClientName = cl.Name;
ee.Money = amount;
ee.CurrencyCode = td.SettlementCurrency;
ee.HappenDate = valueDate;
ee.State = ClientCashInCashOut.已确认;
ee.OptId = UserId;
ee.OptName = UserName;
ee.OptDate = DateTime.Now;
ee.TradeId = td.id;
ee.Action = action;
ee.ValidState = "Valid";
ee.TradeNumber = td.TradeNumber;
ee.CurrencyCode = "CNY";
DbContext.ClientCashInCashOut.Add(ee);
DbContext.SaveChanges();
}
/// <summary>
/// 初始化 利息计算起始日期
/// </summary>
/// <param name="valueDate"></param>
/// <param name="preSettleDate">上一交易日</param>
/// <param name="td">互换交易主信息</param>
/// <param name="interestMode">计息方式</param>
/// <param name="interestStart">计息开始日期</param>
/// <param name="interestEnd">计息结束日期</param>
public bool InitInterestDate(DateTime valueDate, DateTime? preSettleDate, trade td, bool tdClose,bool calcLastNew,out DateTime interestStart, out DateTime interestEnd)
{
interestStart = td.StartDate.Value;
var exerciseDate = td.ExerciseDate.Value;
interestEnd = valueDate> exerciseDate? exerciseDate : valueDate;
bool calcFirst = true;
bool calcLast = true;
if (td.trade_extend != null)
{
calcFirst = td.trade_extend.ExtendObj.InterestCalcMode.StartsWith("1");//算头
calcLast = td.trade_extend.ExtendObj.InterestCalcMode.EndsWith("1");//算尾
}
interestStart = calcFirst ? interestStart : interestStart.AddDays(1);
if (preSettleDate.HasValue)
{
interestStart = preSettleDate.Value;
}
if ((interestEnd == exerciseDate && !calcLast)|| !calcLastNew)
{
interestEnd = interestEnd.AddDays(-1);
}
if (interestStart > interestEnd)
{
interestStart = interestEnd;
return true;//不记利息
}
if (tdClose)
{
interestStart = valueDate;
}
return false;
}
public void UpdateDbOption(DBModelBaseV2 dBModel)
{
dBModel.OptTime = DateTime.Now;
dBModel.OptName = UserName;
dBModel.OptId = UserId;
}
/// <summary>
/// 合成持仓/日终归档 清除互换持仓所有信息
/// </summary>
/// <param name="tradeId"></param>
public void ClearSwapPositions(trade td, DateTime valueDate, List<int> eventTypes, bool delAfter)
{
var swapEvents = DbContext.swap_event.Where(x => x.SwapTradeId == td.id && x.ValueDate >= valueDate && eventTypes.Contains(x.EventType));
var eventIds = swapEvents.Select(s => s.id).ToList();
var eodSwaps = DbContext.eod_swap.Where(x => x.SwapTradeId == td.id && x.ValueDate >= valueDate).ToList();
if (delAfter)
{
var swapFlowEvents = DbContext.swap_flow_event.Where(x => x.SwapTradeId == td.id && x.UnwindDate >= valueDate && x.DataState > (int)SwapFlowDateStateEnum.废弃 && eventTypes.Contains(x.EventType)).ToList();
var eodSwapPositions = DbContext.eod_swap_position.Where(x => x.SwapTradeId == td.id && x.ValueDate >= valueDate).ToList();
DbContext.eod_swap_position.RemoveRange(eodSwapPositions);
DbContext.swap_flow_event.RemoveRange(swapFlowEvents);
}
DbContext.swap_event.RemoveRange(swapEvents);
DbContext.eod_swap.RemoveRange(eodSwaps);
DbContext.SaveChanges();
}
/// <summary>
/// 获取上一交易日
/// </summary>
/// <param name="valueDate">当前交易日</param>
/// <returns></returns>
public DateTime GetPreValueDate(DateTime valueDate)
{
var preSettleDate = valuedateBLL.GetNonHolidayDefore(valueDate.AddDays(-1));//上一交易日
return preSettleDate;
}
/// <summary>
/// 判断交易上一交易日是否收盘
/// </summary>
/// <param name="valueDate">交易日期</param>
/// <param name="tradeStartDate">交易开始日期</param>
/// <returns></returns>
/// <exception cref="ServiceException"></exception>
public DateTime CheckLastEod(DateTime valueDate, DateTime tradeStartDate, int tradeId)
{
var preSettleDate = GetPreValueDate(valueDate);//上一交易日期
List<eod_swap_position> lastEodPositions = new SwapEodPositionService(this).GetPreEodPositions(tradeId, preSettleDate);//上一交易数据
if (preSettleDate > tradeStartDate && lastEodPositions.Count == 0)
{
throw new ServiceException($"上一交易日【{preSettleDate:D}】未收盘");
}
return preSettleDate;
}
/// <summary>
/// 是否有审批流程
/// </summary>
/// <returns></returns>
public bool HasTradeProcess()
{
return DbContext.approvalprocess.Where(t => t.processType == "TradeProcess").Any();
}
}
}