using YLErp.BLL; using YLErp.BLL.Eod; using YLErp.Model; namespace YLErp.Modules.RiskListModule { public class RiskDailyReportService : YLBaseService { /// /// 年盈亏起算日 /// public DateTime CurrentStartDate { get; private set; } /// /// 年累计盈亏截止日 /// 最后一次收盘成功的日期 /// public DateTime CurrentEndDate { get; private set; } /// /// 上年累计盈亏截止日 /// public DateTime LastYearEndDate { get; private set; } /// /// 前一次收盘日期 /// 用于计算截止日价差 /// public DateTime CurrentLastDate { get; private set; } /// /// 总资金 /// public double Total { get; private set; } /// /// 可用资金 /// public double Available { get; private set; } /// /// 客户权益 /// public double CurrFund { get; private set; } /// /// 预付金占用 /// public double CurrMargin { get; private set; } public RiskDailyReportService(OptUserInfo userInfo, DateTime valueDate) : base(userInfo) { CurrentStartDate = valuedateBLL.SystemDate.AccruedTotalPnlStartDate.GetValueOrDefault(); CurrentEndDate = EodOperationBase.GetLastSettlementDate(valueDate); LastYearEndDate = CurrentStartDate == default(DateTime) ? CurrentStartDate : valuedateBLL.GetNonHolidayDefore(CurrentStartDate.AddDays(-1)); CurrentLastDate = valuedateBLL.GetNonHolidayDefore(CurrentEndDate.AddDays(-1)); var account = DbContext.eod_exchange_account.Where(O => O.ValueDate == CurrentEndDate).ToList(); Total = account.Sum(O => O.Total); Available = account.Sum(O => O.Available); CurrFund = account.Sum(O => O.CurrFund); CurrMargin = account.Sum(O => O.CurrMargin); } /// /// 重置累计总盈亏字段值 /// /// /// /// private List ResetOptionAccruedTotalPnL(List objs, DateTime valueDate, List settleTradeIds) where T : EodTradePosition, new() { var result = objs.Select(O => (T)O.Clone()).ToList(); if (valueDate > this.LastYearEndDate) { var dbTable = DbContext.Set(); var ids = result.Where(O => !settleTradeIds.Contains(O.TradeId)).Select(O => O.TradeId).ToList(); var list = (from eodDb in dbTable where eodDb.ValueDate == LastYearEndDate && ids.Contains(eodDb.TradeId) select eodDb).ToList(); list.ForEach(O => { var item = result.Find(B => B.TradeId == O.TradeId); item.TotalPnL -= O.TotalPnL; }); } return result; } /// /// 重置累计总盈亏字段值 /// /// /// /// private List ResetFutureAccruedTotalPnL(List objs, DateTime valueDate) where T : EodTradePosition, new() { var result = objs.Select(O => (T)O.Clone()).ToList(); if (valueDate > this.LastYearEndDate) { var dbTable = DbContext.Set(); var ids = result.Select(O => $"{O.UnderlyingCode}_{O.PositionType}_{O.BookId}").ToList(); var list = (from eodDb in dbTable where eodDb.ValueDate == LastYearEndDate select eodDb).ToList().FindAll(O => ids.Contains($"{O.UnderlyingCode}_{O.PositionType}_{O.BookId}")); list.ForEach(O => { var item = result.Find(B => $"{B.UnderlyingCode}_{B.PositionType}_{B.BookId}" == $"{O.UnderlyingCode}_{O.PositionType}_{O.BookId}"); item.TotalPnL -= O.TotalPnL; }); } return result; } public double GetOptionPositionAccruedTotalPnL(DateTime valueDate) where T : EodTradePosition, new() { var dbTable = DbContext.Set(); var tradeIdList = (from et in DbContext.eod_trade where et.ValueDate == valueDate && ConsTrade.LiveTradeStatusList.Contains(et.TradeStatus) && ConsTrade.OptionTradeTypes.Contains(et.TradeType)/* && !et.TradeJson.Contains("InValid")*/ select et.TradeId).ToArray(); var query = (from eodDb in dbTable where eodDb.ValueDate == valueDate && tradeIdList.Contains(eodDb.TradeId) select eodDb.TotalPnL).ToList().Sum(); var settlementPrice = (from cash in DbContext.trade_cash where tradeIdList.Contains(cash.TradeId) && ClientCashInCashOut.PROFIT_ACTION.Contains(cash.Action) && cash.ValidState != ConsGlobal.InValid && !cash.IsDeleted && cash.ValueDate <= valueDate select cash).ToList(); var tradeIds = settlementPrice.Select(O => O.TradeId).ToHashSet(); var openPrice = (from cash in DbContext.trade_cash where tradeIds.Contains(cash.TradeId) && ClientCashInCashOut.系统操作_期权费 == cash.Action && cash.Amount != 0 && cash.ValidState != ConsGlobal.InValid && !cash.IsDeleted && cash.ValueDate <= valueDate select cash).ToDictionary(K => K.TradeId, V => V); double price = 0; foreach (var item in settlementPrice) { if (openPrice.ContainsKey(item.TradeId)) { price += (item.Amount + (item.UnwindNotional / openPrice[item.TradeId].Notional) * openPrice[item.TradeId].Amount) ?? 0; } else { price += item.Amount; } } return query - price; } /// /// 获取期权列表 /// public List GetOptionPositionList(DateTime valueDate) where T : EodTradePosition, new() { var lastDate = valuedateBLL.GetNonHolidayDefore(valueDate.AddDays(-1)); var actions = new List() { "系统操作-行权费", "系统操作-平仓费" }; var dbTable = DbContext.Set(); var idList = (from et in DbContext.eod_trade where et.ValueDate == valueDate && ConsTrade.LiveTradeStatusList.Contains(et.TradeStatus) && ConsTrade.OptionTradeTypes.Contains(et.TradeType)/* && !et.TradeJson.Contains("InValid")*/ select et.id).ToArray(); var tcQuery = DbContext.trade_cash.Where(tc => !tc.IsDeleted && tc.ValidState != "InValid" && actions.Contains(tc.Action) && tc.ValueDate == valueDate); var query = from eodDb in dbTable join eodT in DbContext.eod_trade.Where(O => idList.Contains(O.id)) on eodDb.TradeId equals eodT.TradeId join lastTempDb in dbTable.Where(et => et.ValueDate == lastDate) on eodT.TradeId equals lastTempDb.TradeId into lastTempDb from lastDb in lastTempDb.DefaultIfEmpty() join tempTc in tcQuery on eodT.TradeId equals tempTc.TradeId into tempTc from tc in tempTc.DefaultIfEmpty() where ConsTrade.OptionTradeTypes.Contains(eodDb.TradeType) && eodDb.ValueDate == valueDate select new { eodT, tc, lastDb, eodDb }; var temp = query.ToList(); var settleTradeId = new List(); temp.ForEach(O => { if (!ConsTrade.LiveTradeStatusList.Contains(O.eodT.TradeStatus)) { O.eodDb.Pv = 0; if (O.lastDb == null)//如果是当天开当天平的交易 { O.eodDb.TotalPnL = -GetOptionEndPnl(valueDate, valueDate, new List { O.eodDb.TradeId }); } else//如果是当天了结的交易 { O.eodDb.TotalPnL = -O.lastDb.TotalPnL; } O.eodDb.DailyPnL = O.eodDb.TotalPnL; settleTradeId.Add(O.eodDb.TradeId); } else if (O.eodT.trade.HasPartialUnWind > 0)//如果交易有部分平仓过 { O.eodDb.TotalPnL = O.eodDb.TotalPnL - GetOptionEndPnl(DateTime.MinValue, O.eodT.ValueDate, new List { O.eodDb.TradeId }); if ((O.tc?.UnwindNotional ?? 0) > 0)//如果当天有部分平仓过 { O.eodDb.DailyPnL = O.eodDb.DailyPnL - GetOptionEndPnl(valueDate, valueDate, new List { O.eodDb.TradeId }); } } }); var list = temp.Select(O => O.eodDb).ToList(); list = ResetOptionAccruedTotalPnL(list, valueDate, settleTradeId); return list; } /// /// 获取场内期权列表 /// public Dictionary GetExchangePositionList(DateTime valueDate) { var lastDate = valuedateBLL.GetNonHolidayDefore(valueDate.AddDays(-1)); var actions = new List() { "系统操作-行权费", "系统操作-平仓费" }; Dictionary result = null; using (var db = new YLContext()) { result = (from eodDb in db.Exchange_Option_Trade join eodPrice in db.eod_exchange_option_price.Where(p => p.ValueDate == valueDate) on eodDb.Code equals eodPrice.ContractCode into dbPrice from eodPrice in dbPrice.DefaultIfEmpty() where (eodDb.ExerciseDate == DateTime.MinValue || eodDb.ExerciseDate > valueDate) && eodDb.TradeDate <= valueDate select new { eodDb, eodPrice }).ToDictionary(K => K.eodDb, V => V.eodPrice); } foreach (var item in result) { if (item.Key.TradeType == "空头") { item.Key.TradeAmount = item.Key.TradeAmount * -1; } } return result; } /// /// 获取期货列表 /// /// /// /// public List GetFutureList(DateTime startDate, DateTime endDate = default(DateTime)) where T : EodTradePosition, new() { if (endDate < startDate) { endDate = startDate; } var dbTable = DbContext.Set(); var list = (from eodDb in dbTable where eodDb.TradeType == "商品期货" && eodDb.ValueDate >= startDate && eodDb.ValueDate <= endDate select eodDb).ToList(); list = ResetFutureAccruedTotalPnL(list, endDate); return list; } /// /// 获取期货总盈亏 /// /// /// /// /// public double GetYearFutureTotlePnl(DateTime currentStart, DateTime currentEnd, DateTime lastDate) where T : EodTradePosition, new() { double result = 0; var currentList = GetFutureList(currentStart, currentEnd) .GroupBy(O => new { O.UnderlyingCode, O.PositionType, O.BookId }) .ToDictionary(K => { var temp = K.First(); return $"{temp.UnderlyingCode}_{temp.PositionType}_{temp.BookId}"; }, V => new List(V), StringComparer.OrdinalIgnoreCase); var lastList = GetFutureList(lastDate) .GroupBy(O => new { O.UnderlyingCode, O.PositionType, O.BookId }) .ToDictionary(K => { var temp = K.First(); return $"{temp.UnderlyingCode}_{temp.PositionType}_{temp.BookId}"; }, V => new List(V), StringComparer.OrdinalIgnoreCase); foreach (var item in currentList) { double lastPnl = 0; if (lastList.ContainsKey(item.Key)) { lastPnl = lastList[item.Key].Sum(O => O.TotalPnL); } var maxDate = item.Value.Max(B => B.ValueDate); result += item.Value.FindAll(O => O.ValueDate == maxDate).Sum(O => O.TotalPnL) - lastPnl; } return result; } /// /// 获取期货持仓盈亏-年 /// /// /// public double GetYearFuturePositionPnl(DateTime lastDate) where T : EodTradePosition, new() { double result = 0; var positionList = GetFutureList(lastDate); result = positionList.Sum(O => (double)(O.DailyPnL)); return result; } /// /// 获取期权已了结盈亏 /// public double GetOptionEndPnl(DateTime currentStart, DateTime currentEnd, List tradeIds = null) { var actions = new List() { "系统操作-行权费", "系统操作-平仓费" }; var query = from tc in DbContext.trade_cash join t in DbContext.trade on tc.TradeId equals t.id where t.ValidState != "InValid" && !tc.IsDeleted && tc.ValueDate >= currentStart && tc.ValueDate <= currentEnd && actions.Contains(tc.Action) select new { tc, t }; if (tradeIds?.Count > 0) { query = query.Where(O => tradeIds.Contains(O.t.id)); } var result = query.Select(O => O.t.BuySell == "卖出" ? O.tc.Amount - (0 - O.t.TradePrice * O.tc.UnwindPercentRate) : O.tc.Amount - O.t.TradePrice * O.tc.UnwindPercentRate).Sum(); //double result = list.Count > 0 ? list.Sum(O => O.Amount ?? 0) : 0; return result ?? 0; } /// /// 获取持仓DeltaCash /// /// /// /// public Dictionary GetFutureDeltaCash(DateTime startDate, DateTime endDate = default(DateTime)) where T : EodTradePosition, new() { if (endDate < startDate) { endDate = startDate; } var dbTable = DbContext.Set(); var query = from eodDb in dbTable join underlying in DbContext.underlying_manager on eodDb.UnderlyingCode equals underlying.UnderlyingCode join price in DbContext.eod_commodity_future_price on eodDb.UnderlyingCode equals price.UnderlyingCode where eodDb.TradeType == "商品期货" && eodDb.ValueDate >= startDate && eodDb.ValueDate <= endDate && eodDb.Amount != 0 && price.ValueDate == endDate select new { underlying.CommodityCode, eodDb.UnderlyingCode, eodDb.ValueDate, eodDb.Amount, price.ClosePrice }; var list = query.AsEnumerable(); var result = list.GroupBy(O => O.CommodityCode).ToDictionary( K => K.Key, V => V.Sum(O => O.Amount * O.ClosePrice), StringComparer.OrdinalIgnoreCase); //var list = // query. // GroupBy(O => O.CommodityCode) // .ToDictionary( // K => K.Key, // V => V.Sum(O => O.Amount * O.ClosePrice), // StringComparer.OrdinalIgnoreCase); return result; } /// /// 获取DeltaCash /// /// /// /// public Dictionary GetOptionDeltaCash(DateTime valueDate) where T1 : EodTradeRisk, new() where T2 : EodTradePosition, new() { var dbTable = DbContext.Set(); var pair = (from riskDb in dbTable join tDb in DbContext.trade on new { id = riskDb.TradeId } equals new { tDb.id } join underlying in DbContext.underlying_manager on tDb.UnderlyingCode equals underlying.UnderlyingCode where underlying.CommodityCode != null && tDb.ValidState != "InValid" && riskDb.ValueDate == valueDate select new EodTradeRisk { Exposure = underlying.CommodityCode, DeltaCash = riskDb.DeltaCash }).ToList(); var option = pair.GroupBy(O => O.Exposure).ToDictionary(K => K.Key, V => V.Select(O => O.DeltaCash).Sum(), StringComparer.OrdinalIgnoreCase); return option; } /// /// 获取GammaCash /// /// /// public double GetOptionGammaCash(DateTime valueDate) where T1 : EodTradeRisk, new() where T2 : EodTradePosition, new() { var dbTable = DbContext.Set(); var query = (from riskDb in dbTable join tDb in DbContext.trade on new { id = riskDb.TradeId } equals new { id = tDb.id } join price in DbContext.eod_commodity_future_price on tDb.UnderlyingCode equals price.UnderlyingCode where tDb.ValidState != "InValid" && riskDb.ValueDate == valueDate && price.ValueDate == valueDate select new { riskDb.Gamma, price.ClosePrice }); var gammaList = query.ToList(); double gammaCash = 0; foreach (var item in gammaList) { gammaCash += (double)item.Gamma * 0.5 * Math.Pow(item.ClosePrice * 0.01, 2); } return gammaCash; } /// /// 获取期初名义本金 /// /// /// public double GetTradePrice(DateTime currentEndDate) { var datas = (from tradeDb in DbContext.eod_trade where tradeDb.ValueDate == currentEndDate && ConsTrade.LiveTradeStatusList.Contains(tradeDb.TradeStatus) select tradeDb).ToList(); double result = 0; foreach (var item in datas) { result += (item.trade.Notional * (item.trade.SpotPrice ?? 0)); } return result; } } }