using Qdp.ComputeService.Data.CommonModels.ValuationParams.Equity; using Qdp.Foundation.Implementations; using YLErp.Abstract; using YLErp.BLL.Calculation; using YLErp.QdpModule; namespace YLErp.Modules.CalculationModule { /// /// 隐含波动率计算服务 /// public class ImpliedVolCalcService { /// /// 根据权利金计算隐含波动率 /// /// 期权单价 /// 计算日期 public static double ImpliedVolFromPremium( double premium, DateTime valueDate, string underlyingTicker, string underlyingInstrumentType, double strike, DateTime startDate, DateTime endDate, string optionType, string exerciseType, double spotPrice, double notional, double riskFreeRate, string tradeType, DateTime exerciseDate, double participationRate, double principalRate, bool isAnnualized, double annualizeFactor, double dividendRate = 0.0, bool isMoneynessOption = false, double initialSpotPrice = 0.0, Dictionary dividends = null, bool hasNightMarket = false, bool preciseTimeMode = false, double ttmDays = double.NaN, IVolatility volatility = null) { var optionTradeParam = new VanillaOptionTradeParam { annualizedFactor = annualizeFactor, buysell = tradeType, preciseTimeMode = preciseTimeMode, dividendRate = dividendRate, dividends = dividends, endDate = endDate, exerciseDate = exerciseDate, exerciseType = exerciseType, hasNightMarket = hasNightMarket, initialSpotPrice = initialSpotPrice, isAnnualized = isAnnualized, isMoneynessOption = isMoneynessOption, notional = notional, optionType = QdpConverter.ConvertOptionType(optionType), participationRate = participationRate, principalRate = principalRate, riskFreeRate = riskFreeRate, settlementDate = exerciseDate, startDate = startDate, strike = strike, timeToMaturityDays = ttmDays, tradeDate = startDate, underlyingInstrumentType = underlyingInstrumentType, underlyingTickers = new[] { underlyingTicker }, tradeId = null, volSurfaceNames = null, isForwardTrade = false }; return ImpliedVolFromPremium(premium, valueDate, optionTradeParam, spotPrice, volatility); } /// /// 根据权利金计算隐含波动率 /// /// 期权单价 /// 计算日期 /// 期权要素 /// 标的现价 public static double ImpliedVolFromPremium(double premium, DateTime valueDate , VanillaOptionTradeParam optionTradeParam, double spotPrice, IVolatility volatility = null) { //在计算ImpliedVol时,提前处理strike,然后都当做非MoneynessOption处理 if (optionTradeParam.isMoneynessOption) { optionTradeParam.isMoneynessOption = false; optionTradeParam.strike *= optionTradeParam.initialSpotPrice; } if (optionTradeParam.volSurfaceNames == null || !optionTradeParam.volSurfaceNames.Any()) { optionTradeParam.volSurfaceNames = new[] { Guid.NewGuid().ToString() }; } var volSurfaceName = optionTradeParam.volSurfaceNames[0]; if (optionTradeParam.underlyingTickers == null || !optionTradeParam.underlyingTickers.Any()) { throw new Exception("缺少标的代码"); } var underlyingTicker = optionTradeParam.underlyingTickers[0]; optionTradeParam.buysell = "买入"; var optionTrade = QdpTradeBuilder.GetVanillaOptionTrade(optionTradeParam); using (var marketProxy = new MarketProxy(valueDate, optionTradeParam.riskFreeRate)) { //设置标的价格 marketProxy.SetStockPrice(underlyingTicker, spotPrice); marketProxy.SetVolSurface(volSurfaceName, volatility ?? QdpVolHelper.GetDefaultVolatility(0.3)); OptionValuationParameters parameters; if (optionTradeParam.underlyingInstrumentType == ConsGlobal.InstrumentType.Stock) { //设置DividendCurve var dividendCurveName = Guid.NewGuid().ToString(); var dividendCurve = CalculatorHelper.CreateConstantRiskFreeCurve(dividendCurveName, optionTradeParam.dividendRate); marketProxy.SetYieldCurve(dividendCurveName, dividendCurve); parameters = new OptionValuationParameters(marketProxy.DiscountCurveName, dividendCurveName, volSurfaceName, underlyingTicker); } else { parameters = new OptionValuationParameters(marketProxy.DiscountCurveName, MarketProxy.ConstantZeroCurve, volSurfaceName, underlyingTicker); } return optionTrade.ImpliedVolFromPremium(premium, marketProxy.QdpMarket, parameters); } } } }