using BaseOUDAL; using Qdp.Pricing.Base.Implementations; using Qdp.Pricing.Library.Equity.Engines.Analytical; using YLErp.BLL; using YLErp.Model; using YLErp.QdpModule; namespace YLErp.Modules.VolatilityModule { /// /// 波动率处理服务 /// public class VolatilityService : YLBaseService { public VolatilityService(OptUserInfo userInfo) : base(userInfo) { } public double GetTradeVol(trade trade, DateTime date) { TradeVolatility tradeVol = null; using (YLContext ylDb = new YLContext()) { tradeVol = ylDb.TradeVolatility.Where(n => n.TradeId == trade.id && n.ValueDate <= date) .OrderByDescending(O => O.ValueDate).FirstOrDefault(); } return GetTradeVol(trade, tradeVol, date); } public void GetTradeVol(List trades, DateTime date) { Dictionary volDic = new Dictionary(); List ids = trades.Where(t => !ConsTrade.TradeTypesForHedge.Contains(t.TradeType) && t.StartDate <= date).Select(O => O.id).ToList(); using (YLContext ylDb = new YLContext()) { var tempQuery = DbContext.TradeVolatility.Where(O => O.ValueDate <= date && ids.Contains(O.TradeId)); if (tempQuery.Any()) { var groupQuery = tempQuery.GroupBy(O => O.TradeId).Select(n => new { TradeId = n.Key, ValueDate = n.Max(m => m.ValueDate) }); var query = from a in DbContext.TradeVolatility join b in groupQuery on new { a.TradeId, a.ValueDate } equals new { b.TradeId, b.ValueDate } select a; volDic = query.ToDictionary(K => K.TradeId); } } foreach (var t in trades) { if (t.StartDate > date || ConsTrade.TradeTypesForHedge.Contains(t.TradeType)) { continue; } volDic.TryGetValue(t.id, out var tradeVol); t.Vol = GetTradeVol(t, tradeVol, date); } } private double GetTradeVol(trade trade, TradeVolatility tradeVol, DateTime date) { var daycountMode = PS.Config.ErpElement.SmoothingDaycountMode == Configuration.Enums.SmoothingDaycountMode.CalendarDay ? Qdp.Pricing.Base.Enums.DayCountMode.CalendarDay : Qdp.Pricing.Base.Enums.DayCountMode.TradingDay; if (tradeVol == null) { try { return AnalyticalOptionTradeVolInterp.tradeVolLinearInterp( new Qdp.Foundation.Implementations.Date(date), trade.TradeOpenVolatility ?? 0, trade.TradeCloseVolatility ?? 0, new Qdp.Foundation.Implementations.Date(trade.StartDate ?? DateTime.Today), new Qdp.Foundation.Implementations.Date(trade.ExerciseDate ?? DateTime.Today), trade.NumOfSmoothingDays ?? 0, daycountMode, CalendarImpl.Get("chn")); } catch { return double.NaN; } } else { return AnalyticalOptionTradeVolInterp.tradeVolLinearInterp( new Qdp.Foundation.Implementations.Date(date), tradeVol.TradePositionVolatility ?? 0, tradeVol.TradeCloseVolatility ?? 0, new Qdp.Foundation.Implementations.Date(tradeVol.ValueDate), new Qdp.Foundation.Implementations.Date(trade.ExerciseDate ?? DateTime.Today), tradeVol.NumOfSmoothingDays ?? 0, daycountMode, CalendarImpl.Get("chn"), includeStartDate: tradeVol.IsFromTradeAdd); } } /// /// 从数据库中查询波动率信息(此处的userGroup参数允许为NULL) private IQueryable _getVolQuery(DateTime date, IEnumerable codes, IEnumerable volTypes = null, string userGroup = null) { codes = codes.ToHashSet(); if (volTypes == null) { volTypes = DbContext.volatility.Select(O => O.VolType).GroupBy(O => O).Select(O => O.Key).ToList(); } var queryGroup = (from vol in DbContext.volatility where vol.QuotationDate <= date && codes.Contains(vol.ContractCode) && (userGroup == null || vol.UserGroup == userGroup) && volTypes.Contains(vol.VolType) group vol by new { vol.QuotationDate, vol.ContractCode, vol.UserGroup, vol.VolType } into grp select grp.Key); var queryKey = queryGroup.GroupBy(O => new { O.ContractCode, O.UserGroup, O.VolType }).Select(O => new { O.Key.ContractCode, O.Key.UserGroup, O.Key.VolType, QuotationDate = O.Max(M => M.QuotationDate) }); return from vol in DbContext.volatility.AsNoTracking() join dict in queryKey on new { vol.QuotationDate, vol.ContractCode, vol.UserGroup, vol.VolType } equals new { dict.QuotationDate, dict.ContractCode, dict.UserGroup, dict.VolType } select vol; } /// /// 从数据库中查询波动率信息(此处的userGroup参数允许为NULL) private IQueryable _getVolQuery(DateTime startDate, DateTime endDate, IEnumerable codes, IEnumerable volTypes = null, string userGroup = null) { codes = codes.ToHashSet(); if (volTypes == null) { volTypes = DbContext.volatility.Select(O => O.VolType).GroupBy(O => O).Select(O => O.Key).ToList(); } var query = from vol in DbContext.volatility.AsNoTracking() where vol.QuotationDate >= startDate && vol.QuotationDate <= endDate && codes.Contains(vol.ContractCode) && (userGroup == null || vol.UserGroup == userGroup) && volTypes.Contains(vol.VolType) select vol; return _getVolQuery(startDate, codes, volTypes, userGroup).Union(query); } /// /// 查询volatility /// public SearchListResult SearchList(VolatilityReq req) { IEnumerable codes = null; if (req.UnderlyingId != null) { codes = new[] { underlying_managerBLL.GetById(req.UnderlyingId.Value).UnderlyingCode }; } if (!string.IsNullOrEmpty(req.UnderlyingName)) { codes = new[] { underlying_managerBLL.GetQuery().Where(O => O.UnderlyingName == req.UnderlyingName).FirstOrDefault().UnderlyingCode }; } if (!string.IsNullOrEmpty(req.ContractCode)) { codes = new[] { req.ContractCode }; } if (req.QuotationDate == null || req.QuotationDate?.Year <= 2000) { if ((req.QuotationDateStart == null || req.QuotationDateStart?.Year < 2000) && (req.QuotationDateEnd == null || req.QuotationDateEnd?.Year < 2000)) { req.QuotationDate = SystemValueDate; req.QuotationDateStart = SystemValueDate; req.QuotationDateEnd = req.QuotationDateStart; } else if (req.QuotationDateStart == null || req.QuotationDateStart?.Year < 2000) { req.QuotationDateStart = req.QuotationDateEnd; } else if (req.QuotationDateEnd == null || req.QuotationDateEnd?.Year < 2000) { req.QuotationDateEnd = SystemValueDate; } if (req.QuotationDateStart >= req.QuotationDateEnd) { req.QuotationDateEnd = req.QuotationDateStart; } } if (codes == null) { codes = (from temp in underlying_managerBLL.GetQuery() where temp.LaunchState == "1" select temp.UnderlyingCode).ToList(); } IQueryable query = null; if (req.QuotationDate != null && req.QuotationDate.Value > DateTime.MinValue) { query = _getVolQuery(req.QuotationDate.Value, codes, userGroup: req.UserGroup); } else { query = _getVolQuery(req.QuotationDateStart.Value, req.QuotationDateEnd.Value, codes, userGroup: req.UserGroup); } if (!string.IsNullOrEmpty(req.VolType)) { query = query.Where(d => d.VolType.Contains(req.VolType)); } if (req.OptId != null) { query = query.Where(d => d.OptId == req.OptId); } if (!string.IsNullOrEmpty(req.OptName)) { query = query.Where(d => d.OptName.Contains(req.OptName)); } req.sidx = "QuotationDate"; req.sord = "asc"; var tempSearchList = query.ToSearchList(req); List dates = QdpCalendarHelper.AllBizDays(req.QuotationDateStart.Value, req.QuotationDateEnd.Value.AddDays(1)); List vols = new List(); var firstVol = tempSearchList.rows.FirstOrDefault(); if (firstVol != null) { foreach (var item in dates) { var vol = tempSearchList.rows.FirstOrDefault(O => O.QuotationDate == item); if (vol == null && firstVol.QuotationDate < item) { vol = firstVol.Clone(item); } else { firstVol = vol; } vols.Add(vol); } tempSearchList.records = vols.Count; tempSearchList.rows = vols; } return tempSearchList; } } }