Files
zszq-trs/YLErpDAL/Modules/SwapModule/SwapTradeBaseService.cs
T

453 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
public int 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();
return ee.id;
}
/// <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, 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 && preSettleDate >= interestStart)
{
interestStart = preSettleDate.Value;
}
if ((interestEnd == exerciseDate && !calcLast))
{
interestEnd = interestEnd.AddDays(-1);
}
if (interestStart > interestEnd || td.StartDate > interestStart)
{
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);
// 删除自动互换产生的资金记录(client_cash_in_out
var swapEventIds = swapEvents.Select(s => s.id).ToList();
if (swapEventIds.Any())
{
// 通过 swap_event 的 ClientCashId 删除对应的资金记录(利息腿)
var clientCashIds = swapEvents.Where(s => s.ClientCashId > 0).Select(s => s.ClientCashId).ToList();
if (clientCashIds.Any())
{
var clientCashRecords = DbContext.ClientCashInCashOut.Where(x => clientCashIds.Contains(x.id)).ToList();
DbContext.ClientCashInCashOut.RemoveRange(clientCashRecords);
}
// 删除预付金腿的资金记录(通过交易ID、日期和Action类型查找,一次性查询避免MySQL连接重用问题)
var swapTradeIds = swapEvents.Select(s => s.SwapTradeId).Distinct().ToList();
var actions = new List<string>() { ClientCashInCashOut.系统操作_预付金返息, ClientCashInCashOut.系统操作_互换 };
var premiumCashRecords = DbContext.ClientCashInCashOut
.Where(x => swapTradeIds.Contains(x.TradeId ?? 0)
&& x.HappenDate>=valueDate
&& actions.Contains(x.Action))
.ToList();
if (premiumCashRecords.Any())
{
DbContext.ClientCashInCashOut.RemoveRange(premiumCashRecords);
}
}
}
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();
}
}
}