/* * 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.Linq; using Python.Runtime; using QuantConnect.Securities; using System.Collections.Generic; using QuantConnect.Data.Fundamental; using QuantConnect.Data.UniverseSelection; namespace QuantConnect.Algorithm.Framework.Selection { /// /// Provides a base class for defining equity coarse/fine fundamental selection models /// public class FundamentalUniverseSelectionModel : UniverseSelectionModel { private readonly string _market; private readonly bool _fundamentalData; private readonly bool _filterFineData; private readonly UniverseSettings _universeSettings; private readonly Func, IEnumerable> _selector; /// /// Initializes a new instance of the class /// public FundamentalUniverseSelectionModel() : this(Market.USA, null) { _fundamentalData = true; } /// /// Initializes a new instance of the class /// /// The target market /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed public FundamentalUniverseSelectionModel(string market, UniverseSettings universeSettings) { _market = market; _fundamentalData = true; _universeSettings = universeSettings; } /// /// Initializes a new instance of the class /// /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed public FundamentalUniverseSelectionModel(UniverseSettings universeSettings) : this(Market.USA, universeSettings) { } /// /// Initializes a new instance of the class /// /// The target market /// Selects symbols from the provided fundamental data set /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed public FundamentalUniverseSelectionModel(string market, Func, IEnumerable> selector, UniverseSettings universeSettings = null) { _market = market; _selector = selector; _fundamentalData = true; _universeSettings = universeSettings; } /// /// Initializes a new instance of the class /// /// Selects symbols from the provided fundamental data set /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed public FundamentalUniverseSelectionModel(Func, IEnumerable> selector, UniverseSettings universeSettings = null) : this(Market.USA, selector, universeSettings) { } /// /// Initializes a new instance of the class /// /// The target market /// Selects symbols from the provided fundamental data set /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed public FundamentalUniverseSelectionModel(string market, PyObject selector, UniverseSettings universeSettings = null) : this(universeSettings) { _market = market; Func, object> selectorFunc; if (selector.TryConvertToDelegate(out selectorFunc)) { _selector = selectorFunc.ConvertToUniverseSelectionSymbolDelegate(); } } /// /// Initializes a new instance of the class /// /// Selects symbols from the provided fundamental data set /// Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed public FundamentalUniverseSelectionModel(PyObject selector, UniverseSettings universeSettings = null) : this(Market.USA, selector, universeSettings) { } /// /// Initializes a new instance of the class /// /// True to also filter using fine fundamental data, false to only filter on coarse data [Obsolete("Fine and Coarse selection are merged, please use 'FundamentalUniverseSelectionModel()'")] protected FundamentalUniverseSelectionModel(bool filterFineData) : this(filterFineData, null) { } /// /// Initializes a new instance of the class /// /// True to also filter using fine fundamental data, false to only filter on coarse data /// The settings used when adding symbols to the algorithm, specify null to use algorithm.UniverseSettings [Obsolete("Fine and Coarse selection are merged, please use 'FundamentalUniverseSelectionModel(UniverseSettings)'")] protected FundamentalUniverseSelectionModel(bool filterFineData, UniverseSettings universeSettings) { _market = Market.USA; _filterFineData = filterFineData; _universeSettings = universeSettings; } /// /// Creates a new fundamental universe using this class's selection functions /// /// The algorithm instance to create universes for /// The universe defined by this model public override IEnumerable CreateUniverses(QCAlgorithm algorithm) { if (_fundamentalData) { var universeSettings = _universeSettings ?? algorithm.UniverseSettings; yield return new FundamentalUniverseFactory(_market, universeSettings, fundamental => Select(algorithm, fundamental)); } else { // for backwards compatibility var universe = CreateCoarseFundamentalUniverse(algorithm); if (_filterFineData) { if (universe.UniverseSettings.Asynchronous.HasValue && universe.UniverseSettings.Asynchronous.Value) { throw new ArgumentException("Asynchronous universe setting is not supported for coarse & fine selections, please use the new Fundamental single pass selection"); } #pragma warning disable CS0618 // Type or member is obsolete universe = new FineFundamentalFilteredUniverse(universe, fine => SelectFine(algorithm, fine)); #pragma warning restore CS0618 // Type or member is obsolete } yield return universe; } } /// /// Creates the coarse fundamental universe object. /// This is provided to allow more flexibility when creating coarse universe. /// /// The algorithm instance /// The coarse fundamental universe public virtual Universe CreateCoarseFundamentalUniverse(QCAlgorithm algorithm) { var universeSettings = _universeSettings ?? algorithm.UniverseSettings; return new CoarseFundamentalUniverse(universeSettings, coarse => { // if we're using fine fundamental selection than exclude symbols without fine data if (_filterFineData) { coarse = coarse.Where(c => c.HasFundamentalData); } #pragma warning disable CS0618 // Type or member is obsolete return SelectCoarse(algorithm, coarse); #pragma warning restore CS0618 // Type or member is obsolete }); } /// /// Defines the fundamental selection function. /// /// The algorithm instance /// The fundamental data used to perform filtering /// An enumerable of symbols passing the filter public virtual IEnumerable Select(QCAlgorithm algorithm, IEnumerable fundamental) { if(_selector == null) { throw new NotImplementedException("If inheriting, please overrride the 'Select' fundamental function, else provide it as a constructor parameter"); } return _selector(fundamental); } /// /// Defines the coarse fundamental selection function. /// /// The algorithm instance /// The coarse fundamental data used to perform filtering /// An enumerable of symbols passing the filter [Obsolete("Fine and Coarse selection are merged, please use 'Select(QCAlgorithm, IEnumerable)'")] public virtual IEnumerable SelectCoarse(QCAlgorithm algorithm, IEnumerable coarse) { throw new NotImplementedException("Please overrride the 'Select' fundamental function"); } /// /// Defines the fine fundamental selection function. /// /// The algorithm instance /// The fine fundamental data used to perform filtering /// An enumerable of symbols passing the filter [Obsolete("Fine and Coarse selection are merged, please use 'Select(QCAlgorithm, IEnumerable)'")] public virtual IEnumerable SelectFine(QCAlgorithm algorithm, IEnumerable fine) { // default impl performs no filtering of fine data return fine.Select(f => f.Symbol); } /// /// Convenience method for creating a selection model that uses only coarse data /// /// Selects symbols from the provided coarse data set /// A new universe selection model that will select US equities according to the selection function specified [Obsolete("Fine and Coarse selection are merged, please use 'Fundamental(Func, IEnumerable>)'")] public static IUniverseSelectionModel Coarse(Func, IEnumerable> coarseSelector) { return new CoarseFundamentalUniverseSelectionModel(coarseSelector); } /// /// Convenience method for creating a selection model that uses coarse and fine data /// /// Selects symbols from the provided coarse data set /// Selects symbols from the provided fine data set (this set has already been filtered according to the coarse selection) /// A new universe selection model that will select US equities according to the selection functions specified [Obsolete("Fine and Coarse selection are merged, please use 'Fundamental(Func, IEnumerable>)'")] public static IUniverseSelectionModel Fine(Func, IEnumerable> coarseSelector, Func, IEnumerable> fineSelector) { return new FineFundamentalUniverseSelectionModel(coarseSelector, fineSelector); } /// /// Convenience method for creating a selection model that uses fundamental data /// /// Selects symbols from the provided fundamental data set /// A new universe selection model that will select US equities according to the selection functions specified public static IUniverseSelectionModel Fundamental(Func, IEnumerable> selector) { return new FundamentalUniverseSelectionModel(selector); } } }