Lean  $LEAN_TAG$
Theta.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using MathNet.Numerics.Distributions;
18 using Python.Runtime;
19 using QuantConnect.Data;
20 
22 {
23  /// <summary>
24  /// Option Theta indicator that calculate the theta of an option
25  /// </summary>
26  /// <remarks>sensitivity of option price on time decay</remarks>
28  {
29  /// <summary>
30  /// Initializes a new instance of the Theta class
31  /// </summary>
32  /// <param name="name">The name of this indicator</param>
33  /// <param name="option">The option to be tracked</param>
34  /// <param name="riskFreeRateModel">Risk-free rate model</param>
35  /// <param name="dividendYieldModel">Dividend yield model</param>
36  /// <param name="mirrorOption">The mirror option for parity calculation</param>
37  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
38  /// <param name="ivModel">The option pricing model used to estimate IV</param>
39  public Theta(string name, Symbol option, IRiskFreeInterestRateModel riskFreeRateModel, IDividendYieldModel dividendYieldModel, Symbol mirrorOption = null,
40  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
41  : base(name, option, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel)
42  {
43  }
44 
45  /// <summary>
46  /// Initializes a new instance of the Theta class
47  /// </summary>
48  /// <param name="option">The option to be tracked</param>
49  /// <param name="riskFreeRateModel">Risk-free rate model</param>
50  /// <param name="dividendYieldModel">Dividend yield model</param>
51  /// <param name="mirrorOption">The mirror option for parity calculation</param>
52  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
53  /// <param name="ivModel">The option pricing model used to estimate IV</param>
54  public Theta(Symbol option, IRiskFreeInterestRateModel riskFreeRateModel, IDividendYieldModel dividendYieldModel, Symbol mirrorOption = null,
55  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
56  : this($"Theta({option},{mirrorOption},{GetOptionModel(optionModel, option.ID.OptionStyle)})", option, riskFreeRateModel,
57  dividendYieldModel, mirrorOption, optionModel, ivModel)
58  {
59  }
60 
61  /// <summary>
62  /// Initializes a new instance of the Theta class
63  /// </summary>
64  /// <param name="name">The name of this indicator</param>
65  /// <param name="option">The option to be tracked</param>
66  /// <param name="riskFreeRateModel">Risk-free rate model</param>
67  /// <param name="dividendYieldModel">Dividend yield model</param>
68  /// <param name="mirrorOption">The mirror option for parity calculation</param>
69  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
70  /// <param name="ivModel">The option pricing model used to estimate IV</param>
71  public Theta(string name, Symbol option, PyObject riskFreeRateModel, PyObject dividendYieldModel, Symbol mirrorOption = null,
72  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
73  : base(name, option, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel)
74  {
75  }
76 
77  /// <summary>
78  /// Initializes a new instance of the Theta class
79  /// </summary>
80  /// <param name="option">The option to be tracked</param>
81  /// <param name="riskFreeRateModel">Risk-free rate model</param>
82  /// <param name="dividendYieldModel">Dividend yield model</param>
83  /// <param name="mirrorOption">The mirror option for parity calculation</param>
84  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
85  /// <param name="ivModel">The option pricing model used to estimate IV</param>
86  public Theta(Symbol option, PyObject riskFreeRateModel, PyObject dividendYieldModel, Symbol mirrorOption = null,
87  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
88  : this($"Theta({option},{mirrorOption},{GetOptionModel(optionModel, option.ID.OptionStyle)})", option, riskFreeRateModel,
89  dividendYieldModel, mirrorOption, optionModel, ivModel)
90  {
91  }
92 
93  /// <summary>
94  /// Initializes a new instance of the Theta class
95  /// </summary>
96  /// <param name="name">The name of this indicator</param>
97  /// <param name="option">The option to be tracked</param>
98  /// <param name="riskFreeRateModel">Risk-free rate model</param>
99  /// <param name="dividendYield">Dividend yield, as a constant</param>
100  /// <param name="mirrorOption">The mirror option for parity calculation</param>
101  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
102  /// <param name="ivModel">The option pricing model used to estimate IV</param>
103  public Theta(string name, Symbol option, IRiskFreeInterestRateModel riskFreeRateModel, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
104  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
105  : base(name, option, riskFreeRateModel, dividendYield, mirrorOption, optionModel, ivModel)
106  {
107  }
108 
109  /// <summary>
110  /// Initializes a new instance of the Theta class
111  /// </summary>
112  /// <param name="option">The option to be tracked</param>
113  /// <param name="riskFreeRateModel">Risk-free rate model</param>
114  /// <param name="dividendYield">Dividend yield, as a constant</param>
115  /// <param name="mirrorOption">The mirror option for parity calculation</param>
116  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
117  /// <param name="ivModel">The option pricing model used to estimate IV</param>
118  public Theta(Symbol option, IRiskFreeInterestRateModel riskFreeRateModel, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
119  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
120  : this($"Theta({option},{mirrorOption},{GetOptionModel(optionModel, option.ID.OptionStyle)})", option, riskFreeRateModel,
121  dividendYield, mirrorOption, optionModel, ivModel)
122  {
123  }
124 
125  /// <summary>
126  /// Initializes a new instance of the Theta class
127  /// </summary>
128  /// <param name="name">The name of this indicator</param>
129  /// <param name="option">The option to be tracked</param>
130  /// <param name="riskFreeRateModel">Risk-free rate model</param>
131  /// <param name="dividendYield">Dividend yield, as a constant</param>
132  /// <param name="mirrorOption">The mirror option for parity calculation</param>
133  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
134  /// <param name="ivModel">The option pricing model used to estimate IV</param>
135  public Theta(string name, Symbol option, PyObject riskFreeRateModel, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
136  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
137  : base(name, option, riskFreeRateModel, dividendYield, mirrorOption, optionModel, ivModel)
138  {
139  }
140 
141  /// <summary>
142  /// Initializes a new instance of the Theta class
143  /// </summary>
144  /// <param name="option">The option to be tracked</param>
145  /// <param name="riskFreeRateModel">Risk-free rate model</param>
146  /// <param name="dividendYield">Dividend yield, as a constant</param>
147  /// <param name="mirrorOption">The mirror option for parity calculation</param>
148  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
149  /// <param name="ivModel">The option pricing model used to estimate IV</param>
150  public Theta(Symbol option, PyObject riskFreeRateModel, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
151  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
152  : this($"Theta({option},{mirrorOption},{GetOptionModel(optionModel, option.ID.OptionStyle)})", option, riskFreeRateModel,
153  dividendYield, mirrorOption, optionModel, ivModel)
154  {
155  }
156 
157  /// <summary>
158  /// Initializes a new instance of the Theta class
159  /// </summary>
160  /// <param name="name">The name of this indicator</param>
161  /// <param name="option">The option to be tracked</param>am>
162  /// <param name="riskFreeRate">Risk-free rate, as a constant</param>
163  /// <param name="dividendYield">Dividend yield, as a constant</param>
164  /// <param name="mirrorOption">The mirror option for parity calculation</param>
165  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
166  /// <param name="ivModel">The option pricing model used to estimate IV</param>
167  public Theta(string name, Symbol option, decimal riskFreeRate = 0.05m, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
168  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
169  : base(name, option, riskFreeRate, dividendYield, mirrorOption, optionModel, ivModel)
170  {
171  }
172 
173  /// <summary>
174  /// Initializes a new instance of the Theta class
175  /// </summary>
176  /// <param name="option">The option to be tracked</param>
177  /// <param name="riskFreeRate">Risk-free rate, as a constant</param>
178  /// <param name="dividendYield">Dividend yield, as a constant</param>
179  /// <param name="mirrorOption">The mirror option for parity calculation</param>
180  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
181  /// <param name="ivModel">The option pricing model used to estimate IV</param>
182  public Theta(Symbol option, decimal riskFreeRate = 0.05m, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
183  OptionPricingModelType? optionModel = null, OptionPricingModelType? ivModel = null)
184  : this($"Theta({option},{mirrorOption},{GetOptionModel(optionModel, option.ID.OptionStyle)})", option, riskFreeRate, dividendYield,
185  mirrorOption, optionModel, ivModel)
186  {
187  }
188 
189  /// <summary>
190  /// Calculate the Theta of the option
191  /// </summary>
192  protected override decimal CalculateGreek(decimal timeTillExpiry)
193  {
194  var underlyingPrice = (double)UnderlyingPrice.Current.Value;
195  var strike = (double)Strike;
196  var timeTillExpiryDouble = (double)timeTillExpiry;
197  var riskFreeRate = (double)RiskFreeRate.Current.Value;
198  var dividendYield = (double)DividendYield.Current.Value;
199  var iv = (double)ImpliedVolatility.Current.Value;
200 
201  double result;
202 
203  switch (_optionModel)
204  {
205  case OptionPricingModelType.BinomialCoxRossRubinstein:
206  case OptionPricingModelType.ForwardTree:
207  var deltaTime = timeTillExpiryDouble / OptionGreekIndicatorsHelper.Steps;
208 
209  var forwardPrice = 0d;
210  var price = 0d;
211  if (_optionModel == OptionPricingModelType.BinomialCoxRossRubinstein)
212  {
213  forwardPrice = OptionGreekIndicatorsHelper.CRRTheoreticalPrice(iv, underlyingPrice, strike, timeTillExpiryDouble - 2 * deltaTime, riskFreeRate, dividendYield, Right);
214  price = OptionGreekIndicatorsHelper.CRRTheoreticalPrice(iv, underlyingPrice, strike, timeTillExpiryDouble, riskFreeRate, dividendYield, Right);
215  }
216  else if (_optionModel == OptionPricingModelType.ForwardTree)
217  {
218  forwardPrice = OptionGreekIndicatorsHelper.ForwardTreeTheoreticalPrice(iv, underlyingPrice, strike, timeTillExpiryDouble - 2 * deltaTime, riskFreeRate, dividendYield, Right);
219  price = OptionGreekIndicatorsHelper.ForwardTreeTheoreticalPrice(iv, underlyingPrice, strike, timeTillExpiryDouble, riskFreeRate, dividendYield, Right);
220  }
221 
222  result = (forwardPrice - price) * 0.5 / deltaTime / 365d;
223  break;
224 
225  case OptionPricingModelType.BlackScholes:
226  default:
227  var norm = new Normal();
228  var d1 = OptionGreekIndicatorsHelper.CalculateD1(underlyingPrice, strike, timeTillExpiryDouble, riskFreeRate, dividendYield, iv);
229  var d2 = OptionGreekIndicatorsHelper.CalculateD2(d1, iv, timeTillExpiryDouble);
230  var discount = Math.Exp(-riskFreeRate * timeTillExpiryDouble);
231  var adjustment = Math.Exp(-dividendYield * timeTillExpiryDouble);
232 
233  // allow at least 1% IV
234  var theta = -underlyingPrice * Math.Max(iv, 0.01) * norm.Density(d1) * adjustment * 0.5 / Math.Sqrt(timeTillExpiryDouble);
235 
236  if (Right == OptionRight.Call)
237  {
238  d1 = norm.CumulativeDistribution(d1);
239  d2 = -norm.CumulativeDistribution(d2);
240  }
241  else
242  {
243  d1 = -norm.CumulativeDistribution(-d1);
244  d2 = norm.CumulativeDistribution(-d2);
245  }
246 
247  theta += dividendYield * underlyingPrice * d1 * adjustment + riskFreeRate * strike * discount * d2;
248  result = theta / 365;
249  break;
250  }
251 
252  return Convert.ToDecimal(result);
253  }
254  }
255 }