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

455 lines
20 KiB
C#

using YLErp.BLL;
using YLErp.BLL.Eod;
using YLErp.Model;
namespace YLErp.Modules.RiskListModule
{
public class RiskDailyReportService : YLBaseService
{
/// <summary>
/// 年盈亏起算日
/// </summary>
public DateTime CurrentStartDate { get; private set; }
/// <summary>
/// 年累计盈亏截止日
/// <para>最后一次收盘成功的日期</para>
/// </summary>
public DateTime CurrentEndDate { get; private set; }
/// <summary>
/// 上年累计盈亏截止日
/// </summary>
public DateTime LastYearEndDate { get; private set; }
/// <summary>
/// 前一次收盘日期
/// <para>用于计算截止日价差</para>
/// </summary>
public DateTime CurrentLastDate { get; private set; }
/// <summary>
/// 总资金
/// </summary>
public double Total { get; private set; }
/// <summary>
/// 可用资金
/// </summary>
public double Available { get; private set; }
/// <summary>
/// 客户权益
/// </summary>
public double CurrFund { get; private set; }
/// <summary>
/// 预付金占用
/// </summary>
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);
}
/// <summary>
/// 重置累计总盈亏字段值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="valueDate"></param>
/// <param name="objs"></param>
private List<T> ResetOptionAccruedTotalPnL<T>(List<T> objs, DateTime valueDate, List<int> settleTradeIds) where T : EodTradePosition, new()
{
var result = objs.Select(O => (T)O.Clone()).ToList();
if (valueDate > this.LastYearEndDate)
{
var dbTable = DbContext.Set<T>();
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;
}
/// <summary>
/// 重置累计总盈亏字段值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="valueDate"></param>
/// <param name="objs"></param>
private List<T> ResetFutureAccruedTotalPnL<T>(List<T> objs, DateTime valueDate) where T : EodTradePosition, new()
{
var result = objs.Select(O => (T)O.Clone()).ToList();
if (valueDate > this.LastYearEndDate)
{
var dbTable = DbContext.Set<T>();
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<T>(DateTime valueDate) where T : EodTradePosition, new()
{
var dbTable = DbContext.Set<T>();
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;
}
/// <summary>
/// 获取期权列表
/// </summary>
public List<T> GetOptionPositionList<T>(DateTime valueDate) where T : EodTradePosition, new()
{
var lastDate = valuedateBLL.GetNonHolidayDefore(valueDate.AddDays(-1));
var actions = new List<string>() { "系统操作-行权费", "系统操作-平仓费" };
var dbTable = DbContext.Set<T>();
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<int>();
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<int> { 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<int> { O.eodDb.TradeId });
if ((O.tc?.UnwindNotional ?? 0) > 0)//如果当天有部分平仓过
{ O.eodDb.DailyPnL = O.eodDb.DailyPnL - GetOptionEndPnl(valueDate, valueDate, new List<int> { O.eodDb.TradeId }); }
}
});
var list = temp.Select(O => O.eodDb).ToList();
list = ResetOptionAccruedTotalPnL(list, valueDate, settleTradeId);
return list;
}
/// <summary>
/// 获取场内期权列表
/// </summary>
public Dictionary<Exchange_Option_Trade, eod_exchange_option_price> GetExchangePositionList(DateTime valueDate)
{
var lastDate = valuedateBLL.GetNonHolidayDefore(valueDate.AddDays(-1));
var actions = new List<string>() { "系统操作-行权费", "系统操作-平仓费" };
Dictionary<Exchange_Option_Trade, eod_exchange_option_price> 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;
}
/// <summary>
/// 获取期货列表
/// </summary>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <returns></returns>
public List<T> GetFutureList<T>(DateTime startDate, DateTime endDate = default(DateTime)) where T : EodTradePosition, new()
{
if (endDate < startDate) { endDate = startDate; }
var dbTable = DbContext.Set<T>();
var list =
(from eodDb in dbTable
where eodDb.TradeType == "商品期货" &&
eodDb.ValueDate >= startDate &&
eodDb.ValueDate <= endDate
select eodDb).ToList();
list = ResetFutureAccruedTotalPnL(list, endDate);
return list;
}
/// <summary>
/// 获取期货总盈亏
/// </summary>
/// <param name="currentStart"></param>
/// <param name="currentEnd"></param>
/// <param name="lastDate"></param>
/// <returns></returns>
public double GetYearFutureTotlePnl<T>(DateTime currentStart, DateTime currentEnd, DateTime lastDate) where T : EodTradePosition, new()
{
double result = 0;
var currentList =
GetFutureList<T>(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<T>(V), StringComparer.OrdinalIgnoreCase);
var lastList =
GetFutureList<T>(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<T>(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;
}
/// <summary>
/// 获取期货持仓盈亏-年
/// </summary>
/// <param name="lastDate"></param>
/// <returns></returns>
public double GetYearFuturePositionPnl<T>(DateTime lastDate) where T : EodTradePosition, new()
{
double result = 0;
var positionList =
GetFutureList<T>(lastDate);
result = positionList.Sum(O => (double)(O.DailyPnL));
return result;
}
/// <summary>
/// 获取期权已了结盈亏
/// </summary>
public double GetOptionEndPnl(DateTime currentStart, DateTime currentEnd, List<int> tradeIds = null)
{
var actions = new List<string>() { "系统操作-行权费", "系统操作-平仓费" };
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;
}
/// <summary>
/// 获取持仓DeltaCash
/// </summary>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <returns></returns>
public Dictionary<string, double> GetFutureDeltaCash<T>(DateTime startDate, DateTime endDate = default(DateTime)) where T : EodTradePosition, new()
{
if (endDate < startDate) { endDate = startDate; }
var dbTable = DbContext.Set<T>();
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;
}
/// <summary>
/// 获取DeltaCash
/// </summary>
/// <param name="valueDate"></param>
/// <param name="sourceType"></param>
/// <returns></returns>
public Dictionary<string, double> GetOptionDeltaCash<T1, T2>(DateTime valueDate) where T1 : EodTradeRisk, new() where T2 : EodTradePosition, new()
{
var dbTable = DbContext.Set<T1>();
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;
}
/// <summary>
/// 获取GammaCash
/// </summary>
/// <param name="valueDate"></param>
/// <returns></returns>
public double GetOptionGammaCash<T1, T2>(DateTime valueDate) where T1 : EodTradeRisk, new() where T2 : EodTradePosition, new()
{
var dbTable = DbContext.Set<T1>();
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;
}
/// <summary>
/// 获取期初名义本金
/// </summary>
/// <param name="currentEndDate"></param>
/// <returns></returns>
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;
}
}
}