414 lines
14 KiB
C#
414 lines
14 KiB
C#
namespace YLErp.Modules.TradeModule
|
|
{
|
|
/// <summary>
|
|
/// 交易现金流水数据提供
|
|
/// (逻辑迁移自tradecontroller.tradeQuery)
|
|
/// </summary>
|
|
public class TradeCashProvider : YLBaseService
|
|
{
|
|
IEnumerable<TpData> _tpdatas;
|
|
Dictionary<int, trade_cash[]> _cashDic;
|
|
|
|
public TradeCashProvider(YLBaseService baseService) : base(baseService)
|
|
{
|
|
}
|
|
|
|
public TradeCashProvider(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 必须要初始化
|
|
/// </summary>
|
|
public TradeCashProvider Initialize(IEnumerable<int> tradeIds)
|
|
{
|
|
if (tradeIds is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(tradeIds));
|
|
}
|
|
|
|
if (!tradeIds.Any(n => n > 0))
|
|
{
|
|
_tpdatas = Enumerable.Empty<TpData>();
|
|
_cashDic = new Dictionary<int, trade_cash[]>(0);
|
|
return this;
|
|
}
|
|
|
|
//获取结构化交易对应的子交易ID
|
|
var idSet = new HashSet<int>(tradeIds);
|
|
|
|
var tpQuery = from t in DbContext.trade
|
|
where t.ParentTradeId > 0 && tradeIds.Contains(t.ParentTradeId)
|
|
orderby t.ParentTradeId
|
|
select new TpData { TradeId = t.id, ParentTradeId = t.ParentTradeId, IsGroup = t.IsGroup };
|
|
|
|
_tpdatas = tpQuery.ToArray();
|
|
|
|
foreach (var item in _tpdatas)
|
|
{
|
|
idSet.Add(item.TradeId);
|
|
if (item.IsGroup == 0)
|
|
{
|
|
idSet.Remove(item.ParentTradeId);
|
|
}
|
|
}
|
|
|
|
//获取tradecash数据
|
|
_cashDic = DbContext.trade_cash.Where(t => t.ValidState != ConsGlobal.InValid && idSet.Contains(t.TradeId) && !t.IsDeleted)
|
|
.ToArray().GroupBy(n => n.TradeId).ToDictionary(n => n.Key, m => m.OrderBy(n => n.ValueDate).ThenBy(n => n.id).ToArray());
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 必须要初始化
|
|
/// </summary>
|
|
public TradeCashProvider Initialize(IEnumerable<int> tradeIds,List<trade> childList)
|
|
{
|
|
if (tradeIds is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(tradeIds));
|
|
}
|
|
|
|
if (!tradeIds.Any(n => n > 0))
|
|
{
|
|
_tpdatas = Enumerable.Empty<TpData>();
|
|
_cashDic = new Dictionary<int, trade_cash[]>(0);
|
|
return this;
|
|
}
|
|
|
|
//获取结构化交易对应的子交易ID
|
|
var idSet = new HashSet<int>(tradeIds);
|
|
|
|
if (childList != null && childList.Count > 0)
|
|
{
|
|
var tpQuery = from t in childList
|
|
where t.ParentTradeId > 0 && tradeIds.Contains(t.ParentTradeId)
|
|
orderby t.ParentTradeId
|
|
select new TpData { TradeId = t.id, ParentTradeId = t.ParentTradeId, IsGroup = t.IsGroup };
|
|
|
|
_tpdatas = tpQuery.ToArray();
|
|
}
|
|
else
|
|
{
|
|
_tpdatas = new List<TpData>();
|
|
}
|
|
|
|
|
|
foreach (var item in _tpdatas)
|
|
{
|
|
idSet.Add(item.TradeId);
|
|
if (item.IsGroup == 0)
|
|
{
|
|
idSet.Remove(item.ParentTradeId);
|
|
}
|
|
}
|
|
|
|
//获取tradecash数据
|
|
_cashDic = DbContext.trade_cash.Where(t => t.ValidState != ConsGlobal.InValid && idSet.Contains(t.TradeId) && !t.IsDeleted)
|
|
.ToArray().GroupBy(n => n.TradeId).ToDictionary(n => n.Key, m => m.OrderBy(n => n.ValueDate).ThenBy(n => n.id).ToArray());
|
|
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取交易了结详情
|
|
/// </summary>
|
|
public TradeCashUnwindDetail GetUnwindDetail(trade trade, string tradeType = null)
|
|
{
|
|
if (_cashDic == null)
|
|
{
|
|
throw new ServiceException("尚未初始化");
|
|
}
|
|
|
|
if (_cashDic.TryGetValue(trade.id, out var tcList))
|
|
{
|
|
var tradeCashUnwindDetail = GetUnwindDetail(trade.id, tradeType, tcList);
|
|
if (trade.IsGroup == 1)
|
|
{
|
|
var childTradeCashs = DbContext.trade_cash.Where(x => x.ParentTradeId == trade.id && x.ValidState != "InValid" && x.Action != ClientCashInCashOut.系统操作_期权费).ToList();
|
|
var childTradeIds = childTradeCashs.Select(x => x.TradeId).Distinct().ToList();
|
|
var childTrades = DbContext.trade.Where(x => childTradeIds.Contains(x.id)).ToList();
|
|
tradeCashUnwindDetail.UnWindTotalFee = childTradeCashs.Sum(x => x.Amount);
|
|
tradeCashUnwindDetail.RealizedPnl = tradeCashUnwindDetail.UnWindTotalFee + childTradeCashs.Sum(x => (x.UnwindPercentRate ?? 0) * (childTrades.FirstOrDefault(y => y.id == x.TradeId)?.TradePrice ?? 0) * (childTrades.FirstOrDefault(y => y.id == x.TradeId).BuySell == "买入" ? -1 : 1));
|
|
}
|
|
return tradeCashUnwindDetail;
|
|
}
|
|
|
|
//使用结构化交易处理方式
|
|
|
|
TradeCashUnwindDetail detail = null;
|
|
|
|
foreach (var item in _tpdatas)
|
|
{
|
|
if (item.ParentTradeId == trade.id && trade.IsGroup == 0)
|
|
{
|
|
if (_cashDic.TryGetValue(item.TradeId, out var tcList2))
|
|
{
|
|
var detail2 = GetUnwindDetail(item.TradeId, tradeType, tcList2);
|
|
if (detail == null)
|
|
{
|
|
detail = detail2;
|
|
}
|
|
else
|
|
{
|
|
var RealizedPnl = detail.RealizedPnl + detail2.RealizedPnl;
|
|
var UnWindTotalFee = detail.UnWindTotalFee + detail2.UnWindTotalFee;
|
|
|
|
if (detail.UnWindDate < detail2.UnWindDate || (detail.UnWindDate == detail2.UnWindDate && detail2.LastTcId > detail.LastTcId))
|
|
{
|
|
detail = detail2; //去了结日期最晚的数据
|
|
}
|
|
|
|
detail.RealizedPnl = RealizedPnl;
|
|
detail.UnWindTotalFee = UnWindTotalFee;
|
|
}
|
|
}
|
|
}
|
|
else if (detail != null)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return detail;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 批量获取交易了结详情
|
|
/// </summary>
|
|
public List<TradeCashUnwindDetail> BatchGetUnwindDetail(IEnumerable<trade> tradeList, List<trade> childList)
|
|
{
|
|
if (_cashDic == null)
|
|
{
|
|
throw new ServiceException("尚未初始化");
|
|
}
|
|
var res=new List<TradeCashUnwindDetail>();
|
|
|
|
|
|
var isGroupTradeIds = tradeList.Where(p => p.IsGroup == 1).Select(p => p.id).Distinct().ToList();
|
|
List<trade_cash> tradeCashList =null;
|
|
if(isGroupTradeIds!=null&& isGroupTradeIds.Count > 0)
|
|
{
|
|
tradeCashList = DbContext.trade_cash.Where(x => isGroupTradeIds.Contains(x.ParentTradeId) && x.ValidState != "InValid" && x.Action != ClientCashInCashOut.系统操作_期权费).ToList();
|
|
}
|
|
if (tradeCashList == null)
|
|
{
|
|
tradeCashList = new List<trade_cash>();
|
|
}
|
|
|
|
foreach (var trade in tradeList)
|
|
{
|
|
if (_cashDic.TryGetValue(trade.id, out var tcList))
|
|
{
|
|
var tradeCashUnwindDetail = GetUnwindDetail(trade.id, "", tcList);
|
|
if (trade.IsGroup == 1)
|
|
{
|
|
var childTradeCashs = tradeCashList.Where(x => x.ParentTradeId == trade.id).ToList();
|
|
var childTradeIds = childTradeCashs.Select(x => x.TradeId).Distinct().ToList();
|
|
var childTrades = childList.Where(x => childTradeIds.Contains(x.id)).ToList();
|
|
tradeCashUnwindDetail.UnWindTotalFee = childTradeCashs.Sum(x => x.Amount);
|
|
tradeCashUnwindDetail.RealizedPnl = tradeCashUnwindDetail.UnWindTotalFee + childTradeCashs.Sum(x => (x.UnwindPercentRate ?? 0) * (childTrades.FirstOrDefault(y => y.id == x.TradeId)?.TradePrice ?? 0) * (childTrades.FirstOrDefault(y => y.id == x.TradeId).BuySell == "买入" ? -1 : 1));
|
|
}
|
|
res.Add(tradeCashUnwindDetail);
|
|
continue;
|
|
}
|
|
|
|
//使用结构化交易处理方式
|
|
|
|
TradeCashUnwindDetail detail = null;
|
|
|
|
foreach (var item in _tpdatas)
|
|
{
|
|
if (item.ParentTradeId == trade.id && trade.IsGroup == 0)
|
|
{
|
|
if (_cashDic.TryGetValue(item.TradeId, out var tcList2))
|
|
{
|
|
var detail2 = GetUnwindDetail(item.TradeId, "", tcList2);
|
|
if (detail == null)
|
|
{
|
|
detail = detail2;
|
|
}
|
|
else
|
|
{
|
|
var RealizedPnl = detail.RealizedPnl + detail2.RealizedPnl;
|
|
var UnWindTotalFee = detail.UnWindTotalFee + detail2.UnWindTotalFee;
|
|
|
|
if (detail.UnWindDate < detail2.UnWindDate || (detail.UnWindDate == detail2.UnWindDate && detail2.LastTcId > detail.LastTcId))
|
|
{
|
|
detail = detail2; //去了结日期最晚的数据
|
|
}
|
|
|
|
detail.RealizedPnl = RealizedPnl;
|
|
detail.UnWindTotalFee = UnWindTotalFee;
|
|
}
|
|
}
|
|
}
|
|
else if (detail != null)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (detail != null)
|
|
{
|
|
res.Add(detail);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
|
|
private TradeCashUnwindDetail GetUnwindDetail(int tradeId, string tradeType, IEnumerable<trade_cash> tcList)
|
|
{
|
|
var detail = new TradeCashUnwindDetail(tradeId);
|
|
|
|
trade_cash tcFirst = null, tcLast = null;
|
|
|
|
foreach (var tc in tcList)
|
|
{
|
|
if (tc.Action == "系统操作-期权费")
|
|
{
|
|
tcFirst = tc;
|
|
continue;
|
|
}
|
|
|
|
tcLast = tc;
|
|
|
|
if (tc.Action == "系统操作-行权费" || tc.Action == "系统操作-平仓费" || tc.IsLastAction)
|
|
{
|
|
detail.UnWindTimes++;
|
|
}
|
|
|
|
if (tc.Action == "系统操作-行权费")
|
|
{
|
|
tc.ActionTradeAmount = tc.TradeAmount ?? 0;
|
|
}
|
|
else
|
|
{
|
|
tc.ActionTradeAmount = tc.UnwindTradeAmount ?? 0;
|
|
}
|
|
|
|
detail.UnWindTotalFee += tc.Amount;
|
|
detail.UnWindTotalAmount += tc.ActionTradeAmount;
|
|
detail.UnWindPercent += tc.UnwindPercentRate ?? 0;
|
|
}
|
|
|
|
if (tcLast != null)
|
|
{
|
|
detail.LastTcId = tcLast.id;
|
|
|
|
if (tcLast.Action == "系统操作-行权费")
|
|
{
|
|
//到期收益/到期数目。 到期权利金即payoff=到期收益单价
|
|
if (Math.Abs(tcLast.ActionTradeAmount) > 0)
|
|
{
|
|
detail.UnWindSinglePrice = tcLast.Amount / tcLast.ActionTradeAmount;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//平仓权利金即平仓单价
|
|
detail.UnWindSinglePrice = tcLast.UnwindPrice ?? 0;
|
|
}
|
|
|
|
detail.UnWindUnderlyingPrice = tcLast.FinalPrice ?? 0;
|
|
detail.UnWindDate = tcLast.HappenedDate ?? tcLast.ValueDate;
|
|
}
|
|
|
|
detail.RealizedPnl = detail.UnWindTotalFee + (tcFirst == null ? 0 : tcFirst.Amount * detail.UnWindPercent);
|
|
|
|
return detail;
|
|
}
|
|
|
|
class TpData
|
|
{
|
|
public int TradeId { get; set; }
|
|
|
|
public int ParentTradeId { get; set; }
|
|
|
|
public int IsGroup { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return TradeId + "--" + ParentTradeId;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 交易了结详情
|
|
/// </summary>
|
|
public class TradeCashUnwindDetail
|
|
{
|
|
public TradeCashUnwindDetail(int tradeId)
|
|
{
|
|
TradeId = tradeId;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 交易ID
|
|
/// </summary>
|
|
public int TradeId { get; set; }
|
|
|
|
/// <summary>
|
|
/// 交易现金数据ID(最后一次)
|
|
/// </summary>
|
|
public int LastTcId { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结百分比(总计)
|
|
/// </summary>
|
|
public double UnWindPercent { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结总数
|
|
/// </summary>
|
|
public double UnWindTotalAmount { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结总额
|
|
/// </summary>
|
|
public double UnWindTotalFee { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结次数
|
|
/// </summary>
|
|
public int UnWindTimes { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结日期(最后一次)
|
|
/// </summary>
|
|
public DateTime? UnWindDate { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结数量(最后一次)
|
|
/// </summary>
|
|
public double UnWindAmount { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结单价(最后一次)
|
|
/// </summary>
|
|
public double UnWindSinglePrice { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结标的价格(最后一次)
|
|
/// </summary>
|
|
public double UnWindUnderlyingPrice { get; set; }
|
|
|
|
/// <summary>
|
|
/// 实现盈亏(整体)
|
|
/// </summary>
|
|
public double RealizedPnl { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return TradeId.ToString();
|
|
}
|
|
}
|
|
}
|