/* * 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; using QuantConnect.Data; using QuantConnect.Data.Auxiliary; using QuantConnect.Data.UniverseSelection; using QuantConnect.Interfaces; using QuantConnect.Securities; using QuantConnect.Securities.Future; namespace QuantConnect.Algorithm.Framework.Selection { /// /// Provides an implementation of that subscribes to future chains /// public class FutureUniverseSelectionModel : UniverseSelectionModel { private DateTime _nextRefreshTimeUtc; private readonly TimeSpan _refreshInterval; private readonly UniverseSettings _universeSettings; private readonly Func> _futureChainSymbolSelector; /// /// Gets the next time the framework should invoke the `CreateUniverses` method to refresh the set of universes. /// public override DateTime GetNextRefreshTimeUtc() => _nextRefreshTimeUtc; /// /// Creates a new instance of /// /// Time interval between universe refreshes /// Selects symbols from the provided future chain public FutureUniverseSelectionModel(TimeSpan refreshInterval, Func> futureChainSymbolSelector) : this(refreshInterval, futureChainSymbolSelector, null) { } /// /// Creates a new instance of /// /// Time interval between universe refreshes /// Selects symbols from the provided future chain /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed /// Performs extra initialization (such as setting models) after we create a new security object [Obsolete("This constructor is obsolete because SecurityInitializer is obsolete and will not be used.")] public FutureUniverseSelectionModel( TimeSpan refreshInterval, Func> futureChainSymbolSelector, UniverseSettings universeSettings, ISecurityInitializer securityInitializer ) : this(refreshInterval, futureChainSymbolSelector, universeSettings) { } /// /// Creates a new instance of /// /// Time interval between universe refreshes /// Selects symbols from the provided future chain /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed public FutureUniverseSelectionModel( TimeSpan refreshInterval, Func> futureChainSymbolSelector, UniverseSettings universeSettings ) { _nextRefreshTimeUtc = DateTime.MinValue; _refreshInterval = refreshInterval; _universeSettings = universeSettings; _futureChainSymbolSelector = futureChainSymbolSelector; } /// /// Creates the universes for this algorithm. Called once after /// /// The algorithm instance to create universes for /// The universes to be used by the algorithm public override IEnumerable CreateUniverses(QCAlgorithm algorithm) { _nextRefreshTimeUtc = algorithm.UtcTime + _refreshInterval; var uniqueSymbols = new HashSet(); foreach (var futureSymbol in _futureChainSymbolSelector(algorithm.UtcTime)) { if (futureSymbol.SecurityType != SecurityType.Future) { throw new ArgumentException("FutureChainSymbolSelector must return future symbols."); } // prevent creating duplicate future chains -- one per symbol if (uniqueSymbols.Add(futureSymbol)) { yield return CreateFutureChain(algorithm, futureSymbol); } } } /// /// Creates the canonical chain security for a given symbol /// /// The algorithm instance to create universes for /// Symbol of the future /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed /// Performs extra initialization (such as setting models) after we create a new security object /// for the given symbol [Obsolete("This method is obsolete because SecurityInitializer is obsolete and will not be used.")] protected virtual Future CreateFutureChainSecurity(QCAlgorithm algorithm, Symbol symbol, UniverseSettings settings, ISecurityInitializer initializer) { return CreateFutureChainSecurity( algorithm.SubscriptionManager.SubscriptionDataConfigService, symbol, settings, algorithm.Securities); } /// /// Creates the canonical chain security for a given symbol /// /// The service used to create new /// Symbol of the future /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed /// Used to create new /// for the given symbol protected virtual Future CreateFutureChainSecurity( ISubscriptionDataConfigService subscriptionDataConfigService, Symbol symbol, UniverseSettings settings, SecurityManager securityManager) { var config = subscriptionDataConfigService.Add( typeof(ZipEntryName), symbol, settings.Resolution, settings.FillForward, settings.ExtendedMarketHours, isFilteredSubscription: false); return (Future)securityManager.CreateSecurity(symbol, config, settings.Leverage, false); } /// /// Defines the future chain universe filter /// protected virtual FutureFilterUniverse Filter(FutureFilterUniverse filter) { // NOP return filter; } /// /// Creates a for a given symbol /// /// The algorithm instance to create universes for /// Symbol of the future /// for the given symbol private FuturesChainUniverse CreateFutureChain(QCAlgorithm algorithm, Symbol symbol) { if (symbol.SecurityType != SecurityType.Future) { throw new ArgumentException("CreateFutureChain requires a future symbol."); } // rewrite non-canonical symbols to be canonical var market = symbol.ID.Market; if (!symbol.IsCanonical()) { symbol = Symbol.Create(symbol.Value, SecurityType.Future, market, $"/{symbol.Value}"); } // resolve defaults if not specified var settings = _universeSettings ?? algorithm.UniverseSettings; // create canonical security object, but don't duplicate if it already exists Security security; Future futureChain; if (!algorithm.Securities.TryGetValue(symbol, out security)) { futureChain = CreateFutureChainSecurity( algorithm.SubscriptionManager.SubscriptionDataConfigService, symbol, settings, algorithm.Securities); } else { futureChain = (Future)security; } // set the future chain contract filter function futureChain.SetFilter(Filter); // force future chain security to not be directly tradable AFTER it's configured to ensure it's not overwritten futureChain.IsTradable = false; return new FuturesChainUniverse(futureChain, settings); } } }