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 = OptionPricingModelType.BlackScholes, 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 = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
56  : this($"Theta({option},{mirrorOption},{optionModel})", option, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel)
57  {
58  }
59 
60  /// <summary>
61  /// Initializes a new instance of the Theta class
62  /// </summary>
63  /// <param name="name">The name of this indicator</param>
64  /// <param name="option">The option to be tracked</param>
65  /// <param name="riskFreeRateModel">Risk-free rate model</param>
66  /// <param name="dividendYieldModel">Dividend yield model</param>
67  /// <param name="mirrorOption">The mirror option for parity calculation</param>
68  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
69  /// <param name="ivModel">The option pricing model used to estimate IV</param>
70  public Theta(string name, Symbol option, PyObject riskFreeRateModel, PyObject dividendYieldModel, Symbol mirrorOption = null,
71  OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
72  : base(name, option, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel)
73  {
74  }
75 
76  /// <summary>
77  /// Initializes a new instance of the Theta class
78  /// </summary>
79  /// <param name="option">The option to be tracked</param>
80  /// <param name="riskFreeRateModel">Risk-free rate model</param>
81  /// <param name="dividendYieldModel">Dividend yield model</param>
82  /// <param name="mirrorOption">The mirror option for parity calculation</param>
83  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
84  /// <param name="ivModel">The option pricing model used to estimate IV</param>
85  public Theta(Symbol option, PyObject riskFreeRateModel, PyObject dividendYieldModel, Symbol mirrorOption = null,
86  OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
87  : this($"Theta({option},{mirrorOption},{optionModel})", option, riskFreeRateModel, dividendYieldModel, mirrorOption, optionModel, ivModel)
88  {
89  }
90 
91  /// <summary>
92  /// Initializes a new instance of the Theta class
93  /// </summary>
94  /// <param name="name">The name of this indicator</param>
95  /// <param name="option">The option to be tracked</param>
96  /// <param name="riskFreeRateModel">Risk-free rate model</param>
97  /// <param name="dividendYield">Dividend yield, as a constant</param>
98  /// <param name="mirrorOption">The mirror option for parity calculation</param>
99  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
100  /// <param name="ivModel">The option pricing model used to estimate IV</param>
101  public Theta(string name, Symbol option, IRiskFreeInterestRateModel riskFreeRateModel, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
102  OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
103  : base(name, option, riskFreeRateModel, dividendYield, mirrorOption, optionModel, ivModel)
104  {
105  }
106 
107  /// <summary>
108  /// Initializes a new instance of the Theta class
109  /// </summary>
110  /// <param name="option">The option to be tracked</param>
111  /// <param name="riskFreeRateModel">Risk-free rate model</param>
112  /// <param name="dividendYield">Dividend yield, as a constant</param>
113  /// <param name="mirrorOption">The mirror option for parity calculation</param>
114  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
115  /// <param name="ivModel">The option pricing model used to estimate IV</param>
116  public Theta(Symbol option, IRiskFreeInterestRateModel riskFreeRateModel, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
117  OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
118  : this($"Theta({option},{mirrorOption},{optionModel})", option, riskFreeRateModel, dividendYield, mirrorOption, optionModel, ivModel)
119  {
120  }
121 
122  /// <summary>
123  /// Initializes a new instance of the Theta class
124  /// </summary>
125  /// <param name="name">The name of this indicator</param>
126  /// <param name="option">The option to be tracked</param>
127  /// <param name="riskFreeRateModel">Risk-free rate model</param>
128  /// <param name="dividendYield">Dividend yield, as a constant</param>
129  /// <param name="mirrorOption">The mirror option for parity calculation</param>
130  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
131  /// <param name="ivModel">The option pricing model used to estimate IV</param>
132  public Theta(string name, Symbol option, PyObject riskFreeRateModel, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
133  OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
134  : base(name, option, riskFreeRateModel, dividendYield, mirrorOption, optionModel, ivModel)
135  {
136  }
137 
138  /// <summary>
139  /// Initializes a new instance of the Theta class
140  /// </summary>
141  /// <param name="option">The option to be tracked</param>
142  /// <param name="riskFreeRateModel">Risk-free rate model</param>
143  /// <param name="dividendYield">Dividend yield, as a constant</param>
144  /// <param name="mirrorOption">The mirror option for parity calculation</param>
145  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
146  /// <param name="ivModel">The option pricing model used to estimate IV</param>
147  public Theta(Symbol option, PyObject riskFreeRateModel, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
148  OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
149  : this($"Theta({option},{mirrorOption},{optionModel})", option, riskFreeRateModel, dividendYield, mirrorOption, optionModel, ivModel)
150  {
151  }
152 
153  /// <summary>
154  /// Initializes a new instance of the Theta class
155  /// </summary>
156  /// <param name="name">The name of this indicator</param>
157  /// <param name="option">The option to be tracked</param>am>
158  /// <param name="riskFreeRate">Risk-free rate, as a constant</param>
159  /// <param name="dividendYield">Dividend yield, as a constant</param>
160  /// <param name="mirrorOption">The mirror option for parity calculation</param>
161  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
162  /// <param name="ivModel">The option pricing model used to estimate IV</param>
163  public Theta(string name, Symbol option, decimal riskFreeRate = 0.05m, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
164  OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
165  : base(name, option, riskFreeRate, dividendYield, mirrorOption, optionModel, ivModel)
166  {
167  }
168 
169  /// <summary>
170  /// Initializes a new instance of the Theta class
171  /// </summary>
172  /// <param name="option">The option to be tracked</param>
173  /// <param name="riskFreeRate">Risk-free rate, as a constant</param>
174  /// <param name="dividendYield">Dividend yield, as a constant</param>
175  /// <param name="mirrorOption">The mirror option for parity calculation</param>
176  /// <param name="optionModel">The option pricing model used to estimate Theta</param>
177  /// <param name="ivModel">The option pricing model used to estimate IV</param>
178  public Theta(Symbol option, decimal riskFreeRate = 0.05m, decimal dividendYield = 0.0m, Symbol mirrorOption = null,
179  OptionPricingModelType optionModel = OptionPricingModelType.BlackScholes, OptionPricingModelType? ivModel = null)
180  : this($"Theta({option},{mirrorOption},{optionModel})", option, riskFreeRate, dividendYield, mirrorOption, optionModel, ivModel)
181  {
182  }
183 
184  // Calculate the Theta of the option
185  protected override decimal CalculateGreek(decimal timeTillExpiry)
186  {
187  var math = OptionGreekIndicatorsHelper.DecimalMath;
188 
189  switch (_optionModel)
190  {
191  case OptionPricingModelType.BinomialCoxRossRubinstein:
192  case OptionPricingModelType.ForwardTree:
193  var deltaTime = timeTillExpiry / OptionGreekIndicatorsHelper.Steps;
194 
195  var forwardPrice = 0m;
196  var price = 0m;
197  if (_optionModel == OptionPricingModelType.BinomialCoxRossRubinstein)
198  {
199  forwardPrice = OptionGreekIndicatorsHelper.CRRTheoreticalPrice(ImpliedVolatility, UnderlyingPrice, Strike, timeTillExpiry - 2 * deltaTime, RiskFreeRate, DividendYield, Right);
200  price = OptionGreekIndicatorsHelper.CRRTheoreticalPrice(ImpliedVolatility, UnderlyingPrice, Strike, timeTillExpiry, RiskFreeRate, DividendYield, Right);
201  }
202  else if (_optionModel == OptionPricingModelType.ForwardTree)
203  {
204  forwardPrice = OptionGreekIndicatorsHelper.ForwardTreeTheoreticalPrice(ImpliedVolatility, UnderlyingPrice, Strike, timeTillExpiry - 2 * deltaTime, RiskFreeRate, DividendYield, Right); price = OptionGreekIndicatorsHelper.ForwardTreeTheoreticalPrice(ImpliedVolatility, UnderlyingPrice, Strike, timeTillExpiry, RiskFreeRate, DividendYield, Right);
205  price = OptionGreekIndicatorsHelper.ForwardTreeTheoreticalPrice(ImpliedVolatility, UnderlyingPrice, Strike, timeTillExpiry, RiskFreeRate, DividendYield, Right);
206  }
207 
208  return (forwardPrice - price) * 0.5m / deltaTime / 365m;
209 
210  case OptionPricingModelType.BlackScholes:
211  default:
212  var norm = new Normal();
213  var d1 = OptionGreekIndicatorsHelper.CalculateD1(UnderlyingPrice, Strike, timeTillExpiry, RiskFreeRate, DividendYield, ImpliedVolatility);
214  var d2 = OptionGreekIndicatorsHelper.CalculateD2(d1, ImpliedVolatility, timeTillExpiry);
215  var discount = math(Math.Exp, -RiskFreeRate * timeTillExpiry);
216  var adjustment = math(Math.Exp, -DividendYield * timeTillExpiry);
217 
218  // allow at least 1% IV
219  var theta = -UnderlyingPrice * Math.Max(ImpliedVolatility, 0.01m) * math(norm.Density, d1) * adjustment * 0.5m / math(Math.Sqrt, timeTillExpiry);
220 
221  if (Right == OptionRight.Call)
222  {
223  d1 = math(norm.CumulativeDistribution, d1);
224  d2 = -math(norm.CumulativeDistribution, d2);
225  }
226  else
227  {
228  d1 = -math(norm.CumulativeDistribution, -d1);
229  d2 = math(norm.CumulativeDistribution, -d2);
230  }
231 
232  theta += DividendYield * UnderlyingPrice * d1 * adjustment + RiskFreeRate * Strike * discount * d2;
233  return theta / 365m;
234  }
235  }
236  }
237 }