Universe Selection
Fundamental Universes
Introduction
A FundamentalUniverseSelectionModel
selects a universe of US Equities based on Fundamental
data. Depending on the Fundamental
properties you use, these universes rely on the US Equity Coarse Universe dataset, the US Fundamental dataset, or both.
These types of universes operate on daily schedule by default. In backtests, they select assets at midnight. In live trading, the selection timing depends on the data provider you use. To adjust the selection schedule, see Schedule.
If you use a fundamental Universe Selection model, the only way to unsubscribe from a security is to return a list from the selection function that doesn't include the security Symbol
. The RemoveSecurity
remove_security
method doesn't work with these types of Universe Selection models.
Fundamental Selection
The FundamentalUniverseSelectionModel
lets you select stocks based on corporate Fundamental
data.
You can specific the selection method, which takes a list of Fundamental
objects as argument and returns a list of Symbol
objects.
public override void Initialize() { // Run asynchronous universe selection to speed up your algorithm. // In this case, you can't rely on the method or algorithm state between filter calls. UniverseSettings.Asynchronous = true; AddUniverseSelection(new FundamentalUniverseSelectionModel(FundamentalFilterFunction)); } public override List<Symbol> FundamentalFilterFunction(List<Fundamental> fundamental) { return (from f in fundamental // Select symbols with fundamental data and a price above $10. where f.Price > 10 && !Double.IsNaN(f.ValuationRatios.PERatio) // Sort the assets in ascending order by their P/E ratio. orderby f.ValuationRatios.PERatio // Select the first 10 assets. select f.Symbol).Take(10); }
def initialize(self) -> None: # Run asynchronous universe selection to speed up your algorithm. # In this case, you can't rely on the method or algorithm state between filter calls. self.universe_settings.asynchronous = True self.add_universe_selection(FundamentalUniverseSelectionModel(self._fundamental_filter_function)) def _fundamental_filter_function(self, fundamental: List[Fundamental]): # Select symbols with fundamental data and a price above $10. filtered = [f for f in fundamental if f.price > 10 and not np.isnan(f.valuation_ratios.pe_ratio)] # Sort the assets in ascending order by their P/E ratio. sorted_by_pe_ratio = sorted(filtered, key=lambda f: f.valuation_ratios.pe_ratio) # Select the first 10 assets. return [f.symbol for f in sorted_by_pe_ratio[:10]]
The following table describes the arguments the model accepts:
Argument | Data Type | Description | Default Value |
---|---|---|---|
selector |
Func<IEnumerable<Fundamental>, IEnumerable<Symbol>>
Callable[[List[Fundamental]], List[Symbol]] | Filter function to select assets based on fundamental data. | |
universeSettings universe_settings | UniverseSettings | The universe settings. If you don't provide an argument, the model uses the algorithm.UniverseSettings algorithm.universe_settings by default. | None null |
The Fundamental
objects have the following properties:
To move the selection function outside of the algorithm class, create a universe selection model that inherits the FundamentalUniverseSelectionModel
class and override its Select
select
method.
// In the Initialize method, enable asynchronous universe selection to speed up your algorithm. UniverseSettings.Asynchronous = true; // Add a custom universe selection model that selects undervalued, liquid stocks. AddUniverseSelection(new LiquidAndLowPEUniverseSelectionModel()); // Outside of the algorithm class, define the universe selection model. public class LiquidAndLowPEUniverseSelectionModel : FundamentalUniverseSelectionModel { public override IEnumerableSelect(QCAlgorithm algorithm, IEnumerable fundamental) { return fundamental // Select symbols with fundamental data and a price above $1. .Where(x => x.HasFundamentalData && x.Price > 1 && !Double.IsNaN(x.ValuationRatios.PERatio)) // Select the 100 assets with the greatest daily dollar volume. .OrderByDescending(x => x.DollarVolume) .Take(100) // Select the 10 assets with the lowest PE ratio. .OrderByDescending(x => x.ValuationRatios.PERatio) .Take(10) .Select(x => x.Symbol); } }
# In the initialize method, enable asynchronous universe selection to speed up your algorithm. self.universe_settings.asynchronous = True # Add a custom universe selection model that selects undervalued, liquid stocks. self.add_universe_selection(LiquidAndLowPEUniverseSelectionModel()) # Outside of the algorithm class, define the universe selection model. class LiquidAndLowPEUniverseSelectionModel(FundamentalUniverseSelectionModel): def select(self, fundamental: List[Fundamental]) -> List[Symbol]: # Select symbols with fundamental data and a price above $1. filtered = [x for x in fundamental if x.price > 1 and not np.isnan(x.valuation_ratios.pe_ratio)] # Select the 100 assets with the greatest daily dollar volume. most_liquid = sorted(filtered, key=lambda x: x.dollar_volume, reverse=True)[:100] # Select the 10 assets with the lowest PE ratio. lowest_pe_ratio = sorted(most_liquid, key=lambda x: x.valuation_ratios.pe_ratio, reverse=True)[:10] return [x.Symbol for x in lowest_pe_ratio]
To return the current universe constituents from the selection function, return Universe.UnchangedUNCHANGED
.
To view the implementation of this model, see the LEAN GitHub repositoryLEAN GitHub repository.
EMA Cross Selection
The EmaCrossUniverseSelectionModel
applies two exponential moving average (EMA) indicators to the price history of assets and then selects the assets that have their fast EMA furthest above their slow EMA on a percentage basis.
// Initialize asynchronous universe settings for faster processing and add EmaCrossUniverseSelectionModel to dynamically manage the universe based on EMA cross signals to identify trending assets. public override void Initialize() { UniverseSettings.Asynchronous = true; AddUniverseSelection(new EmaCrossUniverseSelectionModel()); }
# Initialize asynchronous universe settings for faster processing and add EmaCrossUniverseSelectionModel to dynamically manage the universe based on EMA cross signals to identify trending assets. def initialize(self) -> None: self.universe_settings.asynchronous = True self.add_universe_selection(EmaCrossUniverseSelectionModel())
The following table describes the arguments the model accepts:
Argument | Data Type | Description | Default Value |
---|---|---|---|
fastPeriod fast_period | int | Fast EMA period | 100 |
slowPeriod slow_period | int | Slow EMA period | 300 |
universeCount universe_count | int | Maximum number of members of this universe selection | 500 |
universeSettings universe_settings | UniverseSettings | The universe settings. If you don't provide an argument, the model uses the algorithm.UniverseSettings algorithm.universe_settings by default. | None null |
To view the implementation of this model, see the LEAN GitHub repositoryLEAN GitHub repository.