using Qdp.Pricing.Base.Utilities; using YLErp.Abstract.DataProviders; using YLErp.BLL; using YLErp.BLL.Calculation; using YLErp.Commons; using YLErp.DBModels.Enums; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.Modules.TradeDalModule; using YLErp.Office.ExcelModule; using YLErp.QdpModule; namespace YLErp.Modules.EodModule { public class eod_varReq { /// /// 估值日期 /// public DateTime ValueDate { get; set; } /// /// 估值范围结束日期 /// public DateTime? EndValueDate { get; set; } public int VaRType { get; set; } public double PvPercent { get; set; } public string UnderlyingIds { get; set; } public int? AssetId { get; set; } public string TradeType { get; set; } public bool IsNeedExport { get; set; } public int DaysCount { get; set; } } public class eod_varResult { public string UnderlyingCode { get; set; } public string AssetName { get; set; } public double RealPv { get; set; } public double CalcPv { get; set; } public double WinLoss { get; set; } public double WinLossPercent { get; set; } } /// /// /// public class EodVaRService : YLBaseService { public EodVaRService(OptUserInfo userInfo) : base(userInfo) { } public EodVaRService(YLBaseService baseService) : base(baseService) { } public void SaveEodVaR(eod_var record) { if (record.TradeType == null) { record.TradeType = ""; } var r = DbContext.eod_var.FirstOrDefault(x => x.ValueDate == record.ValueDate && x.VaRType == record.VaRType && x.UnderlyingCode == record.UnderlyingCode && x.TradeType == record.TradeType && x.AssetId == record.AssetId); if (r != null) { r.ValueDate = record.ValueDate; r.PvObject = record.PvObject; r.VaRValue = record.VaRValue; r.RealPv = record.RealPv; r.OptId = record.OptId; r.OptName = record.OptName; r.OptDate = record.OptDate; } else { DbContext.eod_var.Add(record); } DbContext.SaveChanges(); } public void CalcEodVaR(eod_varReq req) { //目前修改dayCount是覆盖之前数据的,不再另存 8/4 if (req.TradeType == null) { req.TradeType = ""; } var PvList = new List(); var query = DbContext.eod_trade.Where(t => t.ValueDate == req.ValueDate); if (!string.IsNullOrWhiteSpace(req.TradeType)) { var tradeType = GlobalDicionary.SupportTradeTypes.Where(O => O != "收益互换" && O != "远期").ToList(); if (req.TradeType == "场外") { query = query.Where(O => tradeType.Contains(O.TradeType)); } else if (req.TradeType == "互换") { query = query.Where(O => O.TradeType == "收益互换"); } else if (req.TradeType == "远期") { query = query.Where(O => O.TradeType == "远期"); } } var eodTradeList = query.ToList(); //过滤只计算支持的交易 var tradeList = eodTradeList.Where(t => t.trade != null && t.trade.TradeType != "自定义交易" && t.trade.TradeType != "结构化交易" && GlobalDicionary.SupportTradeTypes.Contains(t.trade.TradeType) && !ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus)).Select(t => t.trade).ToList(); var trades = DbContext.eod_trade_position .Where(t => t.ValueDate == req.ValueDate && ConsTrade.TradeTypesForHedge.Contains(t.TradeType)) .Select(et => new tradeDto { id = et.TradeId, ClientId = et.ClientId, AssetId = et.BookId, TradeType = et.TradeType, UnderlyingId = et.UnderlyingId, UnderlyingCode = et.UnderlyingCode, BuySell = et.PositionType == "long" ? "买入" : "卖出", IsMoneynessOption = "否", Notional = et.Amount, ExchangeOptionCode = et.ExchangeOptionCode }).ToList(); //var attachTrades = DbContext.trade.Where(t => trades.Keys.Contains(t.id) && t.TradeType != "自定义交易" && GlobalDicionary.SupportTradeTypes.Contains(t.TradeType) && ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus)).ToList(); if (string.IsNullOrWhiteSpace(req.TradeType)) { tradeList.AddRange(trades); } if (req.TradeType == "场内") { tradeList = new List(); trades = trades.Where(o => o.TradeType == "场内期权" || o.TradeType == "股票").ToList(); tradeList.AddRange(trades); } if (req.TradeType == "商品") { tradeList = new List(); trades = trades.Where(o => o.TradeType == "商品期货" || o.TradeType == "商品现货").ToList(); tradeList.AddRange(trades); } if (req.AssetId != null && req.AssetId != 0) { tradeList = tradeList.Where(o => req.AssetId == o.AssetId).ToList(); } if (!tradeList.Any()) { throw new Exception("该交易日未收盘或未找到持仓交易,无法算出VaR值"); } foreach (var td in tradeList) { if (td.TradeType == "场内期权") { var exchangeOption = DataCacheProvider.GetExchangeListOptionDataSource().GetData(td.ExchangeOptionCode); if (exchangeOption != null) { td.ExerciseDate = exchangeOption.MaturityDate; td.ExerciseMode = exchangeOption.ExerciseMode; td.OptionType = exchangeOption.OptionType; td.Strike = exchangeOption.Strike; td.TradeDate = td.StartDate = exchangeOption.OpenDate; } } } tradeBLL.SetFieldsByTradeType(tradeList); new TradeDalService(this).SetSubTradeList(tradeList); var underlyingDics = tradeList.Select(t => new { t.UnderlyingId, t.UnderlyingCode }).ToHashSet(); var underlyingIds = underlyingDics.Select(o => o.UnderlyingId); var underlyingCodes = underlyingDics.Select(o => o.UnderlyingCode); //合成价差期权对应的组合标的 //var tradeListAssociation = tradeList.Where(x => x.TradeType == "合成价差期权"); //var underlyingIdsAssociation = tradeListAssociation.Select(t => t.UnderlyingId).ToHashSet(); //var underlyingCodesAssociation = tradeListAssociation.Select(t => t.UnderlyingCode).ToHashSet(); var syntheticUnderlyings = DbContext.synthetic_underlying.Where(x => underlyingCodes.Contains(x.Name)).ToList(); var underlyingCodesAssociation = syntheticUnderlyings.Select(t => t.Name); var underlyingIdsAssociation = underlyingDics.Where(t => underlyingCodesAssociation.Contains(t.UnderlyingCode)).Select(t => t.UnderlyingId).ToHashSet(); var underlyingIdsAssociationChildren = syntheticUnderlyings.Where(x => x.UnderlyingId1 != null).Select(x => x.UnderlyingId1).ToList(); underlyingIdsAssociationChildren.AddRange(syntheticUnderlyings.Where(x => x.UnderlyingId2 != null).Select(x => x.UnderlyingId2)); underlyingIdsAssociationChildren.AddRange(syntheticUnderlyings.Where(x => x.UnderlyingId3 != null).Select(x => x.UnderlyingId3)); underlyingIdsAssociationChildren.AddRange(syntheticUnderlyings.Where(x => x.UnderlyingId4 != null).Select(x => x.UnderlyingId4)); underlyingIdsAssociationChildren = underlyingIdsAssociationChildren.Distinct().ToList(); var useClosePrice = TradeCalcHelper.UseClosePrice(); var teodPriceProvider = new EodPriceProvider(req.ValueDate).Initialize(); var priceList = teodPriceProvider.GetEodPriceList(); var tdPriceProvider = teodPriceProvider.GetPriceProvider(useClosePrice ? SettlementTypeEnum.ClosePrice : SettlementTypeEnum.SettlePrice); //当日持仓交易的收盘价 var dayEodPrices = priceList.Where(x => underlyingIds.Contains(x.UnderlyingId)).ToList(); //当日持仓合成价差期权交易组合标的对应的子标的的收盘价 var dayEodPricesAssociationChildren = priceList.Where(x => underlyingIdsAssociationChildren.Contains(x.UnderlyingId)).ToList(); //试算的每一个244天 var ValueDateCalc = req.ValueDate; IPriceProvider dayEodPricesCalc = null; IPriceProvider dayEodPricesCalcBefore = null; var underlyingPvs = new Dictionary>(); var tradePvs = new Dictionary>(); for (var i = 0; i < req.DaysCount; i++) { #region 试算的每一天的标的相应的价格 //试算交易日的前一工作日 var ValueDateCalcBefore = valuedateBLL.GetNonHolidayDefore(ValueDateCalc.AddDays(-1)); dayEodPricesCalc = dayEodPricesCalcBefore ?? tdPriceProvider; dayEodPricesCalcBefore = new EodPriceProvider(ValueDateCalcBefore).GetPriceProvider(SettlementTypeEnum.ClosePrice); var calcTrades = tradeList; var eodPrices = new ManualPriceProvider(); if (dayEodPrices != null && dayEodPrices.Any()) { dayEodPrices.ForEach(t => { //组合标的的模拟价格 if (underlyingIdsAssociation.Contains(t.UnderlyingId)) { var syntheticUnderlying = syntheticUnderlyings.FirstOrDefault(x => x.Name == t.UnderlyingCode); if (syntheticUnderlying == null) { throw new Exception($"组合标的{t.UnderlyingCode}不存在,计算失败"); } double price1 = 0, price2 = 0, price3 = 0, price4 = 0; if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode1) && tdPriceProvider.TryGetPrice(syntheticUnderlying.UnderlyingCode1, out var price)) { price1 = GetCalcUnderlyingPrice(syntheticUnderlying.UnderlyingCode1, price, ValueDateCalcBefore, dayEodPricesCalc, dayEodPricesCalcBefore); } if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode2) && tdPriceProvider.TryGetPrice(syntheticUnderlying.UnderlyingCode2, out price)) { price2 = GetCalcUnderlyingPrice(syntheticUnderlying.UnderlyingCode2, price, ValueDateCalcBefore, dayEodPricesCalc, dayEodPricesCalcBefore); } if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode3) && tdPriceProvider.TryGetPrice(syntheticUnderlying.UnderlyingCode3, out price)) { price3 = GetCalcUnderlyingPrice(syntheticUnderlying.UnderlyingCode3, price, ValueDateCalcBefore, dayEodPricesCalc, dayEodPricesCalcBefore); } if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode4) && tdPriceProvider.TryGetPrice(syntheticUnderlying.UnderlyingCode4, out price)) { price4 = GetCalcUnderlyingPrice(syntheticUnderlying.UnderlyingCode4, price, ValueDateCalcBefore, dayEodPricesCalc, dayEodPricesCalcBefore); } price = price1 * (syntheticUnderlying.Coefficient1 ?? 0) + price2 * (syntheticUnderlying.Coefficient2 ?? 0) + price3 * (syntheticUnderlying.Coefficient3 ?? 0) + price4 * (syntheticUnderlying.Coefficient4 ?? 0) + (syntheticUnderlying.Constant ?? 0); if (price != 0) { eodPrices.SetPrice(t.UnderlyingCode, price); } else { calcTrades = calcTrades.Where(o => o.UnderlyingCode != t.UnderlyingCode).ToList(); } } //普通标的的模拟价格 else { var price = GetCalcUnderlyingPrice(t.UnderlyingCode, useClosePrice ? t.ClosePrice : t.SettlePrice, ValueDateCalcBefore, dayEodPricesCalc, dayEodPricesCalcBefore); if (price != 0) { eodPrices.SetPrice(t.UnderlyingCode, price); } else { calcTrades = calcTrades.Where(o => o.UnderlyingCode != t.UnderlyingCode).ToList(); } } }); } #endregion var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( //根据模拟价格,对下一个交易日进行模拟试算 valueDate: QdpCalendarHelper.GetNonHoliday(req.ValueDate.AddDays(1)), tradeList: calcTrades, calcScenario: Enums.CalcScenarioEnum.EodSettlement, priceProvider: eodPrices, pricingRequest: QdpPricingRequest.PV_ONLY, settlementType: useClosePrice ? SettlementTypeEnum.ClosePrice : SettlementTypeEnum.SettlePrice, isUseTradeVol: PS.Config.IsTradeVol, preciseTimeMode: false); foreach (var underlyingPv in underlyingPvs) { underlyingPv.Value.Add(0); } foreach (var result in tradeRiskResult.Results) { foreach (var underlying in result.Underlyings) { if (underlying == null) { continue; } if (underlyingPvs.ContainsKey(underlying.UnderlyingCode)) { var index = underlyingPvs[underlying.UnderlyingCode].Count() - 1; underlyingPvs[underlying.UnderlyingCode][index] = underlyingPvs[underlying.UnderlyingCode].Last() + (double.IsNaN(result.ValueResult.Pv) ? 0 : result.ValueResult.Pv); } else { underlyingPvs.Add(underlying.UnderlyingCode, new List()); underlyingPvs[underlying.UnderlyingCode].Add(double.IsNaN(result.ValueResult.Pv) ? 0 : result.ValueResult.Pv); } } if (req.IsNeedExport) { var t = result.Trade; var postionside = t.BuySell == "买入" ? "long" : "short"; var code = !ConsTrade.TradeTypesForHedge.Contains(t.TradeType) ? t.TradeNumber : HedgePnlCalc.GetHedgeUniqueCode(t.AssetId, t.TradeType, t.BuySell, t.UnderlyingCode, t.ExchangeOptionCode); if (!tradePvs.ContainsKey(code)) { tradePvs.Add(code, new List() { result.ValueResult.Pv }); } else { tradePvs[code].Add(result.ValueResult.Pv); } } } PvList.Add(tradeRiskResult.Results.Sum(x => double.IsNaN(x.ValueResult.Pv) ? 0 : x.ValueResult.Pv)); ValueDateCalc = ValueDateCalcBefore; } var tradeRiskResultToday = CalculatorHelper.CalculateRisksForTrades( valueDate: req.ValueDate, tradeList: tradeList, calcScenario: Enums.CalcScenarioEnum.EodSettlement, priceProvider: tdPriceProvider, pricingRequest: QdpPricingRequest.PV_ONLY, settlementType: useClosePrice ? SettlementTypeEnum.ClosePrice : SettlementTypeEnum.SettlePrice, isUseTradeVol: PS.Config.IsTradeVol, preciseTimeMode: false); if (req.IsNeedExport) { ExportTradePvs(tradeRiskResultToday, tdPriceProvider, req.ValueDate, tradePvs); } var realPv = tradeRiskResultToday.Results.Sum(x => double.IsNaN(x.ValueResult.Pv) ? 0 : x.ValueResult.Pv); var underlyingRealPvs = new Dictionary(); foreach (var result in tradeRiskResultToday.Results) { foreach (var underlying in result.Underlyings) { if (underlying == null) { continue; } if (underlyingRealPvs.ContainsKey(underlying.UnderlyingCode)) { underlyingRealPvs[underlying.UnderlyingCode] += (double.IsNaN(result.ValueResult.Pv) ? 0 : result.ValueResult.Pv); } else { underlyingRealPvs.Add(underlying.UnderlyingCode, 0); underlyingRealPvs[underlying.UnderlyingCode] = (double.IsNaN(result.ValueResult.Pv) ? 0 : result.ValueResult.Pv); } } } var record = new eod_var() { ValueDate = req.ValueDate, PvObject = string.Join(",", PvList), RealPv = realPv, VaRType = (int)EnumVaRType.HistoricalSimulation, OptName = UserName, OptId = UserId, OptDate = DateTime.Now, UnderlyingCode = "", TradeType = req.TradeType, AssetId = req.AssetId ?? 0 }; SaveEodVaR(record); foreach (var underlyingRealPv in underlyingRealPvs) { if (underlyingPvs.TryGetValue(underlyingRealPv.Key, out var underlyingPv)) { record = new eod_var() { ValueDate = req.ValueDate, PvObject = string.Join(",", underlyingPv), RealPv = underlyingRealPv.Value, VaRType = (int)EnumVaRType.HistoricalSimulation, OptName = UserName, OptId = UserId, OptDate = DateTime.Now, UnderlyingCode = underlyingRealPv.Key, TradeType = req.TradeType, AssetId = req.AssetId ?? 0 }; SaveEodVaR(record); } } } public void CalcSimpleDeltaGammaVaR(eod_varReq req) { //从日终风险表获得DeltaCash和GammaCash,并按照标的资产合并 var eodRisks = DbContext.eod_trade_risk.AsNoTracking().Where(r => r.ValueDate == req.ValueDate).ToList(); if (req.AssetId != null && req.AssetId != 0) { var tradeIds = DbContext.trade.Where(o => ConsTrade.PositionTradeStatusList.Contains(o.TradeStatus) && o.AssetId == req.AssetId).Select(o => o.id); eodRisks = eodRisks.Where(o => tradeIds.Contains(o.TradeId)).ToList(); } var totalPv = (double)eodRisks.Sum(r => r.Pv); var underlyingCodes = eodRisks.Where(r => r.Exposure != null).Select(r => r.Exposure).Distinct().ToList(); var deltaCashDict = underlyingCodes.ToDictionary(c => c, x => 0.0); var gammaCashDict = underlyingCodes.ToDictionary(c => c, x => 0.0); var thetaDict = underlyingCodes.ToDictionary(c => c, x => 0.0); var pvDict = underlyingCodes.ToDictionary(c => c, x => 0.0); foreach (var risk in eodRisks) { if (risk.Exposure == null) { continue; } deltaCashDict[risk.Exposure] += risk.DeltaCash; gammaCashDict[risk.Exposure] += risk.GammaCash; thetaDict[risk.Exposure] += (double)risk.Theta; //underlying totalPv的计算 pvDict[risk.Exposure] += (double)risk.Pv; } //获取各标的过去30个交易日的历史波动率 var volDict = underlyingCodes.ToDictionary(c => c, x => 0.0); var underlyings = DbContext.underlying_manager.AsNoTracking().Where(u => underlyingCodes.Contains(u.UnderlyingCode)).ToList(); var volCalculator = new VolCaculator(); var daysInYear = (int)valuedateBLL.TradeDayCount.ToDayCountImpl().DaysInYear(); foreach (var underlying in underlyings) { var priceDict = volCalculator.GetHistoricalPrices(underlying, req.ValueDate, 30 + 1); var prices = priceDict.Select(f => f.Value).ToList(); var lnDiffs = volCalculator.GetLnDiffList(prices); var vol = volCalculator.GetVolFromUnderlyingLogDiffs(lnDiffs, daysInYear); volDict[underlying.UnderlyingCode] = vol; } //计算各标的资产的VaR var varDict = new Dictionary(); var sqrtT = Math.Sqrt(daysInYear); foreach (var code in underlyingCodes) { if (gammaCashDict[code] < 0) { if (double.IsNaN(volDict[code])) { volDict[code] = 0; } var priceChange = 3.0 * volDict[code] / sqrtT; varDict[code] = -(Math.Abs(deltaCashDict[code] * priceChange) + 0.5 * gammaCashDict[code] * priceChange * priceChange); } else { varDict[code] = thetaDict[code]; } } var totalVar = varDict.Values.Sum(); foreach (var code in underlyingCodes) { var value = new eod_var() { ValueDate = req.ValueDate, UnderlyingCode = code, RealPv = pvDict[code], VaRType = (int)EnumVaRType.SimpleDeltaGamma, VaRValue = varDict[code], OptName = UserName, OptId = UserId, OptDate = DateTime.Now, TradeType = "", AssetId = req.AssetId ?? 0 }; SaveEodVaR(value); } var record = new eod_var() { ValueDate = req.ValueDate, UnderlyingCode = "", RealPv = totalPv, VaRType = (int)EnumVaRType.SimpleDeltaGamma, VaRValue = totalVar, OptName = UserName, OptId = UserId, OptDate = DateTime.Now, TradeType = "", AssetId = req.AssetId ?? 0 }; SaveEodVaR(record); } /// /// 根据模拟交易日的标的变化率,试算出一个标的价格 /// private double GetCalcUnderlyingPrice(string underlyingCode, double? settlePrice, DateTime valueDateCalcBefore, IPriceProvider dayEodPricesCalc, IPriceProvider dayEodPricesCalcBefore) { double price = 0; var um = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); if (dayEodPricesCalc.TryGetPrice(underlyingCode, out var dayEodPriceCalc) && dayEodPricesCalcBefore.TryGetPrice(underlyingCode, out var dayEodPriceCalcBefore)) { if (dayEodPriceCalcBefore > 0) { price = (settlePrice ?? 0.0) * dayEodPriceCalc / dayEodPriceCalcBefore; } else { throw new ServiceException($"标的{underlyingCode}在交易日{valueDateCalcBefore:yyyy-MM-dd}的标的结算价不合法,试算失败"); } } else if (um.UnderlyingInstrumentType == "Stock") { if (!dayEodPricesCalc.TryGetPrice(underlyingCode, out dayEodPriceCalc)) { return 0; } else { //取不到前一天的,就取那天的价格 return dayEodPriceCalc; } } else//标的不存在收盘价时,用主标的合约的变化率来计算 { var underlyingCodeArray = underlyingCode.TakeWhile(x => char.IsLetter(x)).ToArray(); var mainUnderlyingCode = new string(underlyingCodeArray) + "00"; if (!dayEodPricesCalc.TryGetPrice(mainUnderlyingCode, out dayEodPriceCalc)) { return 0; } else if (!dayEodPricesCalcBefore.TryGetPrice(mainUnderlyingCode, out dayEodPriceCalcBefore)) { //取不到前一天的,就取那天的价格 return dayEodPriceCalc; } if (dayEodPriceCalcBefore > 0) { price = (settlePrice ?? 0.0) * dayEodPriceCalc / dayEodPriceCalcBefore; } else { throw new ServiceException($"标的{underlyingCode}对应的主标的合约{mainUnderlyingCode}在交易日{valueDateCalcBefore:yyyy-MM-dd}的标的结算价不合法,试算失败"); } } return price; } private void ExportTradePvs(TradeRiskResult resultToday, IPriceProvider priceProvider, DateTime date, Dictionary> tradePvs) { var list = resultToday.Results; var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/EodVar中间数据导出.xlsx"); var dicList = new List>(); foreach (var result in list) { var t = result.Trade; var postionside = t.BuySell == "买入" ? "long" : "short"; var code = t.TradeNumber ?? HedgePnlCalc.GetHedgeUniqueCode(t.AssetId, t.TradeType, t.BuySell, t.UnderlyingCode, t.ExchangeOptionCode); var dic = new Dictionary(); priceProvider.TryGetPrice(result.Trade.UnderlyingCode, out var underlyingPrice); dic["TradeNumber"] = code; dic["UnderlyingCode"] = result.Trade.UnderlyingCode; dic["UnderlyingPrice"] = underlyingPrice.OtcFormatMoney(); dic["Vol"] = result.ValueResult.Vol.OtcFormatPercent(); dic["RealPv"] = result.ValueResult.Pv.OtcFormatMoney(); dic["Pvs"] = string.Join(",", tradePvs[code]); dicList.Add(dic); } var list2 = dicList.Select(n => new ExpandoDictionary(n)).ToArray(); var bytes = ExcelGenerator.UseTemplateGenerator(templateFile).AddVariable(new { list = list2 }).GenerateBytes(); var dicPath = OtcAppContext.MapPath(@"\App_Docs\Temp"); Directory.CreateDirectory(dicPath); var xlsxFilePath = Path.Combine(dicPath, $"EodVar中间数据{date:yyyyMMdd}.xlsx"); File.WriteAllBytes(xlsxFilePath, bytes); } public List GetEodVaR(eod_varReq req) { if (req.TradeType == null) { req.TradeType = ""; } //从js里移过来的逻辑; req.PvPercent = 1 - req.PvPercent; req.AssetId = req.AssetId == null ? 0 : req.AssetId; var eodVaRs = DbContext.eod_var.Where(x => x.ValueDate == req.ValueDate && x.VaRType == req.VaRType && x.TradeType == req.TradeType && x.AssetId == req.AssetId); List underlyingCodes = new List(); if (!string.IsNullOrWhiteSpace(req.UnderlyingIds)) { var underlyingIds = req.UnderlyingIds.Split(','); foreach (var id in underlyingIds) { UnderlyingDataProvider _umProvider = new UnderlyingDataProvider(); var um = _umProvider.GetUnderlying(int.Parse(id)); underlyingCodes.Add(um.UnderlyingCode); } eodVaRs = eodVaRs.Where(o => underlyingCodes.Contains(o.UnderlyingCode)); } if (eodVaRs == null || eodVaRs.Count() < 1) { var service = new EodVaRService(OptUser); if (req.EndValueDate == null || req.EndValueDate.Value == req.ValueDate) { service.CalcEodVaR(req); } else { var dayCount = (req.EndValueDate.Value - req.ValueDate).TotalDays; for (var i = 0; i <= dayCount; i++) { if (!QdpModule.QdpCalendarHelper.IsHoliday(req.ValueDate)) { service.CalcEodVaR(req); } } } eodVaRs = DbContext.eod_var.Where(x => x.ValueDate == req.ValueDate && x.VaRType == req.VaRType && x.TradeType == req.TradeType && x.AssetId == req.AssetId); if (!string.IsNullOrWhiteSpace(req.UnderlyingIds)) { eodVaRs = eodVaRs.Where(o => underlyingCodes.Contains(o.UnderlyingCode)); } } List results = new List(); double calcPv = 0; var totalVaR = eodVaRs.FirstOrDefault(o => o.UnderlyingCode == null || o.UnderlyingCode == ""); eodVaRs = eodVaRs.Where(o => o.UnderlyingCode != null && o.UnderlyingCode != ""); if (underlyingCodes != null && underlyingCodes.Count > 0) { foreach (var eodVaR in eodVaRs) { var AssetName = assetunitBLL.GetAllAssetUnitModel().FirstOrDefault(o => o.id == eodVaR.AssetId)?.Name; AssetName = string.IsNullOrEmpty(AssetName) ? "-- 总计 --" : AssetName; if (req.VaRType == (int)EnumVaRType.HistoricalSimulation) { var pvList = eodVaR.PvObject.Split(',').Select(x => double.TryParse(x, out var temp) ? temp : 0).OrderBy(x => x).ToArray(); var index = (int)Math.Floor(pvList.Length * req.PvPercent) - 1; if (index < 0) { index = 0; } calcPv = pvList[index]; } else { calcPv = eodVaR.VaRValue ?? 0; } var tempResult = new eod_varResult() { UnderlyingCode = eodVaR.UnderlyingCode, AssetName = AssetName, RealPv = eodVaR.RealPv ?? 0, CalcPv = calcPv, WinLoss = calcPv - (eodVaR.RealPv ?? 0), WinLossPercent = (eodVaR.RealPv ?? 0) == 0 ? 0 : (calcPv - eodVaR.RealPv.Value) / Math.Abs(eodVaR.RealPv.Value) }; results.Add(tempResult); } } if (totalVaR != null) { var AssetName = assetunitBLL.GetAllAssetUnitModel().FirstOrDefault(o => o.id == totalVaR.AssetId)?.Name; AssetName = string.IsNullOrEmpty(AssetName) ? "-- 总计 --" : AssetName; if (req.VaRType == (int)EnumVaRType.HistoricalSimulation) { var pvList = totalVaR.PvObject.Split(',').Select(x => double.TryParse(x, out var temp) ? temp : 0).OrderBy(x => x).ToArray(); var index = (int)Math.Floor(pvList.Count() * req.PvPercent) - 1; if (index < 0) { index = 0; } calcPv = pvList[index]; } else { calcPv = totalVaR.VaRValue ?? 0; } results.Add(new eod_varResult() { UnderlyingCode = "-- 总计 --", AssetName = AssetName, RealPv = totalVaR.RealPv ?? 0, CalcPv = calcPv, WinLoss = calcPv - (totalVaR.RealPv ?? 0), WinLossPercent = (totalVaR.RealPv ?? 0) == 0 ? 0 : (calcPv - totalVaR.RealPv.Value) / Math.Abs(totalVaR.RealPv.Value) }); return results; } else { return results; } } } }