Lean  $LEAN_TAG$
OptionSymbolGenerator.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 System.Collections.Generic;
18 
20 {
21  /// <summary>
22  /// Generates a new random option <see cref="Symbol"/>.
23  /// </summary>
25  {
26  private readonly DateTime _minExpiry;
27  private readonly DateTime _maxExpiry;
28  private readonly string _market;
29  private readonly int _symbolChainSize;
30  private readonly decimal _underlyingPrice;
31  private readonly decimal _maximumStrikePriceDeviation;
32  private readonly SecurityType _underlyingSecurityType = SecurityType.Equity;
33 
34  public OptionSymbolGenerator(RandomDataGeneratorSettings settings, IRandomValueGenerator random, decimal underlyingPrice, decimal maximumStrikePriceDeviation)
35  : base(settings, random)
36  {
37  // We add seven days more because TickGenerator for options needs first three underlying data points to warm up
38  // the price generator, so if the expiry date is before settings.Start plus three days no quote or trade data is
39  // generated for this option
40  _minExpiry = (settings.Start).AddDays(7);
41  _maxExpiry = (settings.End).AddDays(7);
42  _market = settings.Market;
43  _underlyingPrice = underlyingPrice;
44  _symbolChainSize = settings.ChainSymbolCount;
45  _maximumStrikePriceDeviation = maximumStrikePriceDeviation;
46  }
47 
48  /// <summary>
49  /// Generates a new random option <see cref="Symbol"/>. The generated option contract Symbol will have an
50  /// expiry between the specified min and max expiration. The strike
51  /// price will be within the specified maximum strike price deviation of the underlying symbol price
52  /// and should be rounded to reasonable value for the given price. For example, a price of 100 dollars would round
53  /// to 5 dollar increments and a price of 5 dollars would round to 50 cent increments
54  /// </summary>
55  /// <param name="ticker">Optionally can provide a ticker that should be used</param>
56  /// <remarks>
57  /// Standard contracts expiry on the third Friday.
58  /// Weekly contracts expiry every week on Friday
59  /// </remarks>
60  /// <returns>A new option contract Symbol within the specified expiration and strike price parameters along with its underlying symbol</returns>
61  protected override IEnumerable<Symbol> GenerateAsset(string ticker = null)
62  {
63  // first generate the underlying
64  var underlying = NextSymbol(_underlyingSecurityType, _market, ticker);
65  yield return underlying;
66 
67  var marketHours = MarketHoursDatabase.GetExchangeHours(_market, underlying, _underlyingSecurityType);
68  var expiry = GetRandomExpiration(marketHours, _minExpiry, _maxExpiry);
69 
70  var strikes = new HashSet<decimal>();
71  for (var i = 0; i < _symbolChainSize; i++)
72  {
73  decimal strike;
74  do
75  {
76  // generate a random strike while respecting the maximum deviation from the underlying's price
77  // since these are underlying prices, use Equity as the security type
78  strike = Random.NextPrice(_underlyingSecurityType, _market, _underlyingPrice,
79  _maximumStrikePriceDeviation);
80 
81  // round the strike price to something reasonable
82  var order = 1 + Math.Log10((double)strike);
83  strike = strike.RoundToSignificantDigits((int)order);
84  }
85  // don't allow duplicate strikes
86  while (!strikes.Add(strike));
87 
88  foreach (var optionRight in new [] { OptionRight.Put, OptionRight.Call })
89  {
90  // when providing a null option w/ an expiry, it will automatically create the OSI ticker string for the Value
91  yield return Symbol.CreateOption(underlying, _market, underlying.SecurityType.DefaultOptionStyle(), optionRight, strike, expiry);
92  }
93  }
94  }
95 
96  /// <summary>
97  /// Returns the number of symbols with the specified parameters can be generated.
98  /// There is no limit for the options.
99  /// </summary>
100  /// <returns>returns int.MaxValue</returns>
101  public override int GetAvailableSymbolCount() => int.MaxValue;
102  }
103 }