using BaseOUDAL; using YLErp.Modules.CalculationModule; using YLErp.Modules.SkewMapVolModule; using YLErp.QdpModule; using YLErp.QdpModule.Constants; namespace YLErp.Modules.VolatilityModule { /// /// 波动率取值服务 /// public class SingleVolService { public static double GetSingleVol(SingleVolReq singleVolReq, int userId, bool isEodCalc = false) { if (string.IsNullOrWhiteSpace(singleVolReq.VolType)) { throw new ServiceException("波动率类型不能为空"); } if (singleVolReq.ExerciseDate == DateTime.MinValue) { throw new ServiceException("行权日不能为空"); } if (singleVolReq.TradeDate == DateTime.MinValue) { throw new ServiceException("交易日期不能为空"); } if (PS.Config.ErpElement.SkewMapVolConstruction) { return GetSingleVolWithSkewMapMode(singleVolReq, userId); } else { return GetSingleVolWithNormalMode(singleVolReq, userId, isEodCalc); } } //获取正常模式的波动率 private static double GetSingleVolWithNormalMode(SingleVolReq singleVolReq, int userId, bool isEodCalc = false) { var userGroup = singleVolReq.UserGroup.TrimToNull() ?? UserBLL.GetUserGroup(userId); var volatility = new VolatilityQueryService(OptUserInfo.SystemUser) .GetVolatility(userGroup, singleVolReq.TradeDate, singleVolReq.VolType, singleVolReq.UnderlyingCode); if (volatility == null) { throw new ServiceException($"没有找到{singleVolReq.VolType}波动率数据:{singleVolReq.UnderlyingCode}"); } if (volatility is VolatilityDefault) { return ConsVolInfos.defVol; } var req = new InterpolatedVolReq { valueDate = singleVolReq.TradeDate, exerciseDate = singleVolReq.ExerciseDate, strike = singleVolReq.Strike, isMoneynessOption = singleVolReq.IsMoneynessOption == "是", isEodCalc = isEodCalc, spot = singleVolReq.SpotPrice, volSurfaceType = volatility.VolSurfaceMode }; return QdpVolHelper.GetInterpolatedVolFromNormalSurface(volatility.VolTable, req, volatility.InterpolationMethod); } //获取skew模式的波动率 private static double GetSingleVolWithSkewMapMode(SingleVolReq req, int userId) { if (req.Vols == null) { var userGroup = UserBLL.GetUserGroup(userId); req.Vols = new VolatilityQueryService(OptUserInfo.SystemUser) .GetVolatility(userGroup, req.TradeDate, "交易", req.UnderlyingCode); } if (req.Vols == null || string.IsNullOrEmpty(req.Vols.VolSurfaceMode)) { throw new InvalidOperationException($"找不到波动率曲面{req.UnderlyingCode}"); } if (!req.BaseVol.HasValue) { throw new InvalidOperationException($"参数BaseVol缺失"); } //var initParam = new VolSurfaceInitParamsBuilder(userId.ToString()).SetValueDate(singleVolReq.TradeDate) // .SetUnderlying(singleVolReq.UnderlyingId, singleVolReq.UnderlyingCode, singleVolReq.UnderlyingName).SetVolatility(volatility).Build(); //VolSurfaceInitializerSingleton.GetInitializer(false).InitializeMarketProxy(initParam); if (req.VolType == "报价Bid") { if (!req.BidVar.HasValue || req.BidVar.Value < 1) { return 0; } //var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId.ToString()); var baseVolSurface = SkewMapVolHelper.GetSkewMapBaseVolSurface(req.UnderlyingCode, req.Vols); var skewMapVolSurface = new SkewMapVolSurface(baseVolSurface.BaseVol); var t = TradeCalcHelper.CalculateTTMDays( req.TradeDate, req.ExerciseDate, req.UnderlyingTypeId, precisionOfMinute: false); return skewMapVolSurface.GetVolWithBaseVol( baseVol: req.BaseVol.Value, t: Math.Ceiling(t), //不考虑日内精确时间 k: req.Strike, spot: req.SpotPrice, isCall: req.CallPut == "Call", isBuy: true, var: req.BidVar ?? 0); } else if (req.VolType == "报价Ask") { if (!req.AskVar.HasValue || req.AskVar.Value < 1) { return 0; } //var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId.ToString()); var baseVolSurface = SkewMapVolHelper.GetSkewMapBaseVolSurface(req.UnderlyingCode, req.Vols); var skewMapVolSurface = new SkewMapVolSurface(baseVolSurface.BaseVol); var t = TradeCalcHelper.CalculateTTMDays( req.TradeDate, req.ExerciseDate, req.UnderlyingTypeId, precisionOfMinute: false); return skewMapVolSurface.GetVolWithBaseVol( baseVol: req.BaseVol.Value, t: Math.Ceiling(t), //不考虑日内精确时间 k: req.Strike, spot: req.SpotPrice, isCall: req.CallPut == "Call", isBuy: false, var: req.AskVar ?? 0); } else { throw new Exception("波动率类型应为'报价Bid'或'报价Ask'"); } } } }