1554 lines
85 KiB
C#
1554 lines
85 KiB
C#
using Dapper;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Linq.Extend;
|
|
using YLErp.BLL;
|
|
using YLErp.BLL.Eod;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.EodModule;
|
|
using YLErp.Modules.EodModule.QueryModule;
|
|
using YLErp.Modules.MarketRiskMoudule;
|
|
using YLErp.Modules.RiskExposure.Dto;
|
|
using YLErp.Modules.RiskModule;
|
|
|
|
namespace YLErp.Modules.RiskExposure
|
|
{
|
|
/// <summary>
|
|
/// 市场风险结算报告服务
|
|
/// </summary>
|
|
public class RiskExposureReportService<eodPosition> : YLBaseService where eodPosition : EodTradePosition
|
|
{
|
|
public RiskExposureReportService(OptUserInfo userInfo) : base(userInfo)
|
|
{ }
|
|
|
|
public RiskExposureReportModel SearchRiskExposureReportsV2<eodRisk, eodPnl>(RiskRequestModel reqModel) where eodRisk : EodTradeRisk where eodPnl : EodPnl
|
|
{
|
|
RiskExposureReportModel result = null;
|
|
|
|
reqModel = CheckModel(reqModel);
|
|
var startDate = EodOperationBase.GetLastSettlementDate(reqModel.ValueDateStart ?? valuedateBLL.SystemDate.AccruedTotalPnlStartDate ?? DateTime.Today);
|
|
var preDate = EodOperationBase.GetLastSettlementDate(startDate.AddDays(-1));
|
|
var dataProvider = new EodRiskCalcDataProvider(reqModel.ValueDateEnd, startDate);
|
|
var useFirstEod = reqModel.ValueDateStart.HasValue ? PredicateBuilder.True<eodPosition>() : PredicateBuilder.False<eodPosition>();
|
|
|
|
var useFirstWhere = "ValueDate=@StartTime";
|
|
|
|
//if (reqModel.ValueDateStart.HasValue)
|
|
//{
|
|
// useFirstEod = PredicateBuilder.Create<eodPosition>(t => t.ValueDate == preDate);
|
|
//}
|
|
//var tdPredicate = PredicateBuilder.Create<trade>(n => n.ValidState != ConsGlobal.InValid);
|
|
|
|
var tradeWhere = "(ValidState<>'InValid' or ValidState is null)";
|
|
|
|
//var predicate = PredicateBuilder.Create<eodPosition>(
|
|
// t => t.ValueDate > preDate && t.ValueDate <= reqModel.ValueDateEnd && t.TradeType != "结构化交易" && t.TradeType != "现金流交易");
|
|
|
|
var predicateWhere = " ValueDate>@StartTime and ValueDate<=@EndTime and TradeType<>'结构化交易' and TradeType<>'现金流交易'";
|
|
|
|
//if (reqModel.UserAssets != null || reqModel.UserClients != null)
|
|
//{
|
|
// tdPredicate = tdPredicate.And(q => reqModel.UserAssets.Contains(q.AssetId) || reqModel.UserClients.Contains(q.ClientId));
|
|
// predicate = predicate.And(q => reqModel.UserAssets.Contains(q.BookId) || reqModel.UserClients.Contains(q.ClientId));
|
|
//}
|
|
|
|
if (reqModel.UserAssets != null && reqModel.UserAssets.Count > 0 && !(reqModel.UserClients != null && reqModel.UserClients.Count > 0))
|
|
{
|
|
tradeWhere += " and AssetId in @UserAssets";
|
|
predicateWhere += " and BookId in @UserAssets";
|
|
}
|
|
if (!(reqModel.UserAssets != null && reqModel.UserAssets.Count > 0) && (reqModel.UserClients != null && reqModel.UserClients.Count > 0))
|
|
{
|
|
tradeWhere += " and ClientId in @UserClients";
|
|
predicateWhere += " and ClientId in @UserClients";
|
|
}
|
|
if((reqModel.UserAssets != null && reqModel.UserAssets.Count > 0) && (reqModel.UserClients != null && reqModel.UserClients.Count > 0))
|
|
{
|
|
tradeWhere += " and (AssetId in @UserAssets or ClientId in @UserClients)";
|
|
predicateWhere += " and (BookId in @UserAssets or ClientId in @UserClients)";
|
|
}
|
|
|
|
if (reqModel.ClientIds != null && reqModel.ClientIds.Count > 0)
|
|
{
|
|
//predicate = predicate.And(q => reqModel.ClientIds.Contains(q.ClientId));
|
|
predicateWhere += " and ClientId in @ClientIds";
|
|
}
|
|
|
|
if (reqModel.BookIds != null && reqModel.BookIds.Count > 0)
|
|
{
|
|
//predicate = predicate.And(q => reqModel.BookIds.Contains(q.BookId));
|
|
predicateWhere += " and BookId in @BookIds";
|
|
}
|
|
|
|
if (reqModel.TradeTypes != null && reqModel.TradeTypes.Any())
|
|
{
|
|
//predicate = predicate.And(q =>
|
|
// ((q.StructureType == null || q.StructureType == "") && reqModel.TradeTypes.Contains(q.TradeType)) ||
|
|
// (q.StructureType != null && q.StructureType != "" && reqModel.TradeTypes.Contains(q.StructureType)));
|
|
|
|
predicateWhere += " and ((IFNULL(StructureType,'')='' and TradeType in @TradeTypes) or (IFNULL(StructureType,'')<>'' and StructureType in @TradeTypes))";
|
|
}
|
|
|
|
if (reqModel.TraderIds != null && reqModel.TraderIds.Any())
|
|
{
|
|
//predicate = predicate.And(t => t.TradeId > 0);
|
|
predicateWhere += " and TradeId>0";
|
|
//tdPredicate = tdPredicate.And(n => reqModel.TraderIds.Contains(n.TraderId));
|
|
tradeWhere += " and TraderId in @TraderIds";
|
|
}
|
|
|
|
if (reqModel.TagIds != null && reqModel.TagIds.Count > 0)
|
|
{
|
|
//var tradeTagIdQuery = from tt in DbContext.trade_tag
|
|
// where reqModel.TagIds.Contains(tt.TagId)
|
|
// select tt.TradeId;
|
|
//tdPredicate = tdPredicate.And(p => tradeTagIdQuery.Contains(p.id));
|
|
|
|
tradeWhere += " and id in (select TradeId from trade_tag where TagId in @TagIds)";
|
|
}
|
|
|
|
if (reqModel.VarietyIds != null && reqModel.VarietyIds.Any() && reqModel.UnderlyingIds != null && reqModel.UnderlyingIds.Any())
|
|
{
|
|
predicateWhere += " and UnderlyingCode in (select UnderlyingCode from underlying_manager where id in @UnderlyingIds and UnderlyingTypeId in @VarietyIds)";
|
|
}
|
|
else
|
|
{
|
|
if (reqModel.VarietyIds != null && reqModel.VarietyIds.Any())
|
|
{
|
|
predicateWhere += " and UnderlyingCode in (select UnderlyingCode from underlying_manager where UnderlyingTypeId in @VarietyIds)";
|
|
}
|
|
|
|
if (reqModel.UnderlyingIds != null && reqModel.UnderlyingIds.Any())
|
|
{
|
|
predicateWhere += " and UnderlyingCode in (select UnderlyingCode from underlying_manager where id in @UnderlyingIds)";
|
|
}
|
|
}
|
|
|
|
predicateWhere += string.Format(" and (TradeId<1 or TradeId in (select id from trade where {0}))", tradeWhere);
|
|
|
|
// var querySql = string.Format(@"SELECT h.*,g.TradeJson AS ParentTradeJson FROM (SELECT b.id,e.TradeJson,b.ValueDate,b.TradeId,b.ParentTradeId,b.UnderlyingCode,b.ExchangeOptionCode,b.UnderlyingId,b.BookId,b.StructureType,b.TradeType,b.Amount,b.TotalPnL,
|
|
//f.TotalPnL AS FirstTotalPnL,b.Pv,b.Cost,f.Pv AS FirstPv,f.Cost AS FirstCost,b.Commission,
|
|
//b.DailyPnL,c.Delta,c.DeltaCash,c.Gamma,c.GammaCash,c.Vega,c.Rho,c.Theta,d.PnLDelta,d.PnLGamma,d.PnLTheta,d.PnLVega,d.PnLPsi
|
|
//FROM (SELECT TradeId,HedgeUniqueCode,MAX(ValueDate) AS ValueDate FROM {0} WHERE {1} GROUP BY TradeId,HedgeUniqueCode) a
|
|
//JOIN {0} b ON a.ValueDate=b.ValueDate AND a.TradeId=b.TradeId AND a.HedgeUniqueCode=b.HedgeUniqueCode
|
|
//JOIN {2} c ON a.ValueDate=c.ValueDate AND a.TradeId=c.TradeId AND a.HedgeUniqueCode=c.HedgeUniqueCode
|
|
//JOIN {3} d ON a.ValueDate=d.ValueDate AND a.TradeId=d.TradeId AND a.HedgeUniqueCode=d.HedgeUniqueCode
|
|
//LEFT JOIN eod_trade e ON a.ValueDate=e.ValueDate AND a.TradeId=e.TradeId AND e.TradeId>0
|
|
//LEFT JOIN (SELECT * FROM {0} WHERE {4}
|
|
//) f ON a.TradeId=f.TradeId AND a.HedgeUniqueCode=f.HedgeUniqueCode) h
|
|
//LEFT JOIN eod_trade g ON h.ValueDate=g.ValueDate AND h.ParentTradeId=g.TradeId AND h.ParentTradeId>0
|
|
//WHERE h.id>@MinId
|
|
//ORDER BY h.id ASC LIMIT 1000;", DbContext.GetTableName<eodPosition>(), predicateWhere, DbContext.GetTableName<eodRisk>(), DbContext.GetTableName<eodPnl>(), useFirstWhere);
|
|
|
|
var querySql = string.Format(@"SELECT h.*,g.TradeJson AS ParentTradeJson FROM (SELECT b.id,e.TradeJson,b.ValueDate,b.TradeId,b.ParentTradeId,b.UnderlyingCode,b.ExchangeOptionCode,b.UnderlyingId,b.BookId,b.StructureType,b.TradeType,b.Amount,b.TotalPnL,
|
|
f.TotalPnL AS FirstTotalPnL,b.Pv,b.Cost,f.Pv AS FirstPv,f.Cost AS FirstCost,b.Commission,
|
|
b.DailyPnL,c.Delta,c.DeltaCash,c.Gamma,c.GammaCash,c.Vega,c.Rho,c.Theta,d.PnLDelta,d.PnLGamma,d.PnLTheta,d.PnLVega,d.PnLPsi
|
|
FROM (SELECT TradeId,HedgeUniqueCode,MAX(ValueDate) AS ValueDate FROM {0} WHERE {1} GROUP BY TradeId,HedgeUniqueCode) a
|
|
JOIN {0} b ON a.ValueDate=b.ValueDate AND a.TradeId=b.TradeId AND a.HedgeUniqueCode=b.HedgeUniqueCode
|
|
LEFT JOIN {2} c ON c.ValueDate=@EndTime AND a.TradeId=c.TradeId AND a.HedgeUniqueCode=c.HedgeUniqueCode
|
|
LEFT JOIN {3} d ON d.ValueDate=@EndTime AND a.TradeId=d.TradeId AND a.HedgeUniqueCode=d.HedgeUniqueCode
|
|
LEFT JOIN eod_trade e ON a.ValueDate=e.ValueDate AND a.TradeId=e.TradeId AND e.TradeId>0
|
|
LEFT JOIN (SELECT * FROM {0} WHERE {4}
|
|
) f ON a.TradeId=f.TradeId AND a.HedgeUniqueCode=f.HedgeUniqueCode) h
|
|
LEFT JOIN eod_trade g ON h.ValueDate=g.ValueDate AND h.ParentTradeId=g.TradeId AND h.ParentTradeId>0
|
|
WHERE h.id>@MinId
|
|
ORDER BY h.id ASC LIMIT 100000;", DbContext.GetTableName<eodPosition>(), predicateWhere, DbContext.GetTableName<eodRisk>(), DbContext.GetTableName<eodPnl>(), useFirstWhere);
|
|
|
|
|
|
var queryList = new List<EodPositionQueryDto>();
|
|
|
|
DbContext.Database.SetCommandTimeout(10000);
|
|
var conn = DbContext.Database.GetDbConnection();
|
|
|
|
var minId = 0;
|
|
|
|
var itemList = conn.Query<EodPositionQueryDto>(querySql, new
|
|
{
|
|
StartTime = preDate,
|
|
EndTime = reqModel.ValueDateEnd,
|
|
UserAssets = reqModel.UserAssets,
|
|
UserClients = reqModel.UserClients,
|
|
ClientIds = reqModel.ClientIds,
|
|
BookIds = reqModel.BookIds,
|
|
TradeTypes = reqModel.TradeTypes,
|
|
TraderIds = reqModel.TraderIds,
|
|
TagIds = reqModel.TagIds,
|
|
UnderlyingIds = reqModel.UnderlyingIds,
|
|
VarietyIds = reqModel.VarietyIds,
|
|
MinId = minId
|
|
}).ToList();
|
|
if (itemList != null && itemList.Count > 0)
|
|
{
|
|
queryList.AddRange(itemList);
|
|
}
|
|
while (itemList != null && itemList.Count >= 100000)
|
|
{
|
|
minId = itemList.Max(p => p.id);
|
|
itemList = conn.Query<EodPositionQueryDto>(querySql, new
|
|
{
|
|
StartTime = preDate,
|
|
EndTime = reqModel.ValueDateEnd,
|
|
UserAssets = reqModel.UserAssets,
|
|
UserClients = reqModel.UserClients,
|
|
ClientIds = reqModel.ClientIds,
|
|
BookIds = reqModel.BookIds,
|
|
TradeTypes = reqModel.TradeTypes,
|
|
TraderIds = reqModel.TraderIds,
|
|
TagIds = reqModel.TagIds,
|
|
UnderlyingIds = reqModel.UnderlyingIds,
|
|
VarietyIds = reqModel.VarietyIds,
|
|
MinId = minId
|
|
}).ToList();
|
|
if (itemList != null && itemList.Count > 0)
|
|
{
|
|
queryList.AddRange(itemList);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var riskExposureItemModels = new List<RiskExposureItemModel>();
|
|
|
|
if (queryList.Count > 0)
|
|
{
|
|
var tradeIds = queryList.Where(p => p.TradeId > 0).Select(p => p.TradeId).Distinct().ToList();
|
|
var spotPriceDic = new Dictionary<int, double?>();
|
|
if (tradeIds != null && tradeIds.Count > 0)
|
|
{
|
|
spotPriceDic = DbContext.trade.AsNoTracking().Where(p => tradeIds.Contains(p.id)).ToDictionary(p => p.id, p => p.SpotPrice);
|
|
|
|
}
|
|
if (spotPriceDic == null)
|
|
{
|
|
spotPriceDic = new Dictionary<int, double?>();
|
|
}
|
|
queryList.ForEach(p =>
|
|
{
|
|
double? sportPrice = 0;
|
|
if (p.TradeId > 0 && spotPriceDic.ContainsKey((int)p.TradeId))
|
|
{
|
|
sportPrice = spotPriceDic[(int)p.TradeId];
|
|
}
|
|
riskExposureItemModels.Add(new RiskExposureItemModel
|
|
{
|
|
eodTrade = new xodTradeBase { TradeJson = p.ParentTradeId > 0 ? p.ParentTradeJson : p.TradeJson },
|
|
ValueDate = p.ValueDate,
|
|
TradeId = p.TradeId,
|
|
ParentTradeId = p.ParentTradeId ?? 0,
|
|
|
|
UnderlyingCode = p.UnderlyingCode,
|
|
OptionCode = p.ExchangeOptionCode,
|
|
UnderlyingId = p.UnderlyingId ?? 0,
|
|
BookId = p.BookId ?? 0,
|
|
TradeType = p.StructureType == null || p.StructureType == "" ? p.TradeType : p.StructureType,
|
|
Amount = p.Amount ?? 0,
|
|
AccruedTotalPnL = (p.TotalPnL ?? 0) - (p.FirstTotalPnL ?? 0),
|
|
CumulativeFloatProfitLoss = (p.Pv ?? 0) - (p.Cost ?? 0) - (p.FirstPv ?? 0) - (p.FirstCost ?? 0),
|
|
Commission = p.Commission ?? 0,//总计手续费
|
|
DailyPnl = p.DailyPnL,
|
|
Delta = p.Delta,
|
|
DeltaCash = p.DeltaCash,
|
|
Gamma = p.Gamma,
|
|
GammaCash = p.GammaCash,
|
|
Vega = p.Vega,
|
|
Rho = (p.Rho ?? 0) * 100,
|
|
Theta = p.Theta,
|
|
SpotPrice = sportPrice,
|
|
dPnlDelta = p.PnLDelta ?? 0,
|
|
dPnlGamma = p.PnLGamma ?? 0,
|
|
dPnlTheta = p.PnLTheta ?? 0,
|
|
dPnlVega = p.PnLVega ?? 0,
|
|
dPnlPsi = p.PnLPsi ?? 0,
|
|
});
|
|
|
|
});
|
|
}
|
|
|
|
|
|
//// 索引数据(先将时间段内所有要统计的数据做个索引)
|
|
////如果后面要升级成只使用HedgeUniqueCode判断,则需要在TradeId大于0时将HedgeUniqueCode变成TradeId
|
|
////否则升级后老的数据和新的数据在这段逻辑中就会进入不同的分组导致统计错误
|
|
//var sourceQuery = from t in DbContext.Set<eodPosition>().Where(predicate)
|
|
// join un in DbContext.underlying_manager on t.UnderlyingCode equals un.UnderlyingCode
|
|
// where (!reqModel.VarietyIds.Any() || reqModel.VarietyIds.Contains(un.UnderlyingTypeId))
|
|
// && (!reqModel.UnderlyingIds.Any() || reqModel.UnderlyingIds.Contains(un.id))
|
|
// && (t.TradeId < 1 || DbContext.trade.Where(n => n.id == t.TradeId).Where(tdPredicate).Any())
|
|
// group t by new { t.TradeId, t.HedgeUniqueCode } into g
|
|
// select new
|
|
// {
|
|
// g.Key.TradeId,
|
|
// g.Key.HedgeUniqueCode,
|
|
// maxDate = g.Max(B => B.ValueDate)
|
|
// };
|
|
|
|
|
|
//var query = from source in sourceQuery
|
|
|
|
// join lastEod in DbContext.Set<eodPosition>()
|
|
// on new { ValueDate = source.maxDate, TradeId = source.TradeId + source.HedgeUniqueCode }
|
|
// equals new { lastEod.ValueDate, TradeId = lastEod.TradeId + lastEod.HedgeUniqueCode }
|
|
|
|
// join tempEod in DbContext.Set<eodPosition>().Where(useFirstEod)
|
|
// on new { TradeId = source.TradeId + source.HedgeUniqueCode }
|
|
// equals new { TradeId = tempEod.TradeId + tempEod.HedgeUniqueCode } into tempEod
|
|
// from firstEod in tempEod.DefaultIfEmpty()
|
|
|
|
// join tempRisk in DbContext.Set<eodRisk>().Where(n => n.ValueDate == reqModel.ValueDateEnd)
|
|
// on new { TradeId = source.TradeId + source.HedgeUniqueCode } equals new { TradeId = tempRisk.TradeId + tempRisk.HedgeUniqueCode } into tempRisk
|
|
// from risk in tempRisk.DefaultIfEmpty()
|
|
|
|
// join tempPnl in DbContext.Set<eodPnl>().Where(n => n.ValueDate == reqModel.ValueDateEnd)
|
|
// on new { TradeId = source.TradeId + source.HedgeUniqueCode } equals new { TradeId = tempPnl.TradeId + tempPnl.HedgeUniqueCode } into tempPnl
|
|
// from pnl in tempPnl.DefaultIfEmpty()
|
|
|
|
// join et in DbContext.eod_trade on new { ValueDate = source.maxDate, source.TradeId } equals new { et.ValueDate, et.TradeId } into tempEt
|
|
// from et in tempEt.DefaultIfEmpty()
|
|
|
|
// join td in DbContext.trade on source.TradeId equals td.id into td_t
|
|
// from td in td_t.DefaultIfEmpty()
|
|
|
|
// select new RiskExposureItemModel
|
|
// {
|
|
// eodTrade = new xodTradeBase { TradeJson = et.TradeJson },
|
|
|
|
// ValueDate = lastEod.ValueDate,
|
|
// TradeId = lastEod.TradeId,
|
|
// ParentTradeId = lastEod.ParentTradeId,
|
|
|
|
// UnderlyingCode = lastEod.UnderlyingCode,
|
|
// OptionCode = lastEod.ExchangeOptionCode,
|
|
// UnderlyingId = lastEod.UnderlyingId,
|
|
// BookId = lastEod.BookId,
|
|
// TradeType = lastEod.StructureType == null || lastEod.StructureType == "" ? lastEod.TradeType : lastEod.StructureType,
|
|
// Amount = lastEod.Amount,
|
|
// AccruedTotalPnL = lastEod.TotalPnL - (firstEod == null ? 0 : firstEod.TotalPnL),
|
|
// CumulativeFloatProfitLoss = lastEod.Pv - lastEod.Cost - (firstEod == null ? 0 : firstEod.Pv - firstEod.Cost),
|
|
// Commission = lastEod.Commission,//总计手续费
|
|
// DailyPnl = lastEod.DailyPnL,
|
|
// Delta = risk == null ? 0 : risk.Delta,
|
|
// DeltaCash = risk == null ? 0 : risk.DeltaCash,
|
|
// Gamma = risk == null ? 0 : risk.Gamma,
|
|
// GammaCash = risk == null ? 0 : risk.GammaCash,
|
|
// Vega = risk == null ? 0 : risk.Vega,
|
|
// Rho = risk == null ? 0 : risk.Rho * 100,
|
|
// Theta = risk == null ? 0 : risk.Theta,
|
|
// SpotPrice = td == null ? 0 : td.SpotPrice,
|
|
// dPnlDelta = pnl == null ? 0 : pnl.PnLDelta,
|
|
// dPnlGamma = pnl == null ? 0 : pnl.PnLGamma,
|
|
// dPnlTheta = pnl == null ? 0 : pnl.PnLTheta,
|
|
// dPnlVega = pnl == null ? 0 : pnl.PnLVega,
|
|
// dPnlPsi = pnl == null ? 0 : pnl.PnLPsi,
|
|
// };
|
|
|
|
//var eodPnlListEnd = query.ToList();
|
|
var eodPnlListEnd = riskExposureItemModels;
|
|
//var stockEqvNotionalDict =
|
|
// (from et in DbContext.eod_trade
|
|
// join source in query
|
|
// on new { et.ValueDate, et.TradeId } equals new { source.ValueDate, TradeId = source.ParentTradeId > 0 ? source.ParentTradeId : (source.TradeId ?? 0) }
|
|
// select new { et.TradeId, et = new xodTradeBase() { TradeJson = et.TradeJson } }).ToArray()
|
|
// .GroupBy(O => O.TradeId).ToDictionary(
|
|
// K => K.Key,
|
|
// V =>
|
|
// {
|
|
// var trade = V.First().et.trade;
|
|
// return new
|
|
// {
|
|
// StockEqvNotional = trade.StockEqvNotional,
|
|
// StockEqvNotionalReal = (trade.StockEqvNotionalReal * trade.Notional / trade.OriginalNotional) ?? 0
|
|
// };
|
|
// });
|
|
var parentTradeList = new List<int>();
|
|
eodPnlListEnd.ForEach(O =>
|
|
{
|
|
if (O.ValueDate != reqModel.ValueDateEnd)
|
|
{
|
|
O.Amount = 0;
|
|
O.CumulativeFloatProfitLoss = 0;
|
|
O.DailyPnl = 0;
|
|
O.Delta = 0;
|
|
O.Gamma = 0;
|
|
O.Vega = 0;
|
|
O.Rho = 0;
|
|
O.Theta = 0;
|
|
O.DeltaCash = 0;
|
|
O.GammaCash = 0;
|
|
O.dPnlDelta = 0;
|
|
O.dPnlGamma = 0;
|
|
O.dPnlTheta = 0;
|
|
O.dPnlVega = 0;
|
|
O.dPnlPsi = 0;
|
|
}
|
|
//var id = O.ParentTradeId > 0 ? O.ParentTradeId : (O.TradeId ?? 0);
|
|
//if (stockEqvNotionalDict.ContainsKey(id))
|
|
//{
|
|
// O.StockEqvNotional = stockEqvNotionalDict[id].StockEqvNotional;
|
|
// O.StockEqvNotionalReal = stockEqvNotionalDict[id].StockEqvNotionalReal;
|
|
//}
|
|
//else
|
|
//{
|
|
// O.StockEqvNotional = 0;
|
|
// O.StockEqvNotionalReal = 0;
|
|
//}
|
|
//stockEqvNotionalDict.Remove(id);//确保多腿交易名义本金不会重复计算
|
|
if (O.eodTrade != null)
|
|
{
|
|
if (O.ParentTradeId > 0)
|
|
{
|
|
if (!parentTradeList.Contains(O.ParentTradeId))
|
|
{
|
|
O.StockEqvNotional = O.eodTrade.trade != null ? O.eodTrade.trade.StockEqvNotional : 0;
|
|
O.StockEqvNotionalReal = O.eodTrade.trade != null ? O.eodTrade.trade.StockEqvNotionalReal : 0;
|
|
parentTradeList.Add(O.ParentTradeId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
O.StockEqvNotional = O.eodTrade.trade != null ? O.eodTrade.trade.StockEqvNotional : 0;
|
|
O.StockEqvNotionalReal = O.eodTrade.trade != null ? O.eodTrade.trade.StockEqvNotionalReal : 0;
|
|
}
|
|
}
|
|
});
|
|
//合并处理
|
|
var underlyingGroup = eodPnlListEnd.GroupBy(e => e.UnderlyingCode.ToUpperInvariant());
|
|
var underlyingIdList = underlyingGroup.Select(g => g.Key).ToList();
|
|
var underlyingRiskList = new List<UnderlyingRiskModel>();
|
|
|
|
//历史累计盈亏
|
|
var predicate2 = BuildPredicateOfEodPnlStatics(reqModel, dataProvider).Compile();
|
|
var accruedTotalPnlService = new AccruedTotalPnlService<eodPosition>(this);
|
|
|
|
var exchangeFinishedPnlList = accruedTotalPnlService.GetFinishedTradePnls(preDate, reqModel.ValueDateEnd.AddDays(-1), true)
|
|
.Where(predicate2).ToList();
|
|
var preValueDate = EodOperationBase.GetLastSettlementDate(reqModel.ValueDateEnd, true);
|
|
var preValueDateCommissionForHedge = accruedTotalPnlService.GetCommissionForHedge(preDate, preValueDate).Where(predicate2).ToList();//前一日的所有合约的累计手续费
|
|
//
|
|
var exchangeOptionRisks = CalculateExchangeListOptionRisks<eodRisk>(reqModel.ValueDateEnd, reqModel);//获取场内交易数据
|
|
var settlementType = ConsGlobal.SettlePriceMode.GetSettlementType(reqModel.EodSettlePriceMode.TrimToNull() ?? valuedateBLL.SystemDate.EodSettlePriceMode);
|
|
|
|
List<underlying_manager> umList = null;
|
|
List<Variety> varietyList = null;
|
|
List<VarietyLimit> limitList = null;
|
|
var umCodeList = underlyingGroup.Select(p => p.Key).Distinct().ToList();
|
|
if (umCodeList != null && umCodeList.Count > 0)
|
|
{
|
|
umList = DbContext.underlying_manager.AsNoTracking().Where(p => umCodeList.Contains(p.UnderlyingCode)).ToList();
|
|
if (umList != null && umList.Count > 0)
|
|
{
|
|
var umTypeIds = umList.Select(p => p.UnderlyingTypeId).Distinct().ToList();
|
|
varietyList = DbContext.variety.AsNoTracking().Where(p => umTypeIds.Contains(p.id)).ToList();
|
|
}
|
|
if (varietyList != null && varietyList.Count > 0)
|
|
{
|
|
var varietyCodes = varietyList.Select(p => p.VarietyCode).Distinct().ToList();
|
|
limitList = DbContext.variety_limit.AsNoTracking().Where(p => varietyCodes.Contains(p.VarietyCode)).ToList();
|
|
}
|
|
}
|
|
if (umList == null)
|
|
{
|
|
umList = new List<underlying_manager>();
|
|
}
|
|
if (varietyList == null)
|
|
{
|
|
varietyList = new List<Variety>();
|
|
}
|
|
if (limitList == null)
|
|
{
|
|
limitList = new List<VarietyLimit>();
|
|
}
|
|
|
|
#region 1.对于最后一日有持仓数据的合约
|
|
foreach (var groupItem in underlyingGroup)
|
|
{
|
|
dataProvider.TryGetEodPrice(groupItem.Key, settlementType, out var price);
|
|
var underlyingRisk = new UnderlyingRiskModel();
|
|
//var underlying = dataProvider.GetUnderlying(groupItem.Key);
|
|
var underlying = umList.FirstOrDefault(d => d.UnderlyingCode.Equals(groupItem.Key));
|
|
Variety variety = null;
|
|
if (underlying != null)
|
|
{
|
|
variety = varietyList.FirstOrDefault(d => d.id == underlying.UnderlyingTypeId);
|
|
//var variety_limit = variety == null ? null : DbContext.variety_limit.FirstOrDefault(o => o.VarietyCode == variety.VarietyCode);
|
|
var variety_limit = variety == null ? null : limitList.FirstOrDefault(o => o.VarietyCode == variety.VarietyCode);
|
|
underlyingRisk.UnderlyingId = underlying.id;
|
|
underlyingRisk.UnderlyingCode = underlying.UnderlyingCode;
|
|
underlyingRisk.UnderlyingPrice = price;
|
|
underlyingRisk.UnderlyingInstrumentType = underlying.UnderlyingInstrumentType;
|
|
underlyingRisk.VarietyCode = underlying.CommodityCode == "组合标的" ? "组合标的" : (variety == null ? underlying.UnderlyingType : variety.VarietyCode);
|
|
underlyingRisk.VarietyOpenLimitIcon = variety == null || !(variety_limit?.IsPercent ?? false) ? "¥" : "%";
|
|
}
|
|
else
|
|
{
|
|
underlying = dataProvider.GetUnderlying(groupItem.Key);
|
|
if (underlying == null)
|
|
{
|
|
throw new ServiceException("标的数据不存在:" + groupItem.Key);
|
|
}
|
|
variety = DbContext.variety.Find(underlying.UnderlyingTypeId);
|
|
var variety_limit = variety == null ? null : DbContext.variety_limit.FirstOrDefault(o => o.VarietyCode == variety.VarietyCode);
|
|
underlyingRisk.UnderlyingId = underlying.id;
|
|
underlyingRisk.UnderlyingCode = underlying.UnderlyingCode;
|
|
underlyingRisk.UnderlyingPrice = price;
|
|
underlyingRisk.UnderlyingInstrumentType = underlying.UnderlyingInstrumentType;
|
|
underlyingRisk.VarietyCode = underlying.CommodityCode == "组合标的" ? "组合标的" : (variety == null ? underlying.UnderlyingType : variety.VarietyCode);
|
|
underlyingRisk.VarietyOpenLimitIcon = variety == null || !(variety_limit?.IsPercent ?? false) ? "¥" : "%";
|
|
}
|
|
|
|
|
|
if (underlying.CommodityCode == "组合标的")
|
|
{
|
|
underlyingRisk.SyntheticUnderlyingTipsInfo = synthetic_underlyingBLL.GetUnderlyingTipsInfo(underlying.UnderlyingCode);
|
|
}
|
|
|
|
var underlyingExchangeFinishedPnlList = exchangeFinishedPnlList.Where(p => string.Equals(p.UnderlyingCode, underlying.UnderlyingCode, StringComparison.OrdinalIgnoreCase)).ToList();
|
|
var underlyingPreValueDateCommissionList = preValueDateCommissionForHedge.Where(p => string.Equals(p.UnderlyingCode, underlying.UnderlyingCode, StringComparison.OrdinalIgnoreCase)).ToList();
|
|
|
|
var otcOptionsTradeType = ConsTrade.OptionTradeTypes.ToList();
|
|
otcOptionsTradeType.Add("结构化交易");
|
|
otcOptionsTradeType.AddRange(DbContext.Structure_Info.Select(o => o.StructureName));
|
|
|
|
otcOptionsTradeType.Remove("收益互换");
|
|
//场外期权
|
|
var otcRiskList = groupItem.Where(g => otcOptionsTradeType.Contains(g.TradeType));
|
|
|
|
underlyingRisk.OtcRisk = new EodRiskModel
|
|
{
|
|
StockEqvNotional = otcRiskList.SumDouble(r => r.StockEqvNotional),
|
|
StockEqvNotionalReal = otcRiskList.SumDouble(r => r.StockEqvNotionalReal),
|
|
Pnl = otcRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0),
|
|
Delta = otcRiskList.SumDouble(r => r.Delta ?? 0),
|
|
DeltaCash = otcRiskList.SumDouble(r => r.DeltaCash ?? 0),
|
|
GammaCash = otcRiskList.SumDouble(r => r.GammaCash ?? 0),
|
|
PositionStockEqvNotional = otcRiskList.SumDouble(r => (r.Amount * r.SpotPrice) ?? 0),
|
|
Gamma = otcRiskList.SumDouble(r => r.Gamma ?? 0),
|
|
Theta = otcRiskList.SumDouble(r => r.Theta ?? 0),
|
|
Vega = otcRiskList.SumDouble(r => r.Vega ?? 0),
|
|
Rho = otcRiskList.SumDouble(r => r.Rho ?? 0),
|
|
DailyPnl = otcRiskList.SumDouble(r => r.DailyPnl ?? 0),
|
|
dPnlDelta = otcRiskList.SumDouble(r => r.dPnlDelta),
|
|
dPnlGamma = otcRiskList.SumDouble(r => r.dPnlGamma),
|
|
dPnlTheta = otcRiskList.SumDouble(r => r.dPnlTheta),
|
|
dPnlVega = otcRiskList.SumDouble(r => r.dPnlVega),
|
|
dPnlPsi = otcRiskList.SumDouble(r => r.dPnlPsi),
|
|
CumulativeFloatProfitLoss = otcRiskList.SumDouble(r => r.CumulativeFloatProfitLoss)
|
|
};
|
|
underlyingRisk.OtcRisk.DeltaInLots = TradeLotsCalc.CalcDeltaInLots(Convert.ToDouble(underlyingRisk.OtcRisk.Delta), variety, underlying);
|
|
underlyingRisk.OtcRisk.GammaInLots = TradeLotsCalc.CalcGammaInLots(Convert.ToDouble(underlyingRisk.OtcRisk.Gamma), variety, underlying);
|
|
|
|
//场内期权
|
|
var exchangeRiskList = groupItem.Where(g => g.TradeType == "场内期权");
|
|
|
|
var preValueDateCommissionExOptSum = underlyingPreValueDateCommissionList.Where(x => x.AssetType == "场内期权").SumDouble(x => x.TotalCommission);
|
|
var underlyingExchangeRisks = exchangeOptionRisks.Where(r => r.UnderlyingCode.Equals(groupItem.Key, StringComparison.OrdinalIgnoreCase));
|
|
underlyingRisk.ExOptionRisk = new EodRiskModel
|
|
{
|
|
Pnl = exchangeRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0),
|
|
Delta = underlyingExchangeRisks.SumDouble(r => NumberHelper.Normalize((double)r.Delta)),
|
|
DeltaCash = underlyingExchangeRisks.SumDouble(r => NumberHelper.Normalize(r.DeltaCash)),
|
|
GammaCash = underlyingExchangeRisks.SumDouble(r => NumberHelper.Normalize(r.GammaCash)),
|
|
StockEqvNotional = exchangeRiskList.SumDouble(r =>
|
|
{
|
|
var exoption = DataCacheProvider.GetExchangeListOptionDataSource().GetData(r.OptionCode);
|
|
return exoption == null ? 0 : NumberHelper.Abs(r.Amount * exoption.Strike);
|
|
}),
|
|
Gamma = underlyingExchangeRisks.SumDouble(r => NumberHelper.Normalize((double)r.Gamma)),
|
|
Theta = underlyingExchangeRisks.SumDouble(r => NumberHelper.Normalize((double)r.Theta)),
|
|
Vega = underlyingExchangeRisks.SumDouble(r => NumberHelper.Normalize((double)r.Vega)),
|
|
Rho = underlyingExchangeRisks.SumDouble(r => NumberHelper.Normalize((double)r.Rho)),
|
|
DailyCommission = exchangeRiskList.SumDouble(r => r.Commission) - preValueDateCommissionExOptSum,//当日累计 - 昨日累计 = 当日手续费
|
|
DailyPnl = exchangeRiskList.SumDouble(r => r.DailyPnl ?? 0),
|
|
dPnlDelta = exchangeRiskList.SumDouble(r => r.dPnlDelta),
|
|
dPnlGamma = exchangeRiskList.SumDouble(r => r.dPnlGamma),
|
|
dPnlTheta = exchangeRiskList.SumDouble(r => r.dPnlTheta),
|
|
dPnlVega = exchangeRiskList.SumDouble(r => r.dPnlVega),
|
|
dPnlPsi = exchangeRiskList.SumDouble(r => r.dPnlPsi),
|
|
CumulativeFloatProfitLoss = exchangeRiskList.SumDouble(r => r.CumulativeFloatProfitLoss),
|
|
Commission = exchangeRiskList.SumDouble(r => r.Commission)
|
|
};
|
|
underlyingRisk.ExOptionRisk.StockEqvNotionalReal = underlyingRisk.ExOptionRisk.StockEqvNotional;
|
|
underlyingRisk.ExOptionRisk.DeltaInLots = TradeLotsCalc.CalcDeltaInLots(Convert.ToDouble(underlyingRisk.ExOptionRisk.Delta), variety, underlying);
|
|
underlyingRisk.ExOptionRisk.GammaInLots = TradeLotsCalc.CalcGammaInLots(Convert.ToDouble(underlyingRisk.ExOptionRisk.Gamma), variety, underlying);
|
|
|
|
//标的交易
|
|
var hedgeRiskList = groupItem.Where(g => g.TradeType == "商品期货" || g.TradeType == "股票" || g.TradeType == "商品现货");
|
|
|
|
var finishedHedgeList = underlyingExchangeFinishedPnlList.Where(x => x.AssetType == "商品期货" || x.AssetType == "股票");
|
|
var preValueDateCommissionHedgeList = underlyingPreValueDateCommissionList.Where(x => x.AssetType == "商品期货" || x.AssetType == "股票");
|
|
|
|
var underlyingHedgeFinishedCommission = finishedHedgeList.SumDouble(x => x.TotalCommission);
|
|
var preValueDateCommissionHedgeSum = preValueDateCommissionHedgeList.SumDouble(x => x.TotalCommission);
|
|
|
|
underlyingRisk.FuturesRisk = new EodRiskModel
|
|
{
|
|
Pnl = hedgeRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0),
|
|
Position = hedgeRiskList.SumDouble(r => r.Amount),
|
|
StockEqvNotional = hedgeRiskList.SumDouble(r => NumberHelper.Abs(r.Amount * price)),
|
|
Commission = hedgeRiskList.SumDouble(r => r.Commission),
|
|
DailyCommission = hedgeRiskList.SumDouble(r => r.Commission) - preValueDateCommissionHedgeSum,//当日累计 - 昨日累计 = 当日手续费
|
|
DailyPnl = hedgeRiskList.SumDouble(r => r.DailyPnl ?? 0)
|
|
};
|
|
underlyingRisk.FuturesRisk.StockEqvNotionalReal = underlyingRisk.FuturesRisk.StockEqvNotional;
|
|
underlyingRisk.FuturesRisk.PositionInLots = TradeLotsCalc.CalcDeltaInLots(Convert.ToDouble(underlyingRisk.FuturesRisk.Position), variety, underlying);
|
|
underlyingRisk.FuturesRisk.PositionIncrementInLots = underlyingRisk.FuturesRisk.PositionInLots - 0;// tartPositionInLots;
|
|
underlyingRisk.FuturesRisk.Delta = underlyingRisk.FuturesRisk.Position;
|
|
underlyingRisk.FuturesRisk.DeltaCash = underlyingRisk.UnderlyingPrice * underlyingRisk.FuturesRisk.Delta ?? 0;
|
|
underlyingRisk.FuturesRisk.GammaCash = underlyingRisk.UnderlyingPrice * underlyingRisk.FuturesRisk.Gamma ?? 0;
|
|
underlyingRisk.FuturesRisk.DeltaInLots = underlyingRisk.FuturesRisk.PositionInLots;
|
|
|
|
//远期统计
|
|
var forwardRiskList = groupItem.Where(g => g.TradeType == "远期");
|
|
underlyingRisk.ForwardRisk = new EodRiskModel
|
|
{
|
|
Pnl = forwardRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0),
|
|
Delta = forwardRiskList.SumDouble(r => r.Delta ?? 0),
|
|
DeltaCash = forwardRiskList.SumDouble(r => r.DeltaCash ?? 0),
|
|
GammaCash = forwardRiskList.SumDouble(r => r.GammaCash ?? 0),
|
|
PositionStockEqvNotional = forwardRiskList.SumDouble(r => (r.Amount * r.SpotPrice) ?? 0),
|
|
DailyPnl = forwardRiskList.SumDouble(r => r.DailyPnl ?? 0)
|
|
};
|
|
underlyingRisk.ForwardRisk.DeltaInLots = TradeLotsCalc.CalcDeltaInLots(Convert.ToDouble(underlyingRisk.ForwardRisk.Delta), variety, underlying);
|
|
|
|
//收益互换统计
|
|
var swapRiskList = groupItem.Where(g => g.TradeType == "收益互换");
|
|
underlyingRisk.SwapRisk = new EodRiskModel
|
|
{
|
|
StockEqvNotional = swapRiskList.SumDouble(r => NumberHelper.Abs(r.StockEqvNotional)),
|
|
StockEqvNotionalReal = swapRiskList.SumDouble(r => NumberHelper.Abs(r.StockEqvNotionalReal)),
|
|
Pnl = swapRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0),
|
|
Delta = swapRiskList.SumDouble(r => r.Delta ?? 0),
|
|
DeltaCash = swapRiskList.SumDouble(r => r.DeltaCash ?? 0),
|
|
GammaCash = swapRiskList.SumDouble(r => r.GammaCash ?? 0),
|
|
PositionStockEqvNotional = swapRiskList.SumDouble(r => (r.Amount * r.SpotPrice) ?? 0),
|
|
DailyPnl = swapRiskList.SumDouble(r => r.DailyPnl ?? 0)
|
|
};
|
|
underlyingRisk.SwapRisk.DeltaInLots = TradeLotsCalc.CalcDeltaInLots(Convert.ToDouble(underlyingRisk.SwapRisk.Delta), variety, underlying);
|
|
|
|
//汇总合计
|
|
underlyingRisk.PortfolioRisk = new EodRiskModel
|
|
{
|
|
StockEqvNotional = underlyingRisk.OtcRisk.StockEqvNotional + underlyingRisk.ExOptionRisk.StockEqvNotional + underlyingRisk.FuturesRisk.StockEqvNotional + /*underlyingRisk.ForwardRisk.StockEqvNotional +*/ underlyingRisk.SwapRisk.StockEqvNotional,
|
|
StockEqvNotionalReal = underlyingRisk.OtcRisk.StockEqvNotionalReal + underlyingRisk.ExOptionRisk.StockEqvNotionalReal + underlyingRisk.FuturesRisk.StockEqvNotionalReal + /*underlyingRisk.ForwardRisk.StockEqvNotionalReal +*/ underlyingRisk.SwapRisk.StockEqvNotionalReal,
|
|
OtcStockEqvNotional = underlyingRisk.OtcRisk.StockEqvNotional + underlyingRisk.SwapRisk.StockEqvNotional,
|
|
OtcStockEqvNotionalReal = underlyingRisk.OtcRisk.StockEqvNotionalReal + underlyingRisk.SwapRisk.StockEqvNotionalReal,
|
|
Pnl = underlyingRisk.OtcRisk.Pnl + underlyingRisk.ExOptionRisk.Pnl + underlyingRisk.FuturesRisk.Pnl + underlyingRisk.ForwardRisk.Pnl + underlyingRisk.SwapRisk.Pnl,
|
|
Delta = underlyingRisk.OtcRisk.Delta + underlyingRisk.ExOptionRisk.Delta + underlyingRisk.FuturesRisk.Delta + underlyingRisk.ForwardRisk.Delta + underlyingRisk.SwapRisk.Delta,
|
|
DeltaCash = underlyingRisk.OtcRisk.DeltaCash + underlyingRisk.ExOptionRisk.DeltaCash + underlyingRisk.FuturesRisk.DeltaCash + underlyingRisk.ForwardRisk.DeltaCash + underlyingRisk.SwapRisk.DeltaCash,
|
|
GammaCash = underlyingRisk.OtcRisk.GammaCash + underlyingRisk.ExOptionRisk.GammaCash + underlyingRisk.FuturesRisk.GammaCash + underlyingRisk.ForwardRisk.GammaCash + underlyingRisk.SwapRisk.GammaCash,
|
|
PositionStockEqvNotional = underlyingRisk.OtcRisk.PositionStockEqvNotional + underlyingRisk.ExOptionRisk.PositionStockEqvNotional + underlyingRisk.ForwardRisk.PositionStockEqvNotional + underlyingRisk.SwapRisk.PositionStockEqvNotional,
|
|
DeltaInLots = underlyingRisk.OtcRisk.DeltaInLots + underlyingRisk.ExOptionRisk.DeltaInLots + underlyingRisk.FuturesRisk.DeltaInLots + underlyingRisk.ForwardRisk.DeltaInLots + underlyingRisk.SwapRisk.DeltaInLots,
|
|
DailyPnl = underlyingRisk.OtcRisk.DailyPnl + underlyingRisk.ExOptionRisk.DailyPnl + underlyingRisk.FuturesRisk.DailyPnl + +underlyingRisk.ForwardRisk.DailyPnl + +underlyingRisk.SwapRisk.DailyPnl,
|
|
Commission = underlyingRisk.ExOptionRisk.Commission + underlyingRisk.FuturesRisk.Commission,
|
|
Gamma = underlyingRisk.OtcRisk.Gamma + underlyingRisk.ExOptionRisk.Gamma,
|
|
Theta = underlyingRisk.OtcRisk.Theta + underlyingRisk.ExOptionRisk.Theta,
|
|
Vega = underlyingRisk.OtcRisk.Vega + underlyingRisk.ExOptionRisk.Vega,
|
|
Rho = underlyingRisk.OtcRisk.Rho + underlyingRisk.ExOptionRisk.Rho,
|
|
dPnlDelta = underlyingRisk.OtcRisk.dPnlDelta + underlyingRisk.ExOptionRisk.dPnlDelta,
|
|
dPnlGamma = underlyingRisk.OtcRisk.dPnlGamma + underlyingRisk.ExOptionRisk.dPnlGamma,
|
|
dPnlTheta = underlyingRisk.OtcRisk.dPnlTheta + underlyingRisk.ExOptionRisk.dPnlTheta,
|
|
dPnlVega = underlyingRisk.OtcRisk.dPnlVega + underlyingRisk.ExOptionRisk.dPnlVega,
|
|
dPnlPsi = underlyingRisk.OtcRisk.dPnlPsi + underlyingRisk.ExOptionRisk.dPnlPsi,
|
|
CumulativeFloatProfitLoss = underlyingRisk.OtcRisk.CumulativeFloatProfitLoss + underlyingRisk.ExOptionRisk.CumulativeFloatProfitLoss,
|
|
};
|
|
underlyingRiskList.Add(underlyingRisk);
|
|
}
|
|
#endregion
|
|
|
|
underlyingRiskList = underlyingRiskList.OrderBy(u => u, new UnderlyingRiskModelSortComparer()).ToList();
|
|
var varietyRiskExposureReports = underlyingRiskList.GroupBy(u => new { u.VarietyCode, u.VarietyOpenLimit, u.VarietyOpenLimitIcon }).Select(g =>
|
|
{
|
|
var list = g.ToList();
|
|
var portfolioSum = new EodRiskModel
|
|
{
|
|
StockEqvNotional = list.SumDouble(l => l.PortfolioRisk.StockEqvNotional),
|
|
StockEqvNotionalReal = list.SumDouble(l => l.PortfolioRisk.StockEqvNotionalReal),
|
|
OtcStockEqvNotional = list.SumDouble(l => l.PortfolioRisk.OtcStockEqvNotional),
|
|
OtcStockEqvNotionalReal = list.SumDouble(l => l.PortfolioRisk.OtcStockEqvNotionalReal),
|
|
Pnl = list.SumDouble(l => l.PortfolioRisk.Pnl),
|
|
Delta = list.SumDouble(l => l.PortfolioRisk.Delta),
|
|
DeltaCash = list.SumDouble(l => l.PortfolioRisk.DeltaCash),
|
|
GammaCash = list.SumDouble(l => l.PortfolioRisk.GammaCash),
|
|
PositionStockEqvNotional = list.SumDouble(l => l.PortfolioRisk.PositionStockEqvNotional),
|
|
DeltaInLots = list.SumDouble(l => l.PortfolioRisk.DeltaInLots),
|
|
DailyPnl = list.SumDouble(l => l.PortfolioRisk.DailyPnl),
|
|
Commission = list.SumDouble(l => l.PortfolioRisk.Commission),
|
|
Gamma = list.SumDouble(l => l.PortfolioRisk.Gamma),
|
|
Theta = list.SumDouble(l => l.PortfolioRisk.Theta),
|
|
Vega = list.SumDouble(l => l.PortfolioRisk.Vega),
|
|
Rho = list.SumDouble(l => l.PortfolioRisk.Rho),
|
|
dPnlDelta = list.SumDouble(l => l.PortfolioRisk.dPnlDelta),
|
|
dPnlGamma = list.SumDouble(l => l.PortfolioRisk.dPnlGamma),
|
|
dPnlTheta = list.SumDouble(l => l.PortfolioRisk.dPnlTheta),
|
|
dPnlVega = list.SumDouble(l => l.PortfolioRisk.dPnlVega),
|
|
dPnlPsi = list.SumDouble(l => l.PortfolioRisk.dPnlPsi),
|
|
CumulativeFloatProfitLoss = list.SumDouble(l => l.PortfolioRisk.CumulativeFloatProfitLoss),
|
|
};
|
|
var otcSum = new EodRiskModel
|
|
{
|
|
StockEqvNotional = list.SumDouble(l => l.OtcRisk.StockEqvNotional),
|
|
StockEqvNotionalReal = list.SumDouble(l => l.OtcRisk.StockEqvNotionalReal),
|
|
Pnl = list.SumDouble(l => l.OtcRisk.Pnl),
|
|
Delta = list.SumDouble(l => l.OtcRisk.Delta),
|
|
DeltaInLots = list.SumDouble(l => l.OtcRisk.DeltaInLots),
|
|
Gamma = list.SumDouble(l => l.OtcRisk.Gamma),
|
|
GammaInLots = list.SumDouble(l => l.OtcRisk.GammaInLots),
|
|
Theta = list.SumDouble(l => l.OtcRisk.Theta),
|
|
Vega = list.SumDouble(l => l.OtcRisk.Vega),
|
|
Rho = list.SumDouble(l => l.OtcRisk.Rho),
|
|
DailyPnl = list.SumDouble(l => l.OtcRisk.DailyPnl),
|
|
DeltaCash = list.SumDouble(l => l.OtcRisk.DeltaCash),
|
|
dPnlDelta = list.SumDouble(l => l.OtcRisk.dPnlDelta),
|
|
dPnlGamma = list.SumDouble(l => l.OtcRisk.dPnlGamma),
|
|
dPnlTheta = list.SumDouble(l => l.OtcRisk.dPnlTheta),
|
|
dPnlVega = list.SumDouble(l => l.OtcRisk.dPnlVega),
|
|
dPnlPsi = list.SumDouble(l => l.OtcRisk.dPnlPsi),
|
|
CumulativeFloatProfitLoss = list.SumDouble(l => l.OtcRisk.CumulativeFloatProfitLoss),
|
|
};
|
|
var exchangeListOptionSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.ExOptionRisk.Pnl),
|
|
Delta = list.SumDouble(l => l.ExOptionRisk.Delta),
|
|
DeltaInLots = list.SumDouble(l => l.ExOptionRisk.DeltaInLots),
|
|
Gamma = list.SumDouble(l => l.ExOptionRisk.Gamma),
|
|
GammaInLots = list.SumDouble(l => l.ExOptionRisk.GammaInLots),
|
|
Theta = list.SumDouble(l => l.ExOptionRisk.Theta),
|
|
Vega = list.SumDouble(l => l.ExOptionRisk.Vega),
|
|
Rho = list.SumDouble(l => l.ExOptionRisk.Rho),
|
|
Commission = list.SumDouble(l => l.ExOptionRisk.Commission),
|
|
DailyPnl = list.SumDouble(l => l.ExOptionRisk.DailyPnl),
|
|
DailyCommission = list.SumDouble(l => l.ExOptionRisk.DailyCommission),
|
|
DeltaCash = list.SumDouble(l => l.ExOptionRisk.DeltaCash),
|
|
StockEqvNotional = list.SumDouble(l => l.ExOptionRisk.StockEqvNotional),
|
|
StockEqvNotionalReal = list.SumDouble(l => l.ExOptionRisk.StockEqvNotionalReal),
|
|
dPnlDelta = list.SumDouble(l => l.ExOptionRisk.dPnlDelta),
|
|
dPnlGamma = list.SumDouble(l => l.ExOptionRisk.dPnlGamma),
|
|
dPnlTheta = list.SumDouble(l => l.ExOptionRisk.dPnlTheta),
|
|
dPnlVega = list.SumDouble(l => l.ExOptionRisk.dPnlVega),
|
|
dPnlPsi = list.SumDouble(l => l.ExOptionRisk.dPnlPsi),
|
|
CumulativeFloatProfitLoss = list.SumDouble(l => l.ExOptionRisk.CumulativeFloatProfitLoss),
|
|
};
|
|
var futuresSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.FuturesRisk.Pnl),
|
|
Position = list.SumDouble(l => l.FuturesRisk.Position),
|
|
PositionInLots = list.SumDouble(l => l.FuturesRisk.PositionInLots),
|
|
PositionIncrementInLots = list.SumDouble(l => l.FuturesRisk.PositionIncrementInLots),
|
|
Commission = list.SumDouble(l => l.FuturesRisk.Commission),
|
|
DailyPnl = list.SumDouble(l => l.FuturesRisk.DailyPnl),
|
|
DailyCommission = list.SumDouble(l => l.FuturesRisk.DailyCommission),
|
|
StockEqvNotional = list.SumDouble(l => l.FuturesRisk.StockEqvNotional),
|
|
StockEqvNotionalReal = list.SumDouble(l => l.FuturesRisk.StockEqvNotionalReal)
|
|
};
|
|
var forwardSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.ForwardRisk.Pnl),
|
|
Delta = list.SumDouble(l => l.ForwardRisk.Delta),
|
|
DeltaInLots = list.SumDouble(l => l.ForwardRisk.DeltaInLots),
|
|
DailyPnl = list.SumDouble(l => l.ForwardRisk.DailyPnl)
|
|
};
|
|
var swapSum = new EodRiskModel
|
|
{
|
|
StockEqvNotional = list.SumDouble(l => l.SwapRisk.StockEqvNotional),
|
|
StockEqvNotionalReal = list.SumDouble(l => l.SwapRisk.StockEqvNotionalReal),
|
|
Pnl = list.SumDouble(l => l.SwapRisk.Pnl),
|
|
Delta = list.SumDouble(l => l.SwapRisk.Delta),
|
|
DeltaInLots = list.SumDouble(l => l.SwapRisk.DeltaInLots),
|
|
DailyPnl = list.SumDouble(l => l.SwapRisk.DailyPnl)
|
|
};
|
|
var varietyLimit = DbContext.variety_limit.FirstOrDefault(o => o.VarietyCode == g.Key.VarietyCode);
|
|
return new VarietyRiskExposureModel
|
|
{
|
|
VarietyCode = g.Key.VarietyCode,
|
|
VarietyOpenLimit = g.Key.VarietyOpenLimit,
|
|
VarietyOpenLimitIcon = g.Key.VarietyOpenLimitIcon,
|
|
VarietySum = new RiskExposureReportSumModel
|
|
{
|
|
PortfolioSum = portfolioSum,
|
|
OtcSum = otcSum,
|
|
ExOptionSum = exchangeListOptionSum,
|
|
FuturesSum = futuresSum,
|
|
ForwardSum = forwardSum,
|
|
SwapSum = swapSum
|
|
},
|
|
UnderlyingRiskList = list,
|
|
varietyLimit = varietyLimit ?? new VarietyLimit()
|
|
};
|
|
}).ToList();
|
|
|
|
result = new RiskExposureReportModel
|
|
{
|
|
ReportModels = varietyRiskExposureReports,
|
|
//总和盈亏比例计算元素取值逻辑
|
|
TotalPnlRate = accruedTotalPnlService.CalcTotalPnlRate(startDate, reqModel.ValueDateEnd),
|
|
Sum = new RiskExposureReportSumModel
|
|
{
|
|
PortfolioSum = varietyRiskExposureReports.Select(r => r.VarietySum.PortfolioSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
OtcSum = varietyRiskExposureReports.Select(r => r.VarietySum.OtcSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
ExOptionSum = varietyRiskExposureReports.Select(r => r.VarietySum.ExOptionSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
FuturesSum = varietyRiskExposureReports.Select(r => r.VarietySum.FuturesSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
ForwardSum = varietyRiskExposureReports.Select(r => r.VarietySum.ForwardSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
SwapSum = varietyRiskExposureReports.Select(r => r.VarietySum.SwapSum).Aggregate(new EodRiskModel(), (p, n) => p + n)
|
|
}
|
|
};
|
|
return result;
|
|
}
|
|
|
|
public RiskExposureReportModel SearchRiskExposureReportsEchart<eodRisk, eodPnl>(RiskRequestModel reqModel) where eodRisk : EodTradeRisk where eodPnl : EodPnl
|
|
{
|
|
RiskExposureReportModel result = null;
|
|
|
|
reqModel = CheckModel(reqModel);
|
|
var startDate = EodOperationBase.GetLastSettlementDate(reqModel.ValueDateStart ?? valuedateBLL.SystemDate.AccruedTotalPnlStartDate ?? DateTime.Today);
|
|
var preDate = EodOperationBase.GetLastSettlementDate(startDate.AddDays(-1));
|
|
var dataProvider = new EodRiskCalcDataProvider(reqModel.ValueDateEnd, startDate);
|
|
var useFirstEod = reqModel.ValueDateStart.HasValue ? PredicateBuilder.True<eodPosition>() : PredicateBuilder.False<eodPosition>();
|
|
if (reqModel.ValueDateStart.HasValue)
|
|
{
|
|
useFirstEod = PredicateBuilder.Create<eodPosition>(t => t.ValueDate == preDate);
|
|
}
|
|
var tdPredicate = PredicateBuilder.Create<trade>(n => n.ValidState != ConsGlobal.InValid);
|
|
var predicate = PredicateBuilder.Create<eodPosition>(
|
|
t => t.ValueDate > preDate && t.ValueDate <= reqModel.ValueDateEnd && t.TradeType != "结构化交易" && t.TradeType != "现金流交易");
|
|
|
|
|
|
if (reqModel.BookIds.Any())
|
|
{
|
|
predicate = predicate.And(q => reqModel.BookIds.Contains(q.BookId));
|
|
}
|
|
|
|
if (reqModel.TradeTypes.Any())
|
|
{
|
|
predicate = predicate.And(q =>
|
|
((q.StructureType == null || q.StructureType == "") && reqModel.TradeTypes.Contains(q.TradeType)) ||
|
|
(q.StructureType != null && q.StructureType != "" && reqModel.TradeTypes.Contains(q.StructureType)));
|
|
}
|
|
|
|
// 索引数据(先将时间段内所有要统计的数据做个索引)
|
|
//如果后面要升级成只使用HedgeUniqueCode判断,则需要在TradeId大于0时将HedgeUniqueCode变成TradeId
|
|
//否则升级后老的数据和新的数据在这段逻辑中就会进入不同的分组导致统计错误
|
|
var sourceQuery = from t in DbContext.Set<eodPosition>().Where(predicate)
|
|
join un in DbContext.underlying_manager on t.UnderlyingCode equals un.UnderlyingCode
|
|
where (!reqModel.VarietyIds.Any() || reqModel.VarietyIds.Contains(un.UnderlyingTypeId))
|
|
&& (!reqModel.UnderlyingIds.Any() || reqModel.UnderlyingIds.Contains(un.id))
|
|
&& (t.TradeId < 1 || DbContext.trade.Where(n => n.id == t.TradeId).Where(tdPredicate).Any())
|
|
group t by new { t.TradeId, t.HedgeUniqueCode } into g
|
|
select new
|
|
{
|
|
g.Key.TradeId,
|
|
g.Key.HedgeUniqueCode,
|
|
maxDate = g.Max(B => B.ValueDate)
|
|
};
|
|
|
|
var query = from source in sourceQuery
|
|
join lastEod in DbContext.Set<eodPosition>()
|
|
on new { ValueDate = source.maxDate, TradeId = source.TradeId + source.HedgeUniqueCode }
|
|
equals new { lastEod.ValueDate, TradeId = lastEod.TradeId + lastEod.HedgeUniqueCode }
|
|
|
|
join tempEod in DbContext.Set<eodPosition>().Where(useFirstEod)
|
|
on new { TradeId = source.TradeId + source.HedgeUniqueCode }
|
|
equals new { TradeId = tempEod.TradeId + tempEod.HedgeUniqueCode } into tempEod
|
|
from firstEod in tempEod.DefaultIfEmpty()
|
|
|
|
select new RiskExposureItemModel
|
|
{
|
|
ValueDate = lastEod.ValueDate,
|
|
TradeId = lastEod.TradeId,
|
|
ParentTradeId = lastEod.ParentTradeId,
|
|
|
|
UnderlyingCode = lastEod.UnderlyingCode,
|
|
OptionCode = lastEod.ExchangeOptionCode,
|
|
UnderlyingId = lastEod.UnderlyingId,
|
|
TradeType = lastEod.StructureType == null || lastEod.StructureType == "" ? lastEod.TradeType : lastEod.StructureType,
|
|
AccruedTotalPnL = lastEod.TotalPnL - (firstEod == null ? 0 : firstEod.TotalPnL),
|
|
};
|
|
|
|
var eodPnlListEnd = query.ToList();
|
|
//合并处理
|
|
var underlyingGroup = eodPnlListEnd.GroupBy(e => e.UnderlyingCode.ToUpperInvariant());
|
|
var underlyingRiskList = new List<UnderlyingRiskModel>();
|
|
|
|
#region 1.对于最后一日有持仓数据的合约
|
|
foreach (var groupItem in underlyingGroup)
|
|
{
|
|
var underlyingRisk = new UnderlyingRiskModel();
|
|
|
|
var otcOptionsTradeType = ConsTrade.OptionTradeTypes.ToList();
|
|
otcOptionsTradeType.Add("结构化交易");
|
|
otcOptionsTradeType.AddRange(DbContext.Structure_Info.Select(o => o.StructureName));
|
|
|
|
otcOptionsTradeType.Remove("收益互换");
|
|
//场外期权
|
|
var otcRiskList = groupItem.Where(g => otcOptionsTradeType.Contains(g.TradeType));
|
|
|
|
underlyingRisk.OtcRisk = new EodRiskModel
|
|
{
|
|
Pnl = otcRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0)
|
|
};
|
|
|
|
//场内期权
|
|
var exchangeRiskList = groupItem.Where(g => g.TradeType == "场内期权");
|
|
underlyingRisk.ExOptionRisk = new EodRiskModel
|
|
{
|
|
Pnl = exchangeRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0)
|
|
};
|
|
|
|
//标的交易
|
|
var hedgeRiskList = groupItem.Where(g => g.TradeType == "商品期货" || g.TradeType == "股票" || g.TradeType == "商品现货");
|
|
underlyingRisk.FuturesRisk = new EodRiskModel
|
|
{
|
|
Pnl = hedgeRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0)
|
|
};
|
|
|
|
//远期统计
|
|
var forwardRiskList = groupItem.Where(g => g.TradeType == "远期");
|
|
underlyingRisk.ForwardRisk = new EodRiskModel
|
|
{
|
|
Pnl = forwardRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0)
|
|
};
|
|
//收益互换统计
|
|
var swapRiskList = groupItem.Where(g => g.TradeType == "收益互换");
|
|
underlyingRisk.SwapRisk = new EodRiskModel
|
|
{
|
|
Pnl = swapRiskList.SumDouble(r => r.AccruedTotalPnL ?? 0)
|
|
};
|
|
//汇总合计
|
|
underlyingRisk.PortfolioRisk = new EodRiskModel
|
|
{
|
|
Pnl = underlyingRisk.OtcRisk.Pnl + underlyingRisk.ExOptionRisk.Pnl + underlyingRisk.FuturesRisk.Pnl + underlyingRisk.ForwardRisk.Pnl + underlyingRisk.SwapRisk.Pnl,
|
|
};
|
|
underlyingRiskList.Add(underlyingRisk);
|
|
}
|
|
#endregion
|
|
|
|
underlyingRiskList = underlyingRiskList.OrderBy(u => u, new UnderlyingRiskModelSortComparer()).ToList();
|
|
var varietyRiskExposureReports = underlyingRiskList.GroupBy(u => new { u.VarietyCode, u.VarietyOpenLimit, u.VarietyOpenLimitIcon }).Select(g =>
|
|
{
|
|
var list = g.ToList();
|
|
var portfolioSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.PortfolioRisk.Pnl)
|
|
};
|
|
var otcSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.OtcRisk.Pnl),
|
|
|
|
};
|
|
var exchangeListOptionSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.ExOptionRisk.Pnl)
|
|
};
|
|
var futuresSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.FuturesRisk.Pnl)
|
|
};
|
|
var forwardSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.ForwardRisk.Pnl)
|
|
};
|
|
var swapSum = new EodRiskModel
|
|
{
|
|
Pnl = list.SumDouble(l => l.SwapRisk.Pnl)
|
|
};
|
|
return new VarietyRiskExposureModel
|
|
{
|
|
VarietySum = new RiskExposureReportSumModel
|
|
{
|
|
PortfolioSum = portfolioSum,
|
|
OtcSum = otcSum,
|
|
ExOptionSum = exchangeListOptionSum,
|
|
FuturesSum = futuresSum,
|
|
ForwardSum = forwardSum,
|
|
SwapSum = swapSum
|
|
}
|
|
};
|
|
}).ToList();
|
|
|
|
result = new RiskExposureReportModel
|
|
{
|
|
Sum = new RiskExposureReportSumModel
|
|
{
|
|
PortfolioSum = varietyRiskExposureReports.Select(r => r.VarietySum.PortfolioSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
OtcSum = varietyRiskExposureReports.Select(r => r.VarietySum.OtcSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
ExOptionSum = varietyRiskExposureReports.Select(r => r.VarietySum.ExOptionSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
FuturesSum = varietyRiskExposureReports.Select(r => r.VarietySum.FuturesSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
ForwardSum = varietyRiskExposureReports.Select(r => r.VarietySum.ForwardSum).Aggregate(new EodRiskModel(), (p, n) => p + n),
|
|
SwapSum = varietyRiskExposureReports.Select(r => r.VarietySum.SwapSum).Aggregate(new EodRiskModel(), (p, n) => p + n)
|
|
}
|
|
};
|
|
return result;
|
|
}
|
|
|
|
|
|
//检查查询对象并规范化
|
|
public RiskRequestModel CheckModel(RiskRequestModel reqModel)
|
|
{
|
|
if (reqModel == null)
|
|
{
|
|
throw new ServiceException("实体不能为空");
|
|
}
|
|
|
|
var endDateName = reqModel.ValueDateStart == null ? "结算日期" : "结束日期";
|
|
|
|
if (reqModel.ValueDateStart != null && reqModel.ValueDateStart > reqModel.ValueDateEnd)
|
|
{
|
|
throw new ServiceException("开始日期不能大于结束日期");
|
|
}
|
|
DateTime settleDate;
|
|
if (reqModel.EodSettlePriceMode == "结算价")
|
|
{
|
|
settleDate = EodOperationBase.GetLastSettlementDate_Settle(false);
|
|
}
|
|
else
|
|
{
|
|
settleDate = EodOperationBase.GetLastSettlementDate(valuedateBLL.ValueDate);
|
|
}
|
|
if (reqModel.ValueDateEnd > settleDate)
|
|
{
|
|
throw new ServiceException($"{endDateName}不能大于上一次收盘日期{settleDate:yyyy-MM-dd}");
|
|
}
|
|
|
|
return reqModel.Normalize();
|
|
}
|
|
|
|
//构建EodPnlStaticsDto对象查询预测
|
|
private Expression<Func<EodPnlStaticsDto, bool>> BuildPredicateOfEodPnlStatics(RiskRequestModel reqModel, EodRiskCalcDataProvider dataProvider)
|
|
{
|
|
var predicate = PredicateBuilder.True<EodPnlStaticsDto>();
|
|
|
|
if (reqModel.BookIds.Any())
|
|
{
|
|
predicate = predicate.And(q => reqModel.BookIds.Contains(q.BookId));
|
|
}
|
|
|
|
if (reqModel.ClientIds.Any())
|
|
{
|
|
predicate = predicate.And(q => reqModel.ClientIds.Contains(q.ClientId));
|
|
}
|
|
|
|
if (reqModel.TradeTypes.Any())
|
|
{
|
|
predicate = predicate.And(q => reqModel.TradeTypes.Contains(q.AssetType));
|
|
}
|
|
|
|
IEnumerable<int> UnderlyingIds = null;
|
|
|
|
//标的过滤
|
|
if (reqModel.UnderlyingIds != null && reqModel.UnderlyingIds.Any())
|
|
{
|
|
UnderlyingIds = reqModel.UnderlyingIds;
|
|
}
|
|
|
|
//品种过滤
|
|
if (reqModel.VarietyIds != null && reqModel.VarietyIds.Any())
|
|
{
|
|
var UnderlyingIds2 = dataProvider.GetUnderlyingQuery()
|
|
.Where(n => reqModel.VarietyIds.Contains(n.UnderlyingTypeId))
|
|
.Select(n => n.id).ToArray();
|
|
//合并标的过滤(取并集)
|
|
UnderlyingIds = UnderlyingIds == null ? UnderlyingIds2 : UnderlyingIds.Intersect(UnderlyingIds2);
|
|
}
|
|
|
|
if (UnderlyingIds != null)
|
|
{
|
|
var UnderlyingCodes = dataProvider.GetUnderlyingQuery()
|
|
.Where(n => UnderlyingIds.Contains(n.id))
|
|
.Select(n => n.UnderlyingCode).ToArray();
|
|
if (!UnderlyingCodes.Any())
|
|
{
|
|
UnderlyingCodes = new string[] { string.Empty };
|
|
}
|
|
predicate = predicate.And(q => UnderlyingCodes.Contains(q.UnderlyingCode));
|
|
}
|
|
|
|
if (reqModel.TraderIds.Any())
|
|
{
|
|
predicate = predicate.And(q => reqModel.TraderIds.Contains(q.TraderId));
|
|
}
|
|
|
|
return predicate;
|
|
}
|
|
/// <summary>
|
|
/// 获取模板名称
|
|
/// </summary>
|
|
private void GetSettleDocName(DateTime? ValueDateStart, string path, out string settleDocName)
|
|
{
|
|
var suffix = "";
|
|
if (PS.Config.GetSettlementConfig().CalcPnlExplain)
|
|
{
|
|
suffix = "(含归因盈亏)";
|
|
}
|
|
//获取盯市报告模板信息
|
|
settleDocName = $"市场风险模板一{suffix}-{PS.Config.Company}.xlsx";//单客户导出单日
|
|
if (ValueDateStart != null)
|
|
{
|
|
settleDocName = $"市场风险模板二{suffix}-{PS.Config.Company}.xlsx";//单客户导出区间
|
|
}
|
|
settleDocName = OtcAppContext.MapPath(Path.Combine(path + settleDocName));
|
|
if (!File.Exists(settleDocName))
|
|
{
|
|
settleDocName = $"市场风险模板一{suffix}.xlsx";//导出单日
|
|
if (ValueDateStart != null)
|
|
{
|
|
settleDocName = $"市场风险模板二{suffix}.xlsx";//导出区间
|
|
}
|
|
settleDocName = OtcAppContext.MapPath(Path.Combine(path + settleDocName));
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 导出报告
|
|
/// </summary>
|
|
public byte[] ExportReport<eodRisk, eodPnl>(RiskRequestModel reqModel) where eodRisk : EodTradeRisk where eodPnl : EodPnl
|
|
{
|
|
RiskExposureReportModel report = null;
|
|
var useOldMaskRiskService = Environment.GetEnvironmentVariable("AppSettings:UseOldMaskRiskService");
|
|
|
|
if (!string.IsNullOrEmpty(useOldMaskRiskService) && "true".Equals(useOldMaskRiskService))
|
|
{
|
|
report = SearchRiskExposureReportsV2<eodRisk, eodPnl>(reqModel);
|
|
}
|
|
else
|
|
{
|
|
var maskRiskService = new MarketRiskService<eodPosition>(OptUser);
|
|
report = maskRiskService.SearchMarketRiskData<eodRisk, eodPnl>(reqModel);
|
|
}
|
|
report.ReportStart = (reqModel.ValueDateStart ?? reqModel.ValueDateEnd).ToString("yyyy-M-d");
|
|
report.ReportEnd = reqModel.ValueDateEnd.ToString("yyyy-M-d");
|
|
|
|
if (report.ReportModels == null || !report.ReportModels.Any())
|
|
{
|
|
throw new Exception("无导出数据!");//(请确保区间收盘是连续的,特别是最后日)
|
|
}
|
|
|
|
GetSettleDocName(reqModel.ValueDateStart, "~/App_Docs/导出模板/", out var settleDocName);
|
|
var templateFileName = settleDocName;
|
|
|
|
var PortfolioList = new List<EodRiskModel>();
|
|
var OtcList = new List<EodRiskModel>();
|
|
var ExOptionList = new List<EodRiskModel>();
|
|
var FuturesList = new List<EodRiskModel>();
|
|
var ForwardList = new List<EodRiskModel>();
|
|
var SwapList = new List<EodRiskModel>();
|
|
var emptyRiskModel = new EodRiskModel { VarietyCode = "####" };
|
|
|
|
foreach (var item in report.ReportModels)
|
|
{
|
|
item.VarietySum.PortfolioSum.VarietyCode = item.VarietyCode;
|
|
PortfolioList.Add(item.VarietySum.PortfolioSum);
|
|
PortfolioList.AddRange(item.UnderlyingRiskList.Select(m =>
|
|
{
|
|
m.PortfolioRisk.UnderlyingCode = m.UnderlyingCode;
|
|
m.PortfolioRisk.UnderlyingPrice = m.UnderlyingPrice?.ToString("F2");
|
|
return m.PortfolioRisk;
|
|
}));
|
|
PortfolioList.Add(emptyRiskModel);
|
|
|
|
item.VarietySum.OtcSum.VarietyCode = item.VarietyCode;
|
|
OtcList.Add(item.VarietySum.OtcSum);
|
|
OtcList.AddRange(item.UnderlyingRiskList.Select(m =>
|
|
{
|
|
m.OtcRisk.UnderlyingCode = m.UnderlyingCode;
|
|
m.OtcRisk.UnderlyingPrice = m.UnderlyingPrice?.ToString("F2");
|
|
return m.OtcRisk;
|
|
}));
|
|
OtcList.Add(emptyRiskModel);
|
|
|
|
item.VarietySum.ExOptionSum.VarietyCode = item.VarietyCode;
|
|
ExOptionList.Add(item.VarietySum.ExOptionSum);
|
|
ExOptionList.AddRange(item.UnderlyingRiskList.Select(m =>
|
|
{
|
|
m.ExOptionRisk.UnderlyingCode = m.UnderlyingCode;
|
|
m.ExOptionRisk.UnderlyingPrice = m.UnderlyingPrice?.ToString("F2");
|
|
return m.ExOptionRisk;
|
|
}));
|
|
ExOptionList.Add(emptyRiskModel);
|
|
|
|
item.VarietySum.FuturesSum.VarietyCode = item.VarietyCode;
|
|
FuturesList.Add(item.VarietySum.FuturesSum);
|
|
FuturesList.AddRange(item.UnderlyingRiskList.Select(m =>
|
|
{
|
|
m.FuturesRisk.UnderlyingCode = m.UnderlyingCode;
|
|
m.FuturesRisk.UnderlyingPrice = m.UnderlyingPrice?.ToString("F2");
|
|
return m.FuturesRisk;
|
|
}));
|
|
FuturesList.Add(emptyRiskModel);
|
|
|
|
item.VarietySum.ForwardSum.VarietyCode = item.VarietyCode;
|
|
ForwardList.Add(item.VarietySum.ForwardSum);
|
|
ForwardList.AddRange(item.UnderlyingRiskList.Select(m =>
|
|
{
|
|
m.ForwardRisk.UnderlyingCode = m.UnderlyingCode;
|
|
m.ForwardRisk.UnderlyingPrice = m.UnderlyingPrice?.ToString("F2");
|
|
return m.ForwardRisk;
|
|
}));
|
|
ForwardList.Add(emptyRiskModel);
|
|
|
|
item.VarietySum.SwapSum.VarietyCode = item.VarietyCode;
|
|
SwapList.Add(item.VarietySum.SwapSum);
|
|
SwapList.AddRange(item.UnderlyingRiskList.Select(m =>
|
|
{
|
|
m.SwapRisk.UnderlyingCode = m.UnderlyingCode;
|
|
m.SwapRisk.UnderlyingPrice = m.UnderlyingPrice?.ToString("F2");
|
|
return m.SwapRisk;
|
|
}));
|
|
SwapList.Add(emptyRiskModel);
|
|
}
|
|
|
|
var varb = new
|
|
{
|
|
PortfolioList,
|
|
report.Sum.PortfolioSum,
|
|
|
|
OtcList,
|
|
report.Sum.OtcSum,
|
|
|
|
ExOptionList,
|
|
report.Sum.ExOptionSum,
|
|
|
|
FuturesList,
|
|
report.Sum.FuturesSum,
|
|
|
|
ForwardList,
|
|
report.Sum.ForwardSum,
|
|
|
|
SwapList,
|
|
report.Sum.SwapSum,
|
|
|
|
report.ReportStart,
|
|
report.ReportEnd
|
|
};
|
|
|
|
using (var generator = Office.ExcelModule.ExcelGenerator
|
|
.UseTemplateGenerator(templateFileName).AddVariable(varb))
|
|
{
|
|
var wrap = generator.GetExcelWrapper();
|
|
|
|
generator.Generate();
|
|
|
|
for (var i = 1; i <= 6; i++)
|
|
{
|
|
var sheet = wrap.GetSheet(i);
|
|
var rowLoop = sheet.GetRowLoop();
|
|
for (var j = 0; j < 1000; j++)
|
|
{
|
|
var value = rowLoop.MoveNext().GetValue(1);
|
|
|
|
if (value == "####")
|
|
{
|
|
rowLoop.Current.ClearContents();
|
|
}
|
|
else if (value == "合计")
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
generator.SaveAs(ms);
|
|
return ms.ToArray();
|
|
}
|
|
}
|
|
|
|
//var modelDict = new Dictionary<string, object> {
|
|
// {"汇总", report}, {"场外期权", report}, {"场内期权", report}, {"标的交易", report}, {"远期", report}
|
|
//};
|
|
|
|
//Action<ExcelWorksheets> generateExcelCallback = (sheets) =>
|
|
//{
|
|
// foreach (var dict in modelDict)
|
|
// {
|
|
// var sheet = sheets[dict.Key];
|
|
// for (var i = 1; i <= 10000; i++)
|
|
// {
|
|
// if (sheet.GetValue(i, 1)?.ToString() == "合计" && sheet.GetValue(i + 1, 1)?.ToString() != "")
|
|
// {
|
|
// sheet.DeleteRow(i);
|
|
// i--;
|
|
// }
|
|
// else if (sheet.GetValue(i, 1)?.ToString() == "合计" && sheet.GetValue(i + 1, 1)?.ToString() == "")
|
|
// {
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
//};
|
|
|
|
//new ExcelTemplateGenerator().SetTemplateFile(sourceFileName)
|
|
// .SetTemplateData(modelDict).SetCallback(generateExcelCallback)
|
|
// .OutputToFile(result.PhysicalPath);
|
|
|
|
//return result;
|
|
}
|
|
|
|
|
|
public void GetPortfolioList<eodRisk, eodPnl>(RiskRequestModel reqModel, out RiskCollectReport riskCollectReport) where eodRisk : EodTradeRisk where eodPnl : EodPnl
|
|
{
|
|
riskCollectReport = new RiskCollectReport();
|
|
var report = SearchRiskExposureReportsV2<eodRisk, eodPnl>(reqModel);
|
|
report.ReportStart = (reqModel.ValueDateStart ?? reqModel.ValueDateEnd).ToString("yyyy-M-d");
|
|
report.ReportEnd = reqModel.ValueDateEnd.ToString("yyyy-M-d");
|
|
|
|
if (report.ReportModels == null || !report.ReportModels.Any())
|
|
{
|
|
throw new Exception("无导出数据!");//(请确保区间收盘是连续的,特别是最后日)
|
|
}
|
|
|
|
var PortfolioList = new List<EodRiskModel>();
|
|
foreach (var item in report.ReportModels)
|
|
{
|
|
item.VarietySum.PortfolioSum.VarietyCode = item.VarietyCode;
|
|
PortfolioList.Add(item.VarietySum.PortfolioSum);
|
|
PortfolioList.AddRange(item.UnderlyingRiskList.Select(m =>
|
|
{
|
|
m.PortfolioRisk.UnderlyingCode = m.UnderlyingCode;
|
|
m.PortfolioRisk.UnderlyingPrice = m.UnderlyingPrice?.ToString("F2");
|
|
return m.PortfolioRisk;
|
|
}));
|
|
}
|
|
|
|
riskCollectReport.PortfolioList = PortfolioList;
|
|
riskCollectReport.PortfolioSum = report.Sum.PortfolioSum;
|
|
riskCollectReport.ReportStart = report.ReportStart;
|
|
riskCollectReport.ReportEnd = report.ReportEnd;
|
|
}
|
|
/// <summary>
|
|
/// 获取取值日的场内期权风险指标
|
|
/// </summary>
|
|
private IEnumerable<EodPositionRisksDTO> CalculateExchangeListOptionRisks(DateTime settleDate, RiskRequestModel reqModel)
|
|
{
|
|
if (reqModel.ClientIds.Any(n => n > 0) || reqModel.TradeTypes.Any() && !reqModel.TradeTypes.Contains("场内期权"))
|
|
{
|
|
return Enumerable.Empty<EodPositionRisksDTO>();
|
|
}
|
|
|
|
var riskPredicate = PredicateBuilder.Create<EodTradeRisk>(t => t.ValueDate == settleDate && t.TradeId < 1);
|
|
var posPredicate = PredicateBuilder.Create<EodTradePosition>(t => t.ValueDate == settleDate && t.TradeId < 1 && t.TradeType == "场内期权");
|
|
|
|
Expression<Func<EodTradeRisk, bool>> pre1 = null;
|
|
Expression<Func<EodTradePosition, bool>> pre2 = null;
|
|
|
|
if (reqModel.UserAssets != null || reqModel.UserClients != null)
|
|
{
|
|
pre1 = PredicateBuilder.Create<EodTradeRisk>(t => reqModel.UserAssets.Contains(t.BookId) || reqModel.UserClients.Contains(t.ClientId));
|
|
pre2 = PredicateBuilder.Create<EodTradePosition>(t => reqModel.UserAssets.Contains(t.BookId) || reqModel.UserClients.Contains(t.ClientId));
|
|
}
|
|
|
|
if (pre1 != null)
|
|
{
|
|
riskPredicate = riskPredicate.And(pre1);
|
|
posPredicate = posPredicate.And(pre2);
|
|
}
|
|
|
|
if (reqModel.BookIds != null && reqModel.BookIds.Any(n => n > 0))
|
|
{
|
|
posPredicate = posPredicate.And(t => reqModel.BookIds.Contains(t.BookId));
|
|
}
|
|
|
|
var varietyIds = reqModel.VarietyIds != null && reqModel.VarietyIds.Any(n => n > 0) ? reqModel.VarietyIds : Enumerable.Empty<int>();
|
|
var underlyingIds = reqModel.UnderlyingIds != null && reqModel.UnderlyingIds.Any(n => n > 0) ? reqModel.UnderlyingIds : Enumerable.Empty<int>();
|
|
|
|
IQueryable<EodTradeRisk> riskQuery;
|
|
IQueryable<EodTradePosition> posQuery;
|
|
|
|
switch (reqModel.EodSettlePriceMode)
|
|
{
|
|
case "结算价":
|
|
riskQuery = DbContext.eod_trade_risk_hedgevol_s.Where(riskPredicate);
|
|
posQuery = DbContext.eod_trade_position_hedgevol_s.Where(posPredicate);
|
|
break;
|
|
default:
|
|
riskQuery = DbContext.eod_trade_risk_hedgevol.Where(riskPredicate);
|
|
posQuery = DbContext.eod_trade_position_hedgevol.Where(posPredicate);
|
|
break;
|
|
}
|
|
|
|
var query = from risk in riskQuery
|
|
join pos in posQuery on risk.HedgeUniqueCode equals pos.HedgeUniqueCode
|
|
join un in DbContext.underlying_manager on pos.UnderlyingCode equals un.UnderlyingCode
|
|
join ex in DbContext.exchange_list_option on pos.ExchangeOptionCode equals ex.ContractCode
|
|
where (!underlyingIds.Any() || underlyingIds.Contains(un.id))
|
|
&& (!varietyIds.Any() || varietyIds.Contains(un.UnderlyingTypeId))
|
|
select new EodPositionRisksDTO
|
|
{
|
|
id = -pos.id,
|
|
|
|
PV = pos.Pv,
|
|
RoundedPV = pos.RoundedPv,
|
|
PositionPnl = pos.PositionPnL,
|
|
RoundedPositionPnl = pos.RoundedPositionPnL,
|
|
|
|
Vega = risk.Vega,
|
|
Theta = risk.Theta,
|
|
Rho = risk.Rho,
|
|
Delta = risk.Delta,
|
|
Gamma = risk.Gamma,
|
|
DeltaCash = risk.DeltaCash,
|
|
GammaCash = risk.GammaCash,
|
|
VegaCash = risk.VegaCash,
|
|
Exposure = risk.CreditExposure,
|
|
CurrentVolatility = risk.Vol,
|
|
|
|
Notional = pos.Amount,
|
|
OriginalNotional = pos.Amount,
|
|
TradePrice = pos.Cost,
|
|
TradeSinglePrice = pos.Amount > 0 ? pos.Cost / pos.Amount : 0,
|
|
TradeType = pos.TradeType,
|
|
UnderlyingCode = pos.UnderlyingCode,
|
|
|
|
UnderlyingPrice = un.Price ?? 0,
|
|
UnderlyingId = un.id,
|
|
VarietyId = un.UnderlyingTypeId,
|
|
UnderlyingAssetName = un.UnderlyingName,
|
|
|
|
Margin = pos.Margin,
|
|
RealizedPnl = pos.TotalPnL - (double)pos.PositionPnL,
|
|
ExchangeOptionCode = pos.ExchangeOptionCode,
|
|
|
|
Strike = ex.Strike,
|
|
ExerciseDate = ex.MaturityDate,
|
|
OptionType = ex.OptionType,
|
|
TradeDate = ex.OpenDate
|
|
};
|
|
|
|
var datas = query.ToArray();
|
|
|
|
foreach (var data in datas)
|
|
{
|
|
data.RiskFreeRate = valuedateBLL.RiskFreeRate / 100;
|
|
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(data.UnderlyingCode);
|
|
|
|
if (um != null)
|
|
{
|
|
data.GammaLots = NumberHelper.Normalize(data.Gamma / um.ContractSize);
|
|
data.DeltaLots = NumberHelper.Normalize(data.Delta / um.ContractSize);
|
|
}
|
|
|
|
data.Rho *= 100;
|
|
data.TradeOriginalAmount = um != null ? data.OriginalNotional / um.CountRatio : data.OriginalNotional;
|
|
}
|
|
|
|
return datas;
|
|
}
|
|
|
|
private IEnumerable<EodPositionRisksDTO> CalculateExchangeListOptionRisks<eodRisk>(DateTime settleDate, RiskRequestModel reqModel) where eodRisk : EodTradeRisk
|
|
{
|
|
if (reqModel.ClientIds.Any(n => n > 0) || reqModel.TradeTypes.Any() && !reqModel.TradeTypes.Contains("场内期权"))
|
|
{
|
|
return Enumerable.Empty<EodPositionRisksDTO>();
|
|
}
|
|
|
|
var riskPredicate = PredicateBuilder.Create<EodTradeRisk>(t => t.ValueDate == settleDate && t.TradeId < 1);
|
|
var posPredicate = PredicateBuilder.Create<EodTradePosition>(t => t.ValueDate == settleDate && t.TradeId < 1 && t.TradeType == "场内期权");
|
|
|
|
Expression<Func<EodTradeRisk, bool>> pre1 = null;
|
|
Expression<Func<EodTradePosition, bool>> pre2 = null;
|
|
|
|
if (reqModel.UserAssets != null || reqModel.UserClients != null)
|
|
{
|
|
pre1 = PredicateBuilder.Create<EodTradeRisk>(t => reqModel.UserAssets.Contains(t.BookId) || reqModel.UserClients.Contains(t.ClientId));
|
|
pre2 = PredicateBuilder.Create<EodTradePosition>(t => reqModel.UserAssets.Contains(t.BookId) || reqModel.UserClients.Contains(t.ClientId));
|
|
}
|
|
|
|
if (pre1 != null)
|
|
{
|
|
riskPredicate = riskPredicate.And(pre1);
|
|
posPredicate = posPredicate.And(pre2);
|
|
}
|
|
|
|
if (reqModel.BookIds != null && reqModel.BookIds.Any(n => n > 0))
|
|
{
|
|
posPredicate = posPredicate.And(t => reqModel.BookIds.Contains(t.BookId));
|
|
}
|
|
|
|
var varietyIds = reqModel.VarietyIds != null && reqModel.VarietyIds.Any(n => n > 0) ? reqModel.VarietyIds : Enumerable.Empty<int>();
|
|
var underlyingIds = reqModel.UnderlyingIds != null && reqModel.UnderlyingIds.Any(n => n > 0) ? reqModel.UnderlyingIds : Enumerable.Empty<int>();
|
|
|
|
IQueryable<EodTradeRisk> riskQuery;
|
|
IQueryable<EodTradePosition> posQuery;
|
|
|
|
switch (reqModel.EodSettlePriceMode)
|
|
{
|
|
case "结算价":
|
|
riskQuery = DbContext.Set<eodRisk>().Where(riskPredicate);
|
|
posQuery = DbContext.Set<eodPosition>().Where(posPredicate);
|
|
break;
|
|
default:
|
|
riskQuery = DbContext.Set<eodRisk>().Where(riskPredicate);
|
|
posQuery = DbContext.Set<eodPosition>().Where(posPredicate);
|
|
break;
|
|
}
|
|
|
|
var query = from risk in riskQuery
|
|
join pos in posQuery on risk.HedgeUniqueCode equals pos.HedgeUniqueCode
|
|
join un in DbContext.underlying_manager on pos.UnderlyingCode equals un.UnderlyingCode
|
|
join ex in DbContext.exchange_list_option on pos.ExchangeOptionCode equals ex.ContractCode
|
|
where (!underlyingIds.Any() || underlyingIds.Contains(un.id))
|
|
&& (!varietyIds.Any() || varietyIds.Contains(un.UnderlyingTypeId))
|
|
select new EodPositionRisksDTO
|
|
{
|
|
id = -pos.id,
|
|
|
|
PV = pos.Pv,
|
|
RoundedPV = pos.RoundedPv,
|
|
PositionPnl = pos.PositionPnL,
|
|
RoundedPositionPnl = pos.RoundedPositionPnL,
|
|
|
|
Vega = risk.Vega,
|
|
Theta = risk.Theta,
|
|
Rho = risk.Rho,
|
|
Delta = risk.Delta,
|
|
Gamma = risk.Gamma,
|
|
DeltaCash = risk.DeltaCash,
|
|
GammaCash = risk.GammaCash,
|
|
VegaCash = risk.VegaCash,
|
|
Exposure = risk.CreditExposure,
|
|
CurrentVolatility = risk.Vol,
|
|
|
|
Notional = pos.Amount,
|
|
OriginalNotional = pos.Amount,
|
|
TradePrice = pos.Cost,
|
|
TradeSinglePrice = pos.Amount > 0 ? pos.Cost / pos.Amount : 0,
|
|
TradeType = pos.TradeType,
|
|
UnderlyingCode = pos.UnderlyingCode,
|
|
|
|
UnderlyingPrice = un.Price ?? 0,
|
|
UnderlyingId = un.id,
|
|
VarietyId = un.UnderlyingTypeId,
|
|
UnderlyingAssetName = un.UnderlyingName,
|
|
|
|
Margin = pos.Margin,
|
|
RealizedPnl = pos.TotalPnL - (double)pos.PositionPnL,
|
|
ExchangeOptionCode = pos.ExchangeOptionCode,
|
|
|
|
Strike = ex.Strike,
|
|
ExerciseDate = ex.MaturityDate,
|
|
OptionType = ex.OptionType,
|
|
TradeDate = ex.OpenDate
|
|
};
|
|
|
|
var datas = query.ToArray();
|
|
|
|
foreach (var data in datas)
|
|
{
|
|
data.RiskFreeRate = valuedateBLL.RiskFreeRate / 100;
|
|
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(data.UnderlyingCode);
|
|
|
|
if (um != null)
|
|
{
|
|
data.GammaLots = NumberHelper.Normalize(data.Gamma / um.ContractSize);
|
|
data.DeltaLots = NumberHelper.Normalize(data.Delta / um.ContractSize);
|
|
}
|
|
|
|
data.Rho *= 100;
|
|
data.TradeOriginalAmount = um != null ? data.OriginalNotional / um.CountRatio : data.OriginalNotional;
|
|
}
|
|
|
|
return datas;
|
|
}
|
|
}
|
|
}
|