Lean  $LEAN_TAG$
OptionContract.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 
20 using System;
21 
23 {
24  /// <summary>
25  /// Defines a single option contract at a specific expiration and strike price
26  /// </summary>
28  {
29  private IOptionData _optionData = OptionPriceModelResultData.Null;
30  private readonly SymbolProperties _symbolProperties;
31 
32  /// <summary>
33  /// Gets the strike price
34  /// </summary>
35  public decimal Strike => Symbol.ID.StrikePrice;
36 
37  /// <summary>
38  /// Gets the strike price multiplied by the strike multiplier
39  /// </summary>
40  public decimal ScaledStrike => Strike * _symbolProperties.StrikeMultiplier;
41 
42  /// <summary>
43  /// Gets the right being purchased (call [right to buy] or put [right to sell])
44  /// </summary>
46 
47  /// <summary>
48  /// Gets the option style
49  /// </summary>
51 
52  /// <summary>
53  /// Gets the theoretical price of this option contract as computed by the <see cref="IOptionPriceModel"/>
54  /// </summary>
55  public decimal TheoreticalPrice => _optionData.TheoreticalPrice;
56 
57  /// <summary>
58  /// Gets the implied volatility of the option contract as computed by the <see cref="IOptionPriceModel"/>
59  /// </summary>
60  public decimal ImpliedVolatility => _optionData.ImpliedVolatility;
61 
62  /// <summary>
63  /// Gets the greeks for this contract
64  /// </summary>
65  public Greeks Greeks => _optionData.Greeks;
66 
67  /// <summary>
68  /// Gets the open interest
69  /// </summary>
70  public override decimal OpenInterest => _optionData.OpenInterest;
71 
72  /// <summary>
73  /// Gets the last price this contract traded at
74  /// </summary>
75  public override decimal LastPrice => _optionData.LastPrice;
76 
77  /// <summary>
78  /// Gets the last volume this contract traded at
79  /// </summary>
80  public override long Volume => _optionData.Volume;
81 
82  /// <summary>
83  /// Gets the current bid price
84  /// </summary>
85  public override decimal BidPrice => _optionData.BidPrice;
86 
87  /// <summary>
88  /// Get the current bid size
89  /// </summary>
90  public override long BidSize => _optionData.BidSize;
91 
92  /// <summary>
93  /// Gets the ask price
94  /// </summary>
95  public override decimal AskPrice => _optionData.AskPrice;
96 
97  /// <summary>
98  /// Gets the current ask size
99  /// </summary>
100  public override long AskSize => _optionData.AskSize;
101 
102  /// <summary>
103  /// Gets the last price the underlying security traded at
104  /// </summary>
105  public decimal UnderlyingLastPrice => _optionData.UnderlyingLastPrice;
106 
107  /// <summary>
108  /// Initializes a new instance of the <see cref="OptionContract"/> class
109  /// </summary>
110  /// <param name="security">The option contract security</param>
112  : base(security.Symbol)
113  {
114  _symbolProperties = security.SymbolProperties;
115  }
116 
117  /// <summary>
118  /// Initializes a new option contract from a given <see cref="OptionUniverse"/> instance
119  /// </summary>
120  /// <param name="contractData">The option universe contract data to use as source for this contract</param>
121  /// <param name="symbolProperties">The contract symbol properties</param>
122  public OptionContract(OptionUniverse contractData, SymbolProperties symbolProperties)
123  : base(contractData.Symbol)
124  {
125  _symbolProperties = symbolProperties;
126  _optionData = new OptionUniverseData(contractData);
127  }
128 
129  /// <summary>
130  /// Sets the option price model evaluator function to be used for this contract
131  /// </summary>
132  /// <param name="optionPriceModelEvaluator">Function delegate used to evaluate the option price model</param>
133  internal void SetOptionPriceModel(Func<OptionPriceModelResult> optionPriceModelEvaluator)
134  {
135  _optionData = new OptionPriceModelResultData(optionPriceModelEvaluator, _optionData as OptionPriceModelResultData);
136  }
137 
138  /// <summary>
139  /// Creates a <see cref="OptionContract"/>
140  /// </summary>
141  /// <param name="baseData"></param>
142  /// <param name="security">Provides price properties for a <see cref="Security"/></param>
143  /// <param name="underlying">Last underlying security trade data</param>
144  /// <returns>Option contract</returns>
145  public static OptionContract Create(BaseData baseData, ISecurityPrice security, BaseData underlying)
146  => Create(baseData.EndTime, security, underlying);
147 
148  /// <summary>
149  /// Creates a <see cref="OptionContract"/>
150  /// </summary>
151  /// <param name="endTime">local date time this contract's data was last updated</param>
152  /// <param name="security">provides price properties for a <see cref="Security"/></param>
153  /// <param name="underlying">last underlying security trade data</param>
154  /// <returns>Option contract</returns>
155  public static OptionContract Create(DateTime endTime, ISecurityPrice security, BaseData underlying)
156  {
157  var contract = new OptionContract(security)
158  {
159  Time = endTime,
160  };
161  contract._optionData.SetUnderlying(underlying);
162 
163  return contract;
164  }
165 
166  /// <summary>
167  /// Creates a new option contract from a given <see cref="OptionUniverse"/> instance,
168  /// using its data to form a quote bar to source pricing data
169  /// </summary>
170  /// <param name="contractData">The option universe contract data to use as source for this contract</param>
171  /// <param name="symbolProperties">The contract symbol properties</param>
172  public static OptionContract Create(OptionUniverse contractData, SymbolProperties symbolProperties)
173  {
174  var contract = new OptionContract(contractData, symbolProperties)
175  {
176  Time = contractData.EndTime,
177  };
178 
179  return contract;
180  }
181 
182  /// <summary>
183  /// Implicit conversion into <see cref="Symbol"/>
184  /// </summary>
185  /// <param name="contract">The option contract to be converted</param>
186  public static implicit operator Symbol(OptionContract contract)
187  {
188  return contract.Symbol;
189  }
190 
191  /// <summary>
192  /// Updates the option contract with the new data, which can be a <see cref="Tick"/> or <see cref="TradeBar"/> or <see cref="QuoteBar"/>
193  /// </summary>
194  internal override void Update(BaseData data)
195  {
196  if (data.Symbol.SecurityType.IsOption())
197  {
198  _optionData.Update(data);
199  }
201  {
202  _optionData.SetUnderlying(data);
203  }
204  }
205 
206  #region Option Contract Data Handlers
207 
208  private interface IOptionData
209  {
210  decimal LastPrice { get; }
211  decimal UnderlyingLastPrice { get; }
212  long Volume { get; }
213  decimal BidPrice { get; }
214  long BidSize { get; }
215  decimal AskPrice { get; }
216  long AskSize { get; }
217  decimal OpenInterest { get; }
218  decimal TheoreticalPrice { get; }
219  decimal ImpliedVolatility { get; }
220  Greeks Greeks { get; }
221 
222  void Update(BaseData data);
223 
224  void SetUnderlying(BaseData data);
225  }
226 
227  /// <summary>
228  /// Handles option data for a contract from actual price data (trade, quote, open interest) and theoretical price model results
229  /// </summary>
230  private class OptionPriceModelResultData : IOptionData
231  {
232  public static readonly OptionPriceModelResultData Null = new(() => OptionPriceModelResult.None);
233 
234  private readonly Lazy<OptionPriceModelResult> _optionPriceModelResult;
235  private TradeBar _tradeBar;
236  private QuoteBar _quoteBar;
237  private OpenInterest _openInterest;
238  private BaseData _underlying;
239 
240  public decimal LastPrice => _tradeBar?.Close ?? decimal.Zero;
241 
242  public decimal UnderlyingLastPrice => _underlying?.Price ?? decimal.Zero;
243 
244  public long Volume => (long)(_tradeBar?.Volume ?? 0L);
245 
246  public decimal BidPrice => _quoteBar?.Bid?.Close ?? decimal.Zero;
247 
248  public long BidSize => (long)(_quoteBar?.LastBidSize ?? 0L);
249 
250  public decimal AskPrice => _quoteBar?.Ask?.Close ?? decimal.Zero;
251 
252  public long AskSize => (long)(_quoteBar?.LastAskSize ?? 0L);
253 
254  public decimal OpenInterest => _openInterest?.Value ?? decimal.Zero;
255 
256  public decimal TheoreticalPrice => _optionPriceModelResult.Value.TheoreticalPrice;
257  public decimal ImpliedVolatility => _optionPriceModelResult.Value.ImpliedVolatility;
258  public Greeks Greeks => _optionPriceModelResult.Value.Greeks;
259 
260  public OptionPriceModelResultData(Func<OptionPriceModelResult> optionPriceModelEvaluator,
261  OptionPriceModelResultData previousOptionData = null)
262  {
263  _optionPriceModelResult = new(optionPriceModelEvaluator, isThreadSafe: false);
264 
265  if (previousOptionData != null)
266  {
267  _tradeBar = previousOptionData._tradeBar;
268  _quoteBar = previousOptionData._quoteBar;
269  _openInterest = previousOptionData._openInterest;
270  _underlying = previousOptionData._underlying;
271  }
272  }
273 
274  public void Update(BaseData data)
275  {
276  switch (data)
277  {
278  case TradeBar tradeBar:
279  _tradeBar = tradeBar;
280  break;
281  case QuoteBar quoteBar:
282  _quoteBar = quoteBar;
283  break;
284  case OpenInterest openInterest:
285  _openInterest = openInterest;
286  break;
287  }
288  }
289 
290  public void SetUnderlying(BaseData data)
291  {
292  _underlying = data;
293  }
294  }
295 
296  /// <summary>
297  /// Handles option data for a contract from a <see cref="OptionUniverse"/> instance
298  /// </summary>
299  private class OptionUniverseData : IOptionData
300  {
301  private readonly OptionUniverse _contractData;
302 
303  public decimal LastPrice => _contractData.Close;
304 
305  // TODO: Null check required for FOPs: since OptionUniverse does not support FOPs,
306  // these instances will by "synthetic" and will not have underlying data.
307  // Can be removed after FOPs are supported by OptionUniverse
308  public decimal UnderlyingLastPrice => _contractData?.Underlying?.Price ?? decimal.Zero;
309 
310  public long Volume => (long)_contractData.Volume;
311 
312  public decimal BidPrice => _contractData.Close;
313 
314  public long BidSize => 0;
315 
316  public decimal AskPrice => _contractData.Close;
317 
318  public long AskSize => 0;
319 
320  public decimal OpenInterest => _contractData.OpenInterest;
321 
322  public decimal TheoreticalPrice => decimal.Zero;
323 
324  public decimal ImpliedVolatility => _contractData.ImpliedVolatility;
325 
326  public Greeks Greeks => _contractData.Greeks;
327 
328  public OptionUniverseData(OptionUniverse contractData)
329  {
330  _contractData = contractData;
331  }
332 
333  public void Update(BaseData data)
334  {
335  }
336 
337  public void SetUnderlying(BaseData data)
338  {
339  }
340  }
341 
342  #endregion
343  }
344 }