Files
zszq-trs/YLErpDAL/Modules/SwapModule/SwapTradeBaseService.cs
T
hjhan f8049f81f8 refactor(swap): InitInterestDate 删除死子句 td.StartDate>interestStart + 触发场景注释归因修正
分析定谳:interestStart 经三条赋值路径(=开始日/不算头+1天/preSettleDate 且仅当
≥interestStart 才覆盖)恒 ≥ td.StartDate,第二 OR 子句恒 false——死代码删除。
注释归因同时修正两侧旧错误:
- 原注释把"不算头首日"笼统挂在返回 true 上——实际由第一子句
  interestStart>interestEnd 兜住(StartDate+1>StartDate);
- 候选修正案"观察日当日已结息(preSettleDate 覆盖窗口末)"亦不精确——日期相等
  时函数返回 false,当日已结息的利息归零在 GetInterests closeList 净额层;
  只有相等叠加到期日不算尾回拨(endDate-1)才严格大于而触发。
新增三条 InitInterestDate 直测钉边界:不算头首日空窗/同日已结息日期相等非空/
同日已结息+到期日回拨空窗。

验证:GLMS20260817Fr007UnwindMorningTest 36/36;全量 981 例 145 败与基线 diff=0
2026-08-19 11:36:53 +08:00

598 lines
28 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)
{
}
#region 可测试化接缝(Seams)——子类共用,override 可在测试中替换 DB/外部调用
/// <summary>查找交易(生产: DbContext.trade.Find;测试: 返回内存对象)。
/// SwapDealService/SwapEodPositionService/SwapFlowEventService 三处实现完全一致,上提基类消除重复。</summary>
protected virtual trade FindTrade(int tradeId)
{
return DbContext.trade.Find(tradeId);
}
#endregion
/// <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 = Math.Round(eodPayPosition.PosiNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
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 = Math.Round(eodPayPosition.PosiNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero);
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 virtual 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;
}
#region 可测试化接缝(ClearSwapPositions 相关)
/// <summary>查找该交易的 flow_event(生产: DbContext.swap_flow_event;测试: 内存列表)</summary>
protected virtual List<swap_flow_event> FindFlowEventsByEventIds(List<long> eventIds)
{
return DbContext.swap_flow_event.Where(x => x.EventId.HasValue && eventIds.Contains(x.EventId.Value)).ToList();
}
/// <summary>查找手动互换的 ClientCashId(生产: DbContext.swap_event;测试: 内存列表)</summary>
protected virtual List<int> FindManualClientCashIds(int swapTradeId)
{
return DbContext.swap_event
.Where(x => x.SwapTradeId == swapTradeId
&& x.ClientCashId > 0
&& x.EventType != (int)SwapEventTypeEnum.自动互换)
.Select(x => x.ClientCashId)
.ToList();
}
/// <summary>查找该交易的资金记录(生产: DbContext.ClientCashInCashOut;测试: 内存列表)</summary>
protected virtual List<ClientCashInCashOut> FindClientCashRecords(int tradeId)
{
return DbContext.ClientCashInCashOut.Where(x => x.TradeId == tradeId).ToList();
}
#endregion
public virtual 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>
/// <returns>true=计息窗口为空(interestStart&gt;interestEnd,本次不计利息,调用方将利率与金额归零);
/// 典型触发=①不算头首日(valueDate==StartDate → StartDate+1&gt;StartDate) ②不算尾到期日回拨后窗口翻转
/// (interestEnd=到期日−1 &lt; interestStart)。判定只看日期窗口,与事件类型无关。
/// 注:当日已结息(preSettleDate==valueDate)日期相等时本函数返回 false——利息归零由
/// GetInterests 的 closeList 净额层处理,不在本判定。</returns>
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 = td.trade_extend?.ExtendObj.CalcFirst ?? true;
bool calcLast = td.trade_extend?.ExtendObj.CalcLast ?? true;
interestStart = calcFirst ? interestStart : interestStart.AddDays(1);
if (preSettleDate.HasValue && preSettleDate >= interestStart)
{
interestStart = preSettleDate.Value;
}
if ((interestEnd == exerciseDate && !calcLast))
{
interestEnd = interestEnd.AddDays(-1);
}
// 原第二 OR 子句 td.StartDate > interestStart 恒 falseinterestStart 经上面调整恒 ≥ td.StartDate
// =开始日 / 不算头+1天 / preSettleDate 且仅当 ≥interestStart 才覆盖),死代码已删(2026-08-19)。
if (interestStart > interestEnd)
{
interestStart = interestEnd;
return true;//不记利息
}
if (tdClose)
{
interestStart = valueDate;
}
return false;
}
public virtual void UpdateDbOption(DBModelBaseV2 dBModel)
{
dBModel.OptTime = DateTime.Now;
dBModel.OptName = UserName;
dBModel.OptId = UserId;
}
/// <summary>
/// 合成持仓/日终归档 清除互换持仓所有信息
/// </summary>
/// <param name="tradeId"></param>
public virtual 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 autoSwapEvents = swapEvents.ToList();
if (autoSwapEvents.Any())
{
// 通过 swap_event 的 ClientCashId 删除对应的资金记录(利息腿)
var clientCashIds = autoSwapEvents
.Where(s => s.ClientCashId > 0)
.Select(s => s.ClientCashId)
.ToList();
var legacyAutoEvents = new List<swap_event>();
foreach (var swapEvent in autoSwapEvents)
{
var eventCashIds = GetAutoSwapClientCashIds(swapEvent);
if (eventCashIds.Any())
{
clientCashIds.AddRange(eventCashIds);
}
else
{
legacyAutoEvents.Add(swapEvent);
}
}
clientCashIds = clientCashIds.Distinct().ToList();
if (clientCashIds.Any())
{
var clientCashRecords = DbContext.ClientCashInCashOut.Where(x => clientCashIds.Contains(x.id)).ToList();
DbContext.ClientCashInCashOut.RemoveRange(clientCashRecords);
}
var legacyCashRecords = GetLegacyAutoSwapClientCashRecords(legacyAutoEvents, clientCashIds);
if (legacyCashRecords.Any())
{
DbContext.ClientCashInCashOut.RemoveRange(legacyCashRecords);
}
}
}
DbContext.swap_event.RemoveRange(swapEvents);
DbContext.eod_swap.RemoveRange(eodSwaps);
DbContext.SaveChanges();
}
private List<int> GetAutoSwapClientCashIds(swap_event swapEvent)
{
if (swapEvent == null || string.IsNullOrWhiteSpace(swapEvent.EventData))
{
return new List<int>();
}
try
{
var unwindData = JsonConvert.DeserializeObject<UnwindData>(swapEvent.EventData);
return unwindData?.ClientCashIds?.Where(x => x > 0).Distinct().ToList() ?? new List<int>();
}
catch
{
return new List<int>();
}
}
protected virtual List<ClientCashInCashOut> GetLegacyAutoSwapClientCashRecords(List<swap_event> swapEvents, List<int> excludedClientCashIds)
{
if (swapEvents == null || !swapEvents.Any())
{
return new List<ClientCashInCashOut>();
}
var eventIds = swapEvents.Select(x => x.id).ToList();
var flowEvents = FindFlowEventsByEventIds(eventIds);
var manualClientCashIds = FindManualClientCashIds(swapEvents.First().SwapTradeId);
var records = new List<ClientCashInCashOut>();
foreach (var swapEvent in swapEvents)
{
UnwindData unwindData = null;
if (!string.IsNullOrWhiteSpace(swapEvent.EventData))
{
try
{
unwindData = JsonConvert.DeserializeObject<UnwindData>(swapEvent.EventData);
}
catch
{
}
}
var eventFlowEvents = flowEvents.Where(x => x.EventId == swapEvent.id).ToList();
var candidateDates = new HashSet<DateTime> { swapEvent.ValueDate.Date };
if (unwindData?.PayDate != null)
{
candidateDates.Add(unwindData.PayDate.Value.Date);
}
eventFlowEvents.Where(x => x.PayDate.HasValue).ToList().ForEach(x => candidateDates.Add(x.PayDate.Value.Date));
var allCashRecords = FindClientCashRecords(swapEvent.SwapTradeId);
var eventRecords = allCashRecords
.Where(x => !excludedClientCashIds.Contains(x.id)
&& !manualClientCashIds.Contains(x.id)
&& (x.Action == ClientCashInCashOut.系统操作_预付金返息 || x.Action == ClientCashInCashOut.系统操作_互换))
.ToList()
.Where(x => x.HappenDate.HasValue && candidateDates.Contains(x.HappenDate.Value.Date))
.Where(x => IsLegacyAutoSwapClientCashRecord(x, unwindData))
.ToList();
records.AddRange(eventRecords);
}
return records.GroupBy(x => x.id).Select(x => x.First()).ToList();
}
private bool IsLegacyAutoSwapClientCashRecord(ClientCashInCashOut cashRecord, UnwindData unwindData)
{
if (unwindData == null)
{
return true;
}
var amount = Convert.ToDecimal(cashRecord.Money ?? 0);
if (cashRecord.Action == ClientCashInCashOut.系统操作_预付金返息)
{
return unwindData.SwapMarginRebatePnl != 0
&& amount == -unwindData.SwapMarginRebatePnl;
}
if (cashRecord.Action == ClientCashInCashOut.系统操作_互换)
{
return (unwindData.SwapCloseAmount != 0 && amount == -unwindData.SwapCloseAmount)
|| (unwindData.SwapDividendPnl != 0 && amount == -unwindData.SwapDividendPnl)
|| (unwindData.SwapRealizedPnL != 0 && amount == -unwindData.SwapRealizedPnL);
}
return false;
}
/// <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();
}
}
}