1515
1616using System ;
1717using MathNet . Numerics . RootFinding ;
18+ using Python . Runtime ;
19+ using QuantConnect . Data ;
1820using QuantConnect . Data . Consolidators ;
19- using QuantConnect . Data . Market ;
2021using QuantConnect . Logging ;
22+ using QuantConnect . Python ;
2123
2224namespace QuantConnect . Indicators
2325{
2426 /// <summary>
2527 /// Implied Volatility indicator that calculate the IV of an option using Black-Scholes Model
2628 /// </summary>
27- public class ImpliedVolatility : BarIndicator , IIndicatorWarmUpPeriodProvider
29+ public class ImpliedVolatility : IndicatorBase < IndicatorDataPoint > , IIndicatorWarmUpPeriodProvider
2830 {
2931 private readonly Symbol _optionSymbol ;
3032 private readonly Symbol _underlyingSymbol ;
@@ -34,29 +36,34 @@ public class ImpliedVolatility : BarIndicator, IIndicatorWarmUpPeriodProvider
3436 private OptionPricingModelType _optionModel ;
3537
3638 /// <summary>
37- /// Gets the expiration time of the option
39+ /// Risk-free rate model
3840 /// </summary>
39- public DateTime Expiry { get ; }
41+ private readonly IRiskFreeInterestRateModel _riskFreeInterestRateModel ;
4042
4143 /// <summary>
42- /// Gets the option right (call/put) of the option
44+ /// Gets the expiration time of the option
4345 /// </summary>
44- public OptionRight Right { get ; }
46+ public DateTime Expiry => _optionSymbol . ID . Date ;
4547
4648 /// <summary>
47- /// Risk Free Rate
49+ /// Gets the option right (call/put) of the option
4850 /// </summary>
49- public decimal RiskFreeRate { get ; set ; }
51+ public OptionRight Right => _optionSymbol . ID . OptionRight ;
5052
5153 /// <summary>
5254 /// Gets the strike price of the option
5355 /// </summary>
54- public decimal Strike { get ; }
56+ public decimal Strike => _optionSymbol . ID . StrikePrice ;
5557
5658 /// <summary>
5759 /// Gets the option style (European/American) of the option
5860 /// </summary>
59- public OptionStyle Style { get ; }
61+ public OptionStyle Style => _optionSymbol . ID . OptionStyle ;
62+
63+ /// <summary>
64+ /// Risk Free Rate
65+ /// </summary>
66+ public Identity RiskFreeRate { get ; set ; }
6067
6168 /// <summary>
6269 /// Gets the historical volatility of the underlying
@@ -73,28 +80,15 @@ public class ImpliedVolatility : BarIndicator, IIndicatorWarmUpPeriodProvider
7380 /// </summary>
7481 public IndicatorBase < IndicatorDataPoint > UnderlyingPrice { get ; }
7582
76- /// <summary>
77- /// Initializes a new instance of the ImpliedVolatility class
78- /// </summary>
79- /// <param name="option">The option to be tracked</param>am>
80- /// <param name="riskFreeRate">The risk free rate</param>
81- /// <param name="period">The lookback period of historical volatility</param>
82- /// <param name="optionModel">The option pricing model used to estimate IV</param>
83- public ImpliedVolatility ( Symbol option , decimal riskFreeRate = 0.05m , int period = 252 ,
84- OptionPricingModelType optionModel = OptionPricingModelType . BlackScholes )
85- : this ( $ "IV({ option . Value } ,{ riskFreeRate } ,{ period } ,{ optionModel } )", option , riskFreeRate , period , optionModel )
86- {
87- }
88-
8983 /// <summary>
9084 /// Initializes a new instance of the ImpliedVolatility class
9185 /// </summary>
9286 /// <param name="name">The name of this indicator</param>
9387 /// <param name="option">The option to be tracked</param>
94- /// <param name="riskFreeRate">The risk free rate</param>
88+ /// <param name="riskFreeRateModel">Risk- free rate model </param>
9589 /// <param name="period">The lookback period of historical volatility</param>
9690 /// <param name="optionModel">The option pricing model used to estimate IV</param>
97- public ImpliedVolatility ( string name , Symbol option , decimal riskFreeRate = 0.05m , int period = 252 ,
91+ public ImpliedVolatility ( string name , Symbol option , IRiskFreeInterestRateModel riskFreeRateModel , int period = 252 ,
9892 OptionPricingModelType optionModel = OptionPricingModelType . BlackScholes )
9993 : base ( name )
10094 {
@@ -107,14 +101,10 @@ public ImpliedVolatility(string name, Symbol option, decimal riskFreeRate = 0.05
107101 _optionSymbol = option ;
108102 _underlyingSymbol = option . Underlying ;
109103 _roc = new ( 1 ) ;
104+ _riskFreeInterestRateModel = riskFreeRateModel ;
110105 _optionModel = optionModel ;
111-
112- Strike = sid . StrikePrice ;
113- Expiry = sid . Date ;
114- Right = sid . OptionRight ;
115- Style = sid . OptionStyle ;
116- RiskFreeRate = riskFreeRate ;
117106
107+ RiskFreeRate = new Identity ( name + "_RiskFreeRate" ) ;
118108 HistoricalVolatility = IndicatorExtensions . Times (
119109 IndicatorExtensions . Of (
120110 new StandardDeviation ( period ) ,
@@ -133,6 +123,75 @@ public ImpliedVolatility(string name, Symbol option, decimal riskFreeRate = 0.05
133123 WarmUpPeriod = period ;
134124 }
135125
126+ /// <summary>
127+ /// Initializes a new instance of the ImpliedVolatility class
128+ /// </summary>
129+ /// <param name="option">The option to be tracked</param>
130+ /// <param name="riskFreeRateModel">Risk-free rate model</param>
131+ /// <param name="period">The lookback period of historical volatility</param>
132+ /// <param name="optionModel">The option pricing model used to estimate IV</param>
133+ public ImpliedVolatility ( Symbol option , IRiskFreeInterestRateModel riskFreeRateModel , int period = 252 ,
134+ OptionPricingModelType optionModel = OptionPricingModelType . BlackScholes )
135+ : this ( $ "IV({ option . Value } ,{ period } ,{ optionModel } )", option , riskFreeRateModel , period , optionModel )
136+ {
137+ }
138+
139+ /// <summary>
140+ /// Initializes a new instance of the ImpliedVolatility class
141+ /// </summary>
142+ /// <param name="name">The name of this indicator</param>
143+ /// <param name="option">The option to be tracked</param>
144+ /// <param name="riskFreeRateModel">Risk-free rate model</param>
145+ /// <param name="period">The lookback period of historical volatility</param>
146+ /// <param name="optionModel">The option pricing model used to estimate IV</param>
147+ public ImpliedVolatility ( string name , Symbol option , PyObject riskFreeRateModel , int period = 252 ,
148+ OptionPricingModelType optionModel = OptionPricingModelType . BlackScholes )
149+ : this ( name , option , RiskFreeInterestRateModelPythonWrapper . FromPyObject ( riskFreeRateModel ) , period , optionModel )
150+ {
151+ }
152+
153+ /// <summary>
154+ /// Initializes a new instance of the ImpliedVolatility class
155+ /// </summary>
156+ /// <param name="option">The option to be tracked</param>
157+ /// <param name="riskFreeRateModel">Risk-free rate model</param>
158+ /// <param name="period">The lookback period of historical volatility</param>
159+ /// <param name="optionModel">The option pricing model used to estimate IV</param>
160+ public ImpliedVolatility ( Symbol option , PyObject riskFreeRateModel , int period = 252 ,
161+ OptionPricingModelType optionModel = OptionPricingModelType . BlackScholes )
162+ : this ( $ "IV({ option . Value } ,{ period } ,{ optionModel } )", option ,
163+ RiskFreeInterestRateModelPythonWrapper . FromPyObject ( riskFreeRateModel ) , period , optionModel )
164+ {
165+ }
166+
167+ /// <summary>
168+ /// Initializes a new instance of the ImpliedVolatility class
169+ /// </summary>
170+ /// <param name="name">The name of this indicator</param>
171+ /// <param name="option">The option to be tracked</param>
172+ /// <param name="riskFreeRate">Risk-free rate, as a constant</param>
173+ /// <param name="period">The lookback period of historical volatility</param>
174+ /// <param name="optionModel">The option pricing model used to estimate IV</param>
175+ public ImpliedVolatility ( string name , Symbol option , decimal riskFreeRate = 0.05m , int period = 252 ,
176+ OptionPricingModelType optionModel = OptionPricingModelType . BlackScholes )
177+ : this ( name , option , new ConstantRiskFreeRateInterestRateModel ( riskFreeRate ) , period , optionModel )
178+ {
179+ }
180+
181+ /// <summary>
182+ /// Initializes a new instance of the ImpliedVolatility class
183+ /// </summary>
184+ /// <param name="option">The option to be tracked</param>
185+ /// <param name="riskFreeRate">Risk-free rate, as a constant</param>
186+ /// <param name="period">The lookback period of historical volatility</param>
187+ /// <param name="optionModel">The option pricing model used to estimate IV</param>
188+ public ImpliedVolatility ( Symbol option , decimal riskFreeRate = 0.05m , int period = 252 ,
189+ OptionPricingModelType optionModel = OptionPricingModelType . BlackScholes )
190+ : this ( $ "IV({ option . Value } ,{ period } ,{ riskFreeRate } ,{ optionModel } )", option ,
191+ new ConstantRiskFreeRateInterestRateModel ( riskFreeRate ) , period , optionModel )
192+ {
193+ }
194+
136195 /// <summary>
137196 /// Gets a flag indicating when this indicator is ready and fully initialized
138197 /// </summary>
@@ -148,17 +207,19 @@ public ImpliedVolatility(string name, Symbol option, decimal riskFreeRate = 0.05
148207 /// </summary>
149208 /// <param name="input">The input given to the indicator</param>
150209 /// <returns>The input is returned unmodified.</returns>
151- protected override decimal ComputeNextValue ( IBaseDataBar input )
210+ protected override decimal ComputeNextValue ( IndicatorDataPoint input )
152211 {
212+ RiskFreeRate . Update ( input . EndTime , _riskFreeInterestRateModel . GetInterestRate ( input . EndTime ) ) ;
213+
153214 var inputSymbol = input . Symbol ;
154215 if ( inputSymbol == _optionSymbol )
155216 {
156- Price . Update ( input . EndTime , input . Close ) ;
217+ Price . Update ( input . EndTime , input . Price ) ;
157218 }
158219 else if ( inputSymbol == _underlyingSymbol )
159220 {
160221 _consolidator . Update ( input ) ;
161- UnderlyingPrice . Update ( input . EndTime , input . Close ) ;
222+ UnderlyingPrice . Update ( input . EndTime , input . Price ) ;
162223 }
163224 else
164225 {
@@ -194,14 +255,15 @@ private decimal CalculateIV(DateTime time)
194255 var spotPrice = UnderlyingPrice . Current . Value ;
195256 var timeToExpiration = Convert . ToDecimal ( ( Expiry - time ) . TotalDays ) / 365m ;
196257
197- Func < double , double > f = ( vol ) => ( double ) ( TheoreticalPrice ( Convert . ToDecimal ( vol ) , spotPrice , Strike , timeToExpiration , RiskFreeRate , Right , _optionModel ) - price ) ;
258+ Func < double , double > f = ( vol ) =>
259+ ( double ) ( TheoreticalPrice ( Convert . ToDecimal ( vol ) , spotPrice , Strike , timeToExpiration , RiskFreeRate . Current . Value , Right , _optionModel ) - price ) ;
198260 try
199261 {
200262 return Convert . ToDecimal ( Brent . FindRoot ( f , 0.01d , 1.0d , 1e-5d , 20 ) ) ;
201263 }
202264 catch
203265 {
204- Log . Error ( "Fail to converge, returning 0." ) ;
266+ Log . Error ( "ImpliedVolatility.CalculateIV(): Fail to converge, returning 0." ) ;
205267 return 0m ;
206268 }
207269 }
@@ -211,12 +273,14 @@ private decimal CalculateIV(DateTime time)
211273 /// </summary>
212274 public override void Reset ( )
213275 {
276+ _consolidator . Dispose ( ) ;
214277 _consolidator = new ( TimeSpan . FromDays ( 1 ) ) ;
215278 _consolidator . DataConsolidated += ( _ , bar ) => {
216279 _roc . Update ( bar . EndTime , bar . Price ) ;
217280 } ;
218281
219282 _roc . Reset ( ) ;
283+ RiskFreeRate . Reset ( ) ;
220284 HistoricalVolatility . Reset ( ) ;
221285 Price . Reset ( ) ;
222286 UnderlyingPrice . Reset ( ) ;
0 commit comments