diff --git a/Indicators/ImpliedVolatility.cs b/Indicators/ImpliedVolatility.cs index 09b7c96c9157..2edb7555424f 100644 --- a/Indicators/ImpliedVolatility.cs +++ b/Indicators/ImpliedVolatility.cs @@ -29,7 +29,7 @@ public class ImpliedVolatility : BarIndicator, IIndicatorWarmUpPeriodProvider private BaseDataConsolidator _consolidator; private RateOfChange _roc; private decimal _impliedVolatility; - private bool _binomial; + private OptionPricingModelType _optionModel; /// /// Gets the expiration time of the option @@ -77,9 +77,10 @@ public class ImpliedVolatility : BarIndicator, IIndicatorWarmUpPeriodProvider /// The option to be trackedam> /// The risk free rate /// The lookback period of historical volatility - /// Should option priced under binomial model? - public ImpliedVolatility(Symbol option, decimal riskFreeRate = 0.05m, int period = 252, bool binomial = false) - : this($"IV({option.Value},{riskFreeRate},{period},{binomial})", option, riskFreeRate, period, binomial) + /// The option pricing model used to estimate IV + public ImpliedVolatility(Symbol option, decimal riskFreeRate = 0.05m, int period = 252, + OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes) + : this($"IV({option.Value},{riskFreeRate},{period},{optionModel})", option, riskFreeRate, period, optionModel) { } @@ -90,8 +91,9 @@ public ImpliedVolatility(Symbol option, decimal riskFreeRate = 0.05m, int period /// The option to be tracked /// The risk free rate /// The lookback period of historical volatility - /// Should option priced under binomial model? - public ImpliedVolatility(string name, Symbol option, decimal riskFreeRate = 0.05m, int period = 252, bool binomial = false) + /// The option pricing model used to estimate IV + public ImpliedVolatility(string name, Symbol option, decimal riskFreeRate = 0.05m, int period = 252, + OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes) : base(name) { var sid = option.ID; @@ -103,7 +105,7 @@ public ImpliedVolatility(string name, Symbol option, decimal riskFreeRate = 0.05 _optionSymbol = option; _underlyingSymbol = option.Underlying; _roc = new(1); - _binomial = binomial; + _optionModel = optionModel; Strike = sid.StrikePrice; Expiry = sid.Date; @@ -172,14 +174,16 @@ protected override decimal ComputeNextValue(IBaseDataBar input) // Calculate the theoretical option price private decimal TheoreticalPrice(decimal volatility, decimal spotPrice, decimal strikePrice, decimal timeToExpiration, decimal riskFreeRate, - OptionRight optionType, bool binomial = false) + OptionRight optionType, OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes) { - if (binomial) + switch (optionModel) { - return OptionGreekIndicatorsHelper.CRRTheoreticalPrice(volatility, spotPrice, strikePrice, timeToExpiration, riskFreeRate, optionType); + case OptionPricingModelType.BinomialCoxRossRubinstein: + return OptionGreekIndicatorsHelper.CRRTheoreticalPrice(volatility, spotPrice, strikePrice, timeToExpiration, riskFreeRate, optionType); + case OptionPricingModelType.BlackScholes: + default: + return OptionGreekIndicatorsHelper.BlackTheoreticalPrice(volatility, spotPrice, strikePrice, timeToExpiration, riskFreeRate, optionType); } - // IV is calculated under BSM framework in default - return OptionGreekIndicatorsHelper.BlackTheoreticalPrice(volatility, spotPrice, strikePrice, timeToExpiration, riskFreeRate, optionType); } // Calculate the IV of the option @@ -189,7 +193,7 @@ private decimal CalculateIV(DateTime time) var spotPrice = UnderlyingPrice.Current.Value; var timeToExpiration = Convert.ToDecimal((Expiry - time).TotalDays) / 365m; - Func f = (vol) => TheoreticalPrice(vol, spotPrice, Strike, timeToExpiration, RiskFreeRate, Right, _binomial); + Func f = (vol) => TheoreticalPrice(vol, spotPrice, Strike, timeToExpiration, RiskFreeRate, Right, _optionModel); return OptionGreekIndicatorsHelper.BrentApproximation(f, price, 0.01m, 1.0m); } diff --git a/Indicators/OptionPricingModelType.cs b/Indicators/OptionPricingModelType.cs new file mode 100644 index 000000000000..df9d3f16be0b --- /dev/null +++ b/Indicators/OptionPricingModelType.cs @@ -0,0 +1,32 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +namespace QuantConnect.Indicators +{ + /// + /// Defines different types of option pricing model + /// + public enum OptionPricingModelType + { + /// + /// Vanilla Black Scholes Model + /// + BlackScholes, + /// + /// The Cox-Ross-Rubinstein binomial tree model (CRR model) + /// + BinomialCoxRossRubinstein + } +} diff --git a/Tests/Indicators/ImpliedVolatilityTests.cs b/Tests/Indicators/ImpliedVolatilityTests.cs index 478b8c691056..e79eebb6e2fd 100644 --- a/Tests/Indicators/ImpliedVolatilityTests.cs +++ b/Tests/Indicators/ImpliedVolatilityTests.cs @@ -145,7 +145,7 @@ public void ComparesIVOnCRRModel(decimal price, decimal spotPrice, OptionRight r { // Under CRR framework var symbol = Symbol.CreateOption("SPY", Market.USA, OptionStyle.American, right, 450m, _reference.AddDays(expiry)); - var indicator = new ImpliedVolatility(_symbol, 0.04m, binomial: true); + var indicator = new ImpliedVolatility(_symbol, 0.04m, optionModel: OptionPricingModelType.BinomialCoxRossRubinstein); var optionTradeBar = new TradeBar(_reference, _symbol, price, price, price, price, 0m); var spotTradeBar = new TradeBar(_reference, _underlying, spotPrice, spotPrice, spotPrice, spotPrice, 0m);