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

738 lines
34 KiB
C#

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
{
/// <summary>
/// 估值日期
/// </summary>
public DateTime ValueDate { get; set; }
/// <summary>
/// 估值范围结束日期
/// </summary>
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; }
}
/// <summary>
///
/// </summary>
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<double>();
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<trade>();
trades = trades.Where(o => o.TradeType == "场内期权" || o.TradeType == "股票").ToList();
tradeList.AddRange(trades);
}
if (req.TradeType == "商品")
{
tradeList = new List<trade>();
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<string, List<double>>();
var tradePvs = new Dictionary<string, List<double>>();
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<double>());
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<double>() { 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<string, double>();
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<string, double>();
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);
}
/// <summary>
/// 根据模拟交易日的标的变化率,试算出一个标的价格
/// </summary>
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<string, List<double>> tradePvs)
{
var list = resultToday.Results;
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/EodVar中间数据导出.xlsx");
var dicList = new List<Dictionary<string, string>>();
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<string, string>();
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<string, string>(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<eod_varResult> 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<string> underlyingCodes = new List<string>();
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<eod_varResult> results = new List<eod_varResult>();
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;
}
}
}
}