/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; namespace QuantConnect.ToolBox.RandomDataGenerator { /// /// Generates a new random option . /// public class OptionSymbolGenerator : BaseSymbolGenerator { private readonly DateTime _minExpiry; private readonly DateTime _maxExpiry; private readonly string _market; private readonly int _symbolChainSize; private readonly decimal _underlyingPrice; private readonly decimal _maximumStrikePriceDeviation; private readonly SecurityType _underlyingSecurityType = SecurityType.Equity; public OptionSymbolGenerator(RandomDataGeneratorSettings settings, IRandomValueGenerator random, decimal underlyingPrice, decimal maximumStrikePriceDeviation) : base(settings, random) { // We add seven days more because TickGenerator for options needs first three underlying data points to warm up // the price generator, so if the expiry date is before settings.Start plus three days no quote or trade data is // generated for this option _minExpiry = (settings.Start).AddDays(7); _maxExpiry = (settings.End).AddDays(7); _market = settings.Market; _underlyingPrice = underlyingPrice; _symbolChainSize = settings.ChainSymbolCount; _maximumStrikePriceDeviation = maximumStrikePriceDeviation; } /// /// Generates a new random option . The generated option contract Symbol will have an /// expiry between the specified min and max expiration. The strike /// price will be within the specified maximum strike price deviation of the underlying symbol price /// and should be rounded to reasonable value for the given price. For example, a price of 100 dollars would round /// to 5 dollar increments and a price of 5 dollars would round to 50 cent increments /// /// Optionally can provide a ticker that should be used /// /// Standard contracts expiry on the third Friday. /// Weekly contracts expiry every week on Friday /// /// A new option contract Symbol within the specified expiration and strike price parameters along with its underlying symbol protected override IEnumerable GenerateAsset(string ticker = null) { // first generate the underlying var underlying = NextSymbol(_underlyingSecurityType, _market, ticker); yield return underlying; var marketHours = MarketHoursDatabase.GetExchangeHours(_market, underlying, _underlyingSecurityType); var expiry = GetRandomExpiration(marketHours, _minExpiry, _maxExpiry); var strikes = new HashSet(); for (var i = 0; i < _symbolChainSize; i++) { decimal strike; do { // generate a random strike while respecting the maximum deviation from the underlying's price // since these are underlying prices, use Equity as the security type strike = Random.NextPrice(_underlyingSecurityType, _market, _underlyingPrice, _maximumStrikePriceDeviation); // round the strike price to something reasonable var order = 1 + Math.Log10((double)strike); strike = strike.RoundToSignificantDigits((int)order); } // don't allow duplicate strikes while (!strikes.Add(strike)); foreach (var optionRight in new [] { OptionRight.Put, OptionRight.Call }) { // when providing a null option w/ an expiry, it will automatically create the OSI ticker string for the Value yield return Symbol.CreateOption(underlying, _market, underlying.SecurityType.DefaultOptionStyle(), optionRight, strike, expiry); } } } /// /// Returns the number of symbols with the specified parameters can be generated. /// There is no limit for the options. /// /// returns int.MaxValue public override int GetAvailableSymbolCount() => int.MaxValue; } }