Files
zszq-trs/YLErpDAL/Modules/TradeModule/TradeDalService.cs
T
2024-05-09 14:06:26 +08:00

489 lines
23 KiB
C#

using YLErp.BLL;
using YLErp.BLL.Eod;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Helpers;
using YLErp.Model;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.DataProviderModule;
using YLErp.Modules.TradeModule.DealModule;
namespace YLErp.Modules.TradeDalModule
{
/// <summary>
/// 交易操作服务
/// </summary>
public class TradeDalService : YLBaseService
{
public TradeDalService(YLBaseService baseService) : base(baseService)
{
}
public TradeDalService(OptUserInfo userInfo) : base(userInfo)
{
}
public void SetStructureInfo(IEnumerable<TradeLinq> trades)
{
IEnumerable<trade> lists = trades.Select(O => new trade
{
TradeType = O.TradeType,
id = O.id,
}).ToArray();
SetStructureInfo(lists);
foreach (var item in lists)
{
if (item.id <= 0) { continue; }
var t = trades.First(O => O.id == item.id);
t.SubTrades = item.SubTrades;
}
}
/// <summary>
/// 获取结构化交易信息
/// </summary>
public void SetStructureInfo(IEnumerable<trade> trades)
{
trades = trades.Where(n => n.TradeType == "结构化交易").ToArray();
if (!trades.Any())
{
return;
}
var tradeids = trades.Select(r => r.id).ToList();
var subTradeDic = new Dictionary<int, string>();
var subGrps = DbContext.trade.Where(n => tradeids.Contains(n.ParentTradeId)).Select(n => new OtcTradeDto
{
Strike = n.Strike,
BuySell = n.BuySell,
IsMoneynessOption = n.IsMoneynessOption,
ParentTradeId = n.ParentTradeId
}).ToArray().GroupBy(n => n.ParentTradeId).ToArray();
foreach (var grp in subGrps)
{
var trad = trades.First(n => n.id == grp.Key);
trad.SubTrades = grp.Select(O => new trade
{
Strike = O.Strike,
BuySell = O.BuySell,
IsMoneynessOption = O.IsMoneynessOption,
ParentTradeId = O.ParentTradeId
}).ToList();
}
}
public void SetStructureInfo(IEnumerable<trade> trades,List<trade> childTrades)
{
if (trades == null || childTrades == null)
{
return;
}
trades = trades.Where(n => n.TradeType == "结构化交易").ToArray();
if (!trades.Any())
{
return;
}
var tradeids = trades.Select(r => r.id).ToList();
var subTradeDic = new Dictionary<int, string>();
var subGrps = childTrades.Where(n => tradeids.Contains(n.ParentTradeId)).Select(n => new OtcTradeDto
{
Strike = n.Strike,
BuySell = n.BuySell,
IsMoneynessOption = n.IsMoneynessOption,
ParentTradeId = n.ParentTradeId
}).ToArray().GroupBy(n => n.ParentTradeId).ToArray();
foreach (var grp in subGrps)
{
var trad = trades.First(n => n.id == grp.Key);
trad.SubTrades = grp.Select(O => new trade
{
Strike = O.Strike,
BuySell = O.BuySell,
IsMoneynessOption = O.IsMoneynessOption,
ParentTradeId = O.ParentTradeId
}).ToList();
}
}
/// <summary>
/// 设置交易
/// </summary>
public void SetSubTradeList(List<trade> trades)
{
var subTradeDic = trades.Where(t => t.ParentTradeId > 0).AsEnumerable().GroupBy(t => t.ParentTradeId).ToDictionary(g => g.Key, g => g.ToList());
foreach (var trade in trades)
{
if (trade.TradeType == "结构化交易" && subTradeDic.ContainsKey(trade.id))
{
trade.SubTrades = subTradeDic[trade.id];
}
}
}
public TradeWithSettlement GetTradeWithSettlementTradeCash(trade trade)
{
var result = new TradeWithSettlement();
if (!ConsTrade.TradeTypesForHedge.Contains(trade.TradeType) && trade.TradeType != "现金流交易")
{
var CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetCountRatio(trade.UnderlyingCode);
trade.TradeOriginalAmount = trade.OriginalNotional / CountRatio;
}
trade.LotsNewInfo = TradeLotsCalc.GetLots(trade.UnderlyingCode, trade.Notional);
if (!string.IsNullOrEmpty(trade.PairTrade))
{
var pairTrade = DbContext.trade.FirstOrDefault(x => x.id.ToString() == trade.PairTrade);
trade.PairTradeNumber = pairTrade == null ? "" : pairTrade.TradeNumber;
}
else
{
trade.PairTradeNumber = "";
}
if (trade.TradeType == "合成价差期权")
{
trade.SyntheticUnderlyingTipsInfo = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
}
tradeBLL.SetFieldsByTradeType(trade);
//了结交易的持仓数量及份额需要为0
if (ConsTrade.TradeCompleteStatus.Contains(trade.TradeStatus))
{
trade.TradeAmount = 0;
trade.Notional = 0;
}
if (!ConsTrade.TradeTypesForHedge.Contains(trade.TradeType))
{
var tradeCashList = DbContext.trade_cash.Where(t =>
t.TradeId == trade.id && t.ValidState != ConsGlobal.InValid && !t.IsDeleted &&
(t.Action == ClientCashInCashOut.系统操作_行权费 || t.Action == ClientCashInCashOut.系统操作_平仓费 || t.Action == ClientCashInCashOut.系统操作_互换 || t.Action == ClientCashInCashOut.系统操作_票息)).OrderBy(t => t.ValueDate).ToList();
var tradeCashSwaps = DbContext.trade_cash_swap.Where(x => x.TradeId == trade.id).ToList();
tradeCashList.ForEach(tradeCash =>
{
if (trade.IsGroup == 1)
{
var winloss = 0.0;
var tradeCashs = DbContext.trade_cash.Where(x => x.ParentTradeCashId == tradeCash.id).ToList();
tradeCashs.ForEach(x =>
{
var tradeCashDetail = DbContext.trade_cash_detail.Where(y => y.TradeCashId == x.id);
var amount = tradeCashDetail.Any() ? tradeCashDetail.Sum(y => y.Amount ?? 0) : x.Amount;
var childTrade = DbContext.trade.Find(x.TradeId);
winloss += amount + (childTrade.TradePrice ?? 0) * (x.UnwindPercentRate ?? 0) * ((childTrade.BuySell == "卖出") ? 1 : -1);
});
tradeCash.WinLoss = winloss.OtcFormatMoney(grouping: false);
}
else
{
var tradeCashDetail = DbContext.trade_cash_detail.Where(x => x.TradeCashId == tradeCash.id);
var amount = tradeCashDetail.Any() ? tradeCashDetail.Sum(x => x.Amount ?? 0) : tradeCash.Amount;
tradeCash.WinLoss = (amount + (trade.TradePrice ?? 0) * (tradeCash.UnwindPercentRate ?? 0) * ((trade.BuySell == "卖出" || trade.TradeType == "远期") ? 1 : -1)).OtcFormatMoney(grouping: false);
if (PS.Config.IsGuoJun)
{
var Quoteamount = tradeCashDetail.Any() ? tradeCashDetail.Sum(y => y.QuoteAmount ?? 0) : (tradeCash.QuoteAmount ?? 0);
tradeCash.QuoteWinloss = (Quoteamount + (trade.TradePrice ?? 0) / (tradeCash.CurrencyRate ?? 1) * (tradeCash.UnwindPercentRate ?? 0) * ((trade.BuySell == "卖出") ? 1 : -1)).OtcFormatMoney(grouping: false);
}
}
tradeCash.SingleWinPrice = Math.Abs(tradeCash.Action == "系统操作-平仓费" && trade.IsUsePremiumRate == true ? TradeHelper.GetTradeSinglePriceByPremiumRate(tradeCash.UnwindPricePercentRate, trade.SpotPrice) : (tradeCash.UnwindPrice ?? 0));
tradeCash.SingleWinPriceString = trade.IsUsePremiumRate == true && tradeCash.Action == "系统操作-平仓费" ? (tradeCash.UnwindPricePercentRate ?? 0).OtcFormat(OtcFormatFlag.premiumRateP) : tradeCash.SingleWinPrice.OtcFormat(OtcFormatFlag.tradeSinglePrice);
tradeCash.SingleWinPricePercent = tradeCash.UnwindPricePercentRate ?? 0;
if (trade.TradeType == "收益互换")
{
tradeCash.trade_cash_swap = tradeCashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id);
}
});
var unWindTradeCashList = tradeCashList.Where(t => t.Action == ClientCashInCashOut.系统操作_平仓费 || (t.Action == ClientCashInCashOut.系统操作_行权费 && t.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权))
.OrderBy(t => t.ValueDate).ToList();
if (trade.TradeType == "累计期权")
{
//部分行权的记录展示在累计收益tab页面了,所以过滤掉
unWindTradeCashList = unWindTradeCashList.Where(x => x.UnwindType != "部分行权").ToList();
}
var swapTradeCashList = tradeCashList.Where(t => t.Action == ClientCashInCashOut.系统操作_互换)
.OrderBy(t => t.ValueDate).ToList();
var couponTradeCashList = tradeCashList.Where(t => t.Action == ClientCashInCashOut.系统操作_票息)
.OrderBy(t => t.ValueDate).ToList();
var maturityTradeCash = tradeCashList.FirstOrDefault(t => t.Action == ClientCashInCashOut.系统操作_行权费 && t.ExerciseWay != TradeCashExerciseWayEnum.提前终止行权 && t.IsLastAction);
if (maturityTradeCash != null)
{
maturityTradeCash.NotionalPercent = maturityTradeCash.UnwindPercentRate ?? 0;
}
bool ActualHasMinusValueOptions = valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1 ? ConsTrade.HasMinusValueOptions.Contains(trade.TradeType) : !ConsTrade.HasMinusValueOptions.Contains(trade.TradeType);
unWindTradeCashList.ForEach(x =>
{
x.NotionalPercent = x.UnwindPercentRate ?? 0;
x.UnwindStockEqvNotional = (trade.OriginalStockEqvNotional ?? 0) * (x.UnwindPercentRate ?? 0);
if (x.HappenedDate != null)
{
x.ValueDate = x.HappenedDate.Value;
}
x.UnwindPrice = ActualHasMinusValueOptions || trade.TradeType == "远期" || trade.TradeType == "收益互换" ? x.UnwindPrice : x.UnwindPrice * (trade.BuySell == "买入" ? 1 : -1);
x.UnwindPricePercentRate = ActualHasMinusValueOptions || trade.TradeType == "远期" || trade.TradeType == "收益互换" ? x.UnwindPricePercentRate : x.UnwindPricePercentRate * (trade.BuySell == "买入" ? 1 : -1);
x.Amount = x.Amount * (valuedateBLL.SystemDate.UnwindAmountAngle == 1 || trade.TradeType == "远期" || trade.TradeType == "收益互换" ? 1 : EodOperationBase.GetSign(trade.BuySell));
x.QuoteAmount = x.QuoteAmount * (valuedateBLL.SystemDate.UnwindAmountAngle == 1 || trade.TradeType == "远期" || trade.TradeType == "收益互换" ? 1 : EodOperationBase.GetSign(trade.BuySell));
});
swapTradeCashList.ForEach(x =>
{
x.InitialAmount = x.Amount - (x.ExtraAmount ?? 0);
x.InitialSpotPrice = trade.SpotPrice ?? 0;
x.StockEqvNotional = (trade.OriginalStockEqvNotional ?? 0) * (x.NotionalPercentRate ?? 0);
});
result.UnwindTradeCashList = unWindTradeCashList;
if (trade.IsGroup == 1 && trade.TradeType == "收益互换" && unWindTradeCashList.Any())
{
var unwindTradeCash = unWindTradeCashList.FirstOrDefault();
var childrenTradeCashList = DbContext.trade_cash.Where(t =>
t.ParentTradeCashId == unwindTradeCash.id && t.ValidState != "InValid" && !t.IsDeleted &&
(t.Action == ClientCashInCashOut.系统操作_行权费 || t.Action == ClientCashInCashOut.系统操作_平仓费 || t.Action == ClientCashInCashOut.系统操作_互换)).OrderBy(t => t.ValueDate).ToList();
var childrenTradeCashIds = childrenTradeCashList.Select(x => x.id).ToList();
var childrenTradeCashSwaps = DbContext.trade_cash_swap.Where(x => childrenTradeCashIds.Contains(x.TradeCashId)).ToList();
var childrenTradeIds = childrenTradeCashList.Select(x => x.TradeId).ToList();
var childrenTrades = DbContext.trade.Where(x => childrenTradeIds.Contains(x.id)).ToList();
var childrenTradeSwaps = DbContext.trade_swap.Where(x => childrenTradeIds.Contains(x.TradeId)).ToList();
childrenTradeCashList.ForEach(tradeCash =>
{
var childTrade = childrenTrades.FirstOrDefault(y => y.id == tradeCash.TradeId);
var childrenTradeSwap = childrenTradeSwaps.FirstOrDefault(y => y.TradeId == tradeCash.TradeId);
tradeCash.UnderlyingCode = childTrade.UnderlyingCode;
tradeCash.CallPut = childrenTradeSwap.IsPayFloatingProfit ? childrenTradeSwap.PayLongShort : childrenTradeSwap.GetLongShort;
var tradeCashDetail = DbContext.trade_cash_detail.Where(x => x.TradeCashId == tradeCash.id);
var amount = tradeCashDetail.Any() ? tradeCashDetail.Sum(x => x.Amount ?? 0) : tradeCash.Amount;
tradeCash.WinLoss = (amount + (childTrade.TradePrice ?? 0) * (tradeCash.UnwindPercentRate ?? 0) * ((childTrade.BuySell == "卖出") ? 1 : -1)).OtcFormatMoney(grouping: false);
if (childTrade.TradeType == "收益互换")
{
tradeCash.trade_cash_swap = childrenTradeCashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id);
}
});
result.UnwindChildrenTradeCashList = childrenTradeCashList;
}
result.MaturityTradeCash = maturityTradeCash;
result.SwapTradeCashList = swapTradeCashList;
result.CouponTradeCashList = couponTradeCashList;
if (trade.ExerciseDate < valuedateBLL.ValueDate && trade.CanExpire())
{
if (EodPriceQueryService.TryGetEodPrice(trade.ExerciseDate.Value, trade.UnderlyingCode, out var eodPrice))
{
trade.FinalPrice = eodPrice.GetPrice(trade.SettlementType);
}
}
}
result.Trade = trade;
return result;
}
/// <summary>
/// 获取交易信息
/// <para>优先从eod表中取</para>
/// </summary>
/// <param name="ids"></param>
/// <param name="valueDate"></param>
/// <param name="useTracking">是否需要跟踪引用,用于需要对结果进行修改并保存的操作</param>
/// <returns></returns>
public List<trade> GetTradeOrEodTrade(IEnumerable<int> ids, DateTime valueDate, bool useTracking = false)
{
if (ids is null)
{
throw new ArgumentNullException(nameof(ids));
}
var eodTradeArr = (from et in DbContext.eod_trade.AsNoTracking()
where et.ValueDate == valueDate
&& ids.Contains(et.TradeId)
select et).ToArray();
var newIds = ids.Except(eodTradeArr.Select(O => O.TradeId)).ToArray();
List<trade> tradeList = null;
if (newIds.Length < 1)
{
tradeList = new List<trade>();
}
else
{
tradeList = (useTracking ? DbContext.trade : DbContext.trade.AsNoTracking())
.Where(t => newIds.Contains(t.id) && t.ValidState != "InValid").ToList();
tradeBLL.SetFieldsByTradeType(tradeList);
foreach (var t in tradeList)
{
if (t.TradeType == "累计期权")
{
new TradeModule.OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(t, valueDate);
}
}
}
if (useTracking)
{
tradeList.AddRange(TrackTrade(eodTradeArr));
}
else
{
tradeList.AddRange(eodTradeArr.Select(O => O.trade));
}
return tradeList;
}
/// <summary>
/// 根据tradeId或子交易Id
/// 用于生成交易确认书的,该方法会根据交易日去获取eodtrade而非valuedate
/// </summary>
public List<trade> GetTradeOrEodTradeOfTidASid(IEnumerable<int> tradeIds, DateTime valueDate, bool useTracking = false, bool withNoGroupChildrenTrades = true, bool useTradeDate = true)
{
if (tradeIds is null)
{
throw new ArgumentNullException(nameof(tradeIds));
}
var pids = DbContext.trade.Where(c => tradeIds.Contains(c.id) && c.ParentTradeId > 0).Select(d => d.ParentTradeId).ToArray();
var idset = new HashSet<int>(tradeIds.Concat(pids).ToArray());
return GetTradeOrEodTradeOfTidAPid(idset, valueDate, useTracking, withNoGroupChildrenTrades, useTradeDate);
}
/// <summary>
/// 根据tradeId或ParentTradeId获取交易信息
/// <para>优先从eod表中取</para>
/// </summary>
public List<trade> GetTradeOrEodTradeOfTidAPid(IEnumerable<int> tradeIds, DateTime valueDate, bool useTracking = false, bool withNoGroupChildrenTrades = true, bool useTradeDate = false)
{
if (tradeIds is null)
{
throw new ArgumentNullException(nameof(tradeIds));
}
var eodTradeArr = (from et in DbContext.eod_trade
where et.ValueDate == valueDate
&& (tradeIds.Contains(et.TradeId) || tradeIds.Contains(et.ParentTradeId))
select et).ToArray();
//生成确认书时,需要根据交易日获取当天的收盘数据,以防trade表会因为除权除息改变数据了
if (useTradeDate)
{
eodTradeArr = (from et in DbContext.eod_trade
join trade in DbContext.trade on new { id = et.TradeId, tradeDate = et.ValueDate } equals new { trade.id, tradeDate = trade.TradeDate ?? DateTime.Now }
where tradeIds.Contains(et.TradeId) || tradeIds.Contains(et.ParentTradeId)
select et).ToArray();
}
var eodTradeIds = eodTradeArr.Select(O => O.TradeId).ToArray();
var tradeList = (from t in useTracking ? DbContext.trade : DbContext.trade.AsNoTracking()
where !eodTradeIds.Contains(t.id) && (tradeIds.Contains(t.id) || tradeIds.Contains(t.ParentTradeId))
&& t.ValidState != "InValid"
select t).ToList();
if (withNoGroupChildrenTrades)
{
tradeList = (from t in useTracking ? DbContext.trade : DbContext.trade.AsNoTracking()
where !eodTradeIds.Contains(t.id) && (tradeIds.Contains(t.id) || tradeIds.Contains(t.ParentTradeId))
&& t.ValidState != "InValid"
&& t.IsGroup != 2
select t).ToList();
}
tradeBLL.SetFieldsByTradeType(tradeList);
if (useTracking)
{
tradeList.AddRange(TrackTrade(eodTradeArr));
}
else
{
tradeList.AddRange(eodTradeArr.Select(O => O.trade));
}
return tradeList;
}
/// <summary>
/// 获取结构化交易信息
/// <para>优先从eod表中取</para>
/// </summary>
/// <param name="parentIds"></param>
/// <param name="valueDate"></param>
/// <returns></returns>
public List<trade> GetStructTradeFromTradeOrEodTrade(IEnumerable<int> parentIds, DateTime valueDate, bool useTracking = false)
{
if (parentIds is null)
{
throw new ArgumentNullException(nameof(parentIds));
}
var eodTradeArr = (from et in DbContext.eod_trade
where et.ValueDate == valueDate
&& (parentIds.Contains(et.ParentTradeId))
select et).ToArray();
List<trade> tradeList = null;
var newIds = parentIds.Except(eodTradeArr.Select(O => O.ParentTradeId)).ToArray();
if (newIds.Length < 1)
{
tradeList = new List<trade>();
}
else
{
tradeList = (from t in useTracking ? DbContext.trade : DbContext.trade.AsNoTracking()
where newIds.Contains(t.ParentTradeId)
&& t.ValidState != "InValid"
select t).ToList();
}
if (useTracking)
{
tradeList.AddRange(TrackTrade(eodTradeArr));
}
else
{
tradeList.AddRange(eodTradeArr.Select(O => O.trade));
}
return tradeList;
}
/// <summary>
/// 将交易还原到某日收盘之前
/// <para>主要针对除权除息过的交易</para>
/// </summary>
/// <param name="t"></param>
/// <param name="valueDate"></param>
public void RollbackToBeforeSettle(trade t, DateTime valueDate)
{
var originTrade = GetTradeOrEodTrade(new[] { t.id }, valueDate).FirstOrDefault();
if (originTrade != null && originTrade.Notional > 0)
{
//将交易信息还原到收盘前
DividendService.SetDividendTradeData(t, originTrade);
}
}
private List<trade> TrackTrade(IEnumerable<eod_trade> eodTrades)
{
var result = new List<trade>();
var eodIds = eodTrades.Select(O => O.TradeId);
var trades = eodTrades.Select(O => O.trade);
var trackTrades = DbContext.trade.Where(O => eodIds.Contains(O.id)).ToDictionary(K => K.id, V => V);
foreach (var item in trades)
{
DividendService.SetDividendTradeData(trackTrades[item.id], item);
result.Add(trackTrades[item.id]);
}
return result;
}
}
}