using Qdp.Pricing.Library.Common.MathMethods.VolTermStructure; using YLErp.Abstract; using YLErp.Models; using YLErp.Modules.SkewMapVolModule; using YLErp.QdpModule; using YLErp.QdpModule.Constants; namespace YLErp.Modules.CalculationModule { public static class SkewMapVolHelper { public static double GetInterpolatedVol( IVolatility volSurface, DateTime valueDate, string underlyingCode, DateTime exerciseDate, double strikePrice, bool isBuy, bool isCall, double spotPrice, double timeToMaturityDays = double.NaN, int? skewMapVolVar = null) { var baseVolSurface = GetSkewMapBaseVolSurface(underlyingCode, volSurface); var skewMapVolSurface = new SkewMapVolSurface(baseVolSurface.BaseVol); var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); var t = double.IsNaN(timeToMaturityDays) ? TradeCalcHelper.CalculateTTMDays( valueDate, exerciseDate, varietyid: underlying?.UnderlyingTypeId ?? 0, precisionOfMinute: false) : timeToMaturityDays; var volVar = skewMapVolVar ?? (int)(isBuy ? baseVolSurface.BidVar : baseVolSurface.AskVar); return skewMapVolSurface.GetVol( t: Math.Ceiling(t), //不考虑日内精确时间 k: strikePrice, spot: spotPrice, isCall: isCall, isBuy: isBuy, var: volVar); } /// /// skewmapvol转换为正常波动率构造 /// public static IVolatility GetNormalVolatility( IVolatility volSurface, DateTime valueDate, string underlyingCode, DateTime exerciseDate, double strikePrice, bool isBuy, bool isCall, double spotPrice, double timeToMaturityDays = double.NaN, int? skewMapVolVar = null) { var vol = GetInterpolatedVol(volSurface, valueDate, underlyingCode, exerciseDate, strikePrice, isBuy, isCall, spotPrice, timeToMaturityDays, skewMapVolVar); var singleVols = QdpVolHelper.GenerateFlatSingleVols(vol); return new VolatilityImpl { InterpolationMethod = ConsVolInfos.defInterpolationMethod, VolSurfaceMode = ConsVolInfos.defVolMode, VolTable = singleVols }; } public static SkewMapBaseVolSurface GetSkewMapBaseVolSurface(string underlyingCode, IVolatility volSurface) { Dictionary baseVols = null; try { baseVols = volSurface.VolTable.ToDictionary(x => x.Expire, x => x.Vol); } catch (Exception ex) { throw new Exception($"{underlyingCode}的BaseVol格式不正确", ex); } if (baseVols == null) { throw new Exception($"{underlyingCode}的BaseVol为空"); } if (!baseVols.ContainsKey("BidVar") || !baseVols.ContainsKey("AskVar")) { throw new Exception($"{underlyingCode}的BidVar或AskVar缺失"); } var baseVolSurface = new SkewMapBaseVolSurface { BaseVol = baseVols, BidVar = baseVols["BidVar"], AskVar = baseVols["AskVar"] }; return baseVolSurface; } /// /// 获取某交易的BaseVol /// public static double GetSkewMapBaseVolForTrade( DateTime valueDate, string UnderlyingCode, IVolatility volSurface, int UnderlyingTypeId, DateTime ExerciseDate, double timeToMaturityDays = double.NaN) { var baseVolSurface = GetSkewMapBaseVolSurface(UnderlyingCode, volSurface); var skewMapVolSurface = new SkewMapVolSurface(baseVolSurface.BaseVol); var t = double.IsNaN(timeToMaturityDays) ? TradeCalcHelper.CalculateTTMDays( valueDate, ExerciseDate, UnderlyingTypeId, precisionOfMinute: false) : timeToMaturityDays; //用于波动率插值的t,不考虑日内精确时间,所以向上取整 return skewMapVolSurface.GetBaseVol(Math.Ceiling(t)); } public static List ContructSkewMapVolTable(double baseVol, int bidVar, int askVar) { return new List() { new SingleVol() { Strike = 1.0, Expire = "1M", Vol = baseVol }, new SingleVol() { Strike = 1.0, Expire = "3M", Vol = baseVol }, new SingleVol() { Strike = 1.0, Expire = "6M", Vol = baseVol }, new SingleVol() { Strike = 1.0, Expire = "BidVar", Vol = bidVar }, new SingleVol() { Strike = 1.0, Expire = "AskVar", Vol = askVar }, }; } } }