Files
zszq-trs/YLErpDAL/Modules/EodModule/SettlementModule/Base/EodSettleDataQueryService.cs
T
2024-05-09 14:06:26 +08:00

339 lines
16 KiB
C#

using System.Linq.Expressions;
using YLErp.BLL;
using YLErp.Modules.DataProviderModule;
using YLErp.Modules.TradeModule;
using YLErp.Modules.TradeModule.ForwardModule;
namespace YLErp.Modules.EodModule.SettlementModule
{
/// <summary>
/// 用于结算的数据查询服务
/// </summary>
public class EodSettleDataQueryService : YLBaseService
{
public EodSettleDataQueryService(OptUserInfo optUser) : base(optUser)
{
}
public EodSettleDataQueryService(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
/// 获取要结算的交易数据
/// </summary>
/// <param name="settleDate">结算日期</param>
/// <param name="tradeDataPredicate">交易数据查询过滤条件</param>
/// <param name="tradecashProvider">交易资金提供接口</param>
/// <param name="preSettleDate">上个结算日(多交易日历场景下的假日到期交易处理时使用)</param>
public List<trade> GetOtcTrades(DateTime settleDate, Expression<Func<trade, bool>> tradeDataPredicate
, out TradeCashDataProvider tradecashProvider, DateTime preSettleDate = default)
{
if (tradeDataPredicate is null)
{
throw new ArgumentNullException(nameof(tradeDataPredicate));
}
var tradeList = new List<trade>(1000);
//------------------------------------------------------
// eod trades
//------------------------------------------------------
var etQuery = from et in DbContext.eod_trade
join t in DbContext.trade.Where(tradeDataPredicate) on et.TradeId equals t.id
where et.ValueDate == settleDate
select new
{
t.id,
et.TradeId,
et.TradeJson,
t.BuySell,
t.AssetId,
t.ExerciseDate,
t.DividendRate,
t.TradeType
};
var etList = etQuery.ToArray();
List<TradeMeta> structProductTradeMetaList = null;
if (etList != null && etList.Length > 0)
{
var structProductTradeIds = etList.Where(p => "结构化产品".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList();
if (structProductTradeIds != null && structProductTradeIds.Count > 0)
{
structProductTradeMetaList = DbContext.TradeMeta.AsNoTracking().Where(d => structProductTradeIds.Contains(d.TradeId)).ToList();
}
}
if (structProductTradeMetaList == null)
{
structProductTradeMetaList = new List<TradeMeta>();
}
foreach (var item in etList)
{
try
{
var t = TradeHelper2.Deserialize(item.TradeJson);
t.id = item.TradeId;
t.BuySell = item.BuySell;
t.AssetId = item.AssetId;
if (t.ExerciseDate != item.ExerciseDate && !DbContext.ExtensionTime.Any(x => x.TradeId == t.id && x.IsValid && x.OldMaturityDate == t.ExerciseDate && x.NewMaturityDate == item.ExerciseDate && x.OptDate >= settleDate))
{
t.ExerciseDate = item.ExerciseDate;
}
t.MetaDic["from_eod_trade"] = "true";
tradeList.Add(t);
//先简单处理一下避免某些情况下删除eodtrade表数据
//比如手动在数据库改了观察频率回到历史收盘(手动改是因为回到历史收盘太慢了而且涉及到除权除息的各种问题)
if (t.TradeType == "雪球期权")
{
var snowball = DbContext.trade_snowball.Where(n => n.TradeId == item.id).Select(n => new
{
n.KOObservationDates,
n.ObservationDates,
n.KOObservationSettleDates
}).FirstOrDefault();
if (snowball != null && t.trade_snowball != null)
{
t.trade_snowball.ObservationDates = snowball.ObservationDates;
t.trade_snowball.KOObservationDates = snowball.KOObservationDates;
t.trade_snowball.KOObservationSettleDates = snowball.KOObservationSettleDates;
}
}
else if (t.TradeType == "凤凰期权")
{
var autocall = DbContext.trade_autocall.Where(n => n.TradeId == item.id).Select(n => new
{
n.ObservationDates,
n.KOObservationDates
}).FirstOrDefault();
if (autocall != null && t.trade_autocall != null)
{
t.trade_autocall.ObservationDates = autocall.ObservationDates;
t.trade_autocall.KOObservationDates = autocall.KOObservationDates;
}
}
else if (t.TradeType == "累计期权")
{
t.MetaDic.Remove("from_eod_trade");
new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(t, settleDate);
}
else if (t.TradeType == "远期")
{
var forwardTrade = DbContext.trade_forward.Where(n => n.TradeId == item.id).Select(n => new
{
n.ForwardValue,
n.OpenCommission
}).FirstOrDefault();
}
else if (t.TradeType == "结构化产品")
{
var tradeMetas = structProductTradeMetaList.Where(d => d.TradeId == t.id).ToDictionary(g => g.MetaKey, g => g.MetaValue);
if (tradeMetas != null && tradeMetas.Count > 0)
{
foreach (var d in tradeMetas)
{
if (!t.MetaDic.ContainsKey(d.Key))
{
t.MetaDic.Add(d.Key, d.Value);
}
}
}
}
else if (t.TradeType == "亚式期权")
{
if (t.trade_asian_option.PayoffType == "EnhancedArithmeticAverage" && t.trade_asian_option.EnhancedPrice == 0 && t.TradeDate < new DateTime(2023, 2, 19) && t.Strike.HasValue)
{
t.trade_asian_option.EnhancedPrice = t.Strike.Value;
}
}
//解决收盘时从hisdata取了null并且存入了eodtrade的情况下数据问题
if (t.DividendRate == null)
{
t.DividendRate = item.DividendRate;
}
}
catch (Exception ex)
{
LogFactory.GetLogger("eod_trade.TradeJson解析").Error(ex);
}
}
//------------------------------------------------------
// 多交易日历场景下的假日到期交易处理
//------------------------------------------------------
if (PS.Config.ErpElement.SupportMultiCalendar)
{
var pretQuery = from et in DbContext.eod_trade
join t in DbContext.trade on et.TradeId equals t.id
where et.ValueDate == preSettleDate
&& !DbContext.trade.Where(tradeDataPredicate).Any(n => n.id == et.TradeId)
select new
{
et.TradeId,
et.TradeJson,
t.BuySell,
t.UnderlyingCode
};
var pretList = pretQuery.ToArray();
if (pretList.Any())
{
var exHolidaySet = DataCacheProvider.GetMarketDataSource().AsQueryable()
.Where(n => !string.IsNullOrEmpty(n.ExchangeNo) && QdpModule.QdpCalendarHelper.IsHoliday(preSettleDate, n.CalendarName.TrimToNull() ?? ConsGlobal.DefaultCalendar))
.Select(n => n.ExchangeNo.ToUpperInvariant()).ToHashSet();
foreach (var item in pretList)
{
if (!tradeList.Any(x => x.id == item.TradeId))
{
var un = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode);
if (!string.IsNullOrEmpty(un.MarketCode) && exHolidaySet.Contains(un.MarketCode))
{
try
{
var t = TradeHelper2.Deserialize(item.TradeJson);
t.id = item.TradeId;
t.BuySell = item.BuySell;
t.MetaDic["from_eod_trade"] = "true";
tradeList.Add(t);
}
catch (Exception ex)
{
LogFactory.GetLogger("eod_trade.TradeJson解析").Error(ex);
}
}
}
}
}
}
//------------------------------------------------------
// 没有出现在eodtrae表中的交易数据
//------------------------------------------------------
var eodTradeIds = tradeList.Select(n => n.id);
tradeDataPredicate = tradeDataPredicate.And(t => !eodTradeIds.Contains(t.id));
var trades = DbContext.trade.AsNoTracking().Where(tradeDataPredicate).ToArray();
//------------------------------------------------------
// 交易资金接口
//------------------------------------------------------
var tradeIds = trades.Select(x => x.id).ToList();
tradecashProvider = new TradeCashDataProvider().Initialize(eodTradeIds.Concat(tradeIds).ToArray());
var tradecashPreProvider = new TradeCashPreDataProvider().Initialize(eodTradeIds.Concat(tradeIds).ToArray());
//------------------------------------------------------
// 交易数据结果集
//------------------------------------------------------
if (!trades.Any())
{
return tradeList;
}
tradeList.AddRange(trades);
structProductTradeMetaList = null;
if (trades != null && trades.Length > 0)
{
var structProductTradeIds = trades.Where(p => "结构化产品".Equals(p.TradeType)).Select(p => p.id).Distinct().ToList();
if (structProductTradeIds != null && structProductTradeIds.Count > 0)
{
structProductTradeMetaList = DbContext.TradeMeta.AsNoTracking().Where(d => structProductTradeIds.Contains(d.TradeId)).ToList();
}
}
if (structProductTradeMetaList == null)
{
structProductTradeMetaList = new List<TradeMeta>();
}
foreach (var t in trades)
{
if (t.TradeType == "累计期权")
{
new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(t, settleDate);
}
if (t.TradeType == "结构化产品")
{
var tradeMetas = structProductTradeMetaList.Where(d => d.TradeId == t.id).ToDictionary(g => g.MetaKey, g => g.MetaValue);
if (tradeMetas != null && tradeMetas.Count > 0)
{
foreach (var d in tradeMetas)
{
if (!t.MetaDic.ContainsKey(d.Key))
{
t.MetaDic.Add(d.Key, d.Value);
}
}
}
}
ProcessTrade(settleDate, tradecashProvider, tradecashPreProvider, t);
}
return tradeList;
}
public static void ProcessTrade(DateTime settleDate, TradeCashDataProvider tradecashProvider, TradeCashPreDataProvider tradecashPreProvider, trade t)
{
//存在收盘之后的了结记录,代表收盘日那天,交易为确认成交状态
var tradeCashs = tradecashProvider.GetTradeCashes(t.id).Where(x => x.ValidState != "InValid" && !x.IsDeleted && x.Action != "系统操作-期权费" && (x.HappenedDate > settleDate || x.ValueDate > settleDate && x.HappenedDate == null));
t.TradeStatus = tradeCashs.Any() ? ConsTrade.确认成交 : t.TradeStatus;
//收历史盘时,找到收盘日之前最近一次的了结日期
var lastSecondTradeCash = tradecashProvider.GetTradeCashes(t.id).Where(x => x.ValidState != "InValid" && !x.IsDeleted && x.Action != "系统操作-期权费" && (x.HappenedDate <= settleDate || x.ValueDate <= settleDate && x.HappenedDate == null)).OrderByDescending(y => y.id).FirstOrDefault();
t.UnWindDate = lastSecondTradeCash?.HappenedDate ?? lastSecondTradeCash?.ValueDate;
if (ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus))
{
t.Notional = 0;
t.TradeAmount = 0;
t.StockEqvNotional = 0;
}
else
{
var tc = tradeCashs.Where(x => x.Notional != 0).FirstOrDefault();
if (tc != null)
{
t.Notional = tc.Notional;
}
else
{
//取第一个ValueDate大于settleDate的TradeCash数据(TradeCashPreDataProvider类中ValueDate已做正序处理)
var tcPrePredicate = new Func<trade_cash_pre, bool>(x => x.Action != "系统操作-期权费" && x.Notional != 0
&& x.ValueDate > settleDate && (x.HappenedDate > settleDate || x.HappenedDate == null));
var tcPre = tradecashPreProvider.GetTradeCashPres(t.id).FirstOrDefault(tcPrePredicate);
if (tcPre != null)
{
t.Notional = tcPre.Notional;
}
}
if (t.TradeType == ConsGlobal.TradeType.CashFlow)
{
t.TradeAmount = 0;
t.StockEqvNotional = t.Notional;
}
else
{
var CountRatio = (DataCacheProvider.GetUnderlyingDataSource().GetData(t.UnderlyingId)?.CountRatio) ?? 1;
t.TradeAmount = t.Notional / CountRatio;
t.StockEqvNotional = t.OriginalNotional == 0 ? 0 : (t.Notional / t.OriginalNotional * t.OriginalStockEqvNotional) ?? 0;
}
}
tradeBLL.SetFieldsByTradeType(t, settleDate);
}
}
}