# Equity

## Fundamental Universes

### Introduction

A fundamental universe lets you select stocks based on corporate fundamental data. This data is powered by Morningstar® and includes approximately 8,100 tickers (including delisted companies) with 900 properties each.

### Create Universes

To add a fundamental universe, in the Initialize method, pass a filter function to the AddUniverse method. The filter function receives a list of Fundamental objects and must return a list of Symbol objects. The Symbol objects you return from the function are the constituents of the fundamental universe and LEAN automatically creates subscriptions for them. Don't call AddEquity in the filter function.

public class MyUniverseAlgorithm : QCAlgorithm {
public override void Initialize()
{
}

private IEnumerable<Symbol> FundamentalFilterFunction(IEnumerable<Fundamental> fundamental)
{
return (from f in fundamental
where f.HasFundamentalData
select f.Symbol);
}
}
class MyUniverseAlgorithm(QCAlgorithm):
def Initialize(self) -> None:

def FundamentalFunction(self, fundamental: List[Fundamental]) -> List[Symbol]:
return [c.Symbol for c in fundamental if c.HasFundamentalData]

Fundamental objects have the following attributes:

#### Example

The simplest example of accessing the fundamental object would be harnessing the iconic PE ratio for a stock. This is a ratio of the price it commands to the earnings of a stock. The lower the PE ratio for a stock, the more affordable it appears.

// Take the top 50 by dollar volume using fundamental
// Then the top 10 by PERatio using fine
fundamental => (from f in fundamental
where f.Price > 10 && f.HasFundamentalData
orderby f.DollarVolume descending).Take(100)
.OrderBy(f => f.ValuationRatios.PERatio).Take(10)
.Select(f => f.Symbol));
# In Initialize:

def FundamentalSelectionFunction(self, fundamental: List[Fundamental]) -> List[Symbol]:
filtered = [f for f in fundamental if f.Price > 10 and f.HasFundamentalData]
sortedByDollarVolume = sorted(filtered, key=lambda f: f.DollarVolume, reverse=True)[:100]
sortedByPeRatio = sorted(sortedByDollarVolume, key=lambda f: f.ValuationRatios.PERatio, reverse=False)[:10]
return [f.Symbol for f in sortedByPeRatio]

#### Asset Categories

In addition to valuation ratios, the US Fundamental Data from Morningstar has many other data point attributes, including over 200 different categorization fields for each US stock. Morningstar groups these fields into sectors, industry groups, and industries.

Sectors are large super categories of data. To get the sector of a stock, use the MorningstarSectorCode property.

var tech = fundamental.Where(x => x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Technology);
tech = [x for x in fundamental if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Technology]


Industry groups are clusters of related industries that tie together. To get the industry group of a stock, use the MorningstarIndustryGroupCode property.

var ag = fundamental.Where(x => x.AssetClassification.MorningstarIndustryGroupCode == MorningstarIndustryGroupCode.Agriculture);
ag = [x for x in fundamental if x.AssetClassification.MorningstarIndustryGroupCode == MorningstarIndustryGroupCode.Agriculture]


Industries are the finest level of classification available. They are the individual industries according to the Morningstar classification system. To get the industry of a stock, use the MorningstarIndustryCode.

var coal = fundamental.Where(x => x.AssetClassification.MorningstarIndustryCode == MorningstarSectorCode.Coal);
coal = [x for x in fundamental if x.AssetClassification.MorningstarIndustryCode == MorningstarSectorCode.Coal]


#### Practical Limitations

Fundamental universes allow you to select an unlimited universe of assets to analyze. Each asset in the universe consumes approximately 5MB of RAM, so you may quickly run out of memory if your universe filter selects many assets. If you backtest your algorithms in the Algorithm Lab, familiarize yourself with the RAM capacity of your backtesting and live trading nodes. To keep your algorithm fast and efficient, only subscribe to the assets you need.

### Direct Access

To get fundamental data for Equities in your algorithm, use the Fundamentals property of the Equity objects. The fundamental data represent the company's fundamentals for the current algorithm time.

var fundamentals = Securities[_symbol].Fundamentals;
fundamentals = self.Securities[self.symbol].Fundamentals

To get fundamental data for Equities, regardless of whether or not you have subscribed to them in your algorithm, call the Fundamentals method. If you pass one Symbol, the method returns a Fundamental object. If you pass a list of Symbol objects, the method returns a list of Fundamental objects. The fundamental data represents the corporate fundamentals for the current algorithm time.

// Single asset
var ibm = QuantConnect.Symbol.Create("IBM", SecurityType.Equity, Market.USA);
var ibmFundamental = Fundamentals(ibm);

// Multiple assets
var nb = QuantConnect.Symbol.Create("NB", SecurityType.Equity, Market.USA);
var fundamentals = Fundamentals(new List<Symbol>{ nb, ibm }).ToList();
# Single asset
ibm = QuantConnect.Symbol.Create("IBM", SecurityType.Equity, Market.USA)
ibm_fundamental = self.Fundamentals(ibm)

# Multiple assets
nb = QuantConnect.Symbol.Create("NB", SecurityType.Equity, Market.USA)
fundamentals = self.Fundamentals([ nb, ibm ])

#### Data Availability

Some assets don't have fundamentals (for example, ETFs) and the Morningstar dataset doesn't provide fundamentals for all US Equities. To check if fundamental data is available for an asset, use the HasFundamentalData property.

var hasFundamentalData = Securities[_symbol].Fundamentals.HasFundamentalData;
has_fundamental_data = self.Securities[self.symbol].Fundamentals.HasFundamentalData

#### Object References

If you save a reference to the Fundamentals object or its properties, you can access the fundamental properties as they change over time.

_fundamentals = Securities[_symbol].Fundamentals;
var earningRatios = _fundamentals.EarningRatios;
self.fundamentals  = self.Securities[self.symbol].Fundamentals
earning_ratios = self.fundamentals.EarningRatios

### Historical Data

To get historical fundamental data, call the History method. The return type depends on how you call the method.

var ibm = QuantConnect.Symbol.Create("IBM", SecurityType.Equity, Market.USA);

// Fundamental objects
var fundamentalHistory = History<Fundamental>(ibm, TimeSpan.FromDays(30));

// Fundamentals objects for all US Equities (including delisted companies)
var fundamentalsHistory = History<Fundamentals>(TimeSpan.FromDays(30));
ibm = Symbol.Create("IBM", SecurityType.Equity, Market.USA)

# DataFrame objects
df_history = qb.History(Fundamental, ibm, timedelta(30))

# Fundamental objects
fundamental_history = self.History[Fundamental](ibm, timedelta(30))

# Fundamentals objects for all US Equities (including delisted companies)
fundamentals_history = self.History[Fundamentals](timedelta(30))

### Selection Frequency

Equity universes run on a daily basis.

The live data for fundamental universe selection arrives at 6/7 AM Eastern Time (ET), so fundamental universe selection runs for live algorithms between 7 and 8 AM ET. This timing allows you to place trades before the market opens. Don't schedule anything for midnight because the universe selection data isn't ready yet.

### Examples

The following examples are typical filter functions you may want.

The most common use case is to select a lot of liquid stocks. With a fundamental universe filter, this is simple and fast. The following example selects the top most liquid 500 stocks over $10 per share. private IEnumerable<Symbol> FundamentalFilterFunction(IEnumerable<Fundamental> fundamental) { // Linq makes this a piece of cake; return (from f in fundamental where f.Price > 10 && f.DollarVolume > 10000000 orderby f.DollarVolume descending select f.Symbol).Take(500); } def FundamentalFilterFunction(self, fundamental: List[Fundamental]) -> List[Symbol]: filtered = [f for f in fundamental if f.Price > 10 and f.DollarVolume > 10000000] sortedByDollarVolume = sorted(filtered, key=lambda f: f.DollarVolume, reverse=True) return sortedByDollarVolume[:500] #### Example 2: Take 10 stocks above their 200-Day EMA and have more than$1B daily trading volume

Another common request is to filter the universe by a technical indicator, such as only picking stocks above their 200-day EMA. The Fundamental object has adjusted price and volume information, so you can do any price-related analysis.

ConcurrentDictionary<Symbol, SelectionData>
_stateData = new ConcurrentDictionary<Symbol, SelectionData>();

private IEnumerable<Symbol> FundamentalFilterFunction(IEnumerable<Fundamental> fundamental)
{
// Linq makes this a piece of cake;
return (from f in fundamental
let avg = _stateData.GetOrAdd(f.Symbol, sym => new SelectionData(200))
where f.Price > avg.Ema.Current.Value && f.DollarVolume > 1000000000
orderby f.DollarVolume descending
select f.Symbol).Take(10);
}
# setup state storage in initialize method
self.stateData = { }

def FundamentalFilterFunction(self, fundamental: List[Fundamental]) -> List[Symbol]:    # We are going to use a dictionary to refer the object that will keep the moving averages
for f in fundamental:        if f.Symbol not in self.stateData:
self.stateData[f.Symbol] = SelectionData(f.Symbol, 200)

# Updates the SymbolData object with current EOD price
avg = self.stateData[f.Symbol]

# Filter the values of the dict to those above EMA and more than \$1B vol.
values = [x for x in self.stateData.values() if x.is_above_ema and x.volume > 1000000000]

# sort by the largest in volume.
values.sort(key=lambda x: x.volume, reverse=True)

# we need to return only the symbol objects
return [ x.symbol for x in values[:10] ]

In this example, the SelectionData class group variables for the universe selection and updates the indicator of each asset. We highly recommend you follow this pattern to keep your algorithm tidy and bug free. The following snippet shows an example implementation of the SelectionData class, but you can make this whatever you need to store your custom universe filters.

class SelectionData(object):
def __init__(self, symbol, period):
self.symbol = symbol
self.ema = ExponentialMovingAverage(period)
self.is_above_ema = False
self.volume = 0

def update(self, time, price, volume):
self.volume = volume
if self.ema.Update(time, price):
self.is_above_ema = price > ema.Current.Value
// example selection data class
private class SelectionData
{
// variables you need for selection

// initialize your variables and indicators.
public SelectionData(int period)
{
Ema = new ExponentialMovingAverage(period);
}

// update your variables and indicators with the latest data.
// you may also want to use the History API here.
public bool Update(DateTime time, decimal value)
{
return Ema.Update(time, value);
}
}

Note that the preceding SelectionData class uses a manual EMA indicator instead of the automatic version. For more information about universes that select assets based on indicators, see Indicator Universes. You need to use a SelectionData class instead of assigning the EMA to the Fundamental object because you can't create custom propertiesattributes on Fundamental objects like you can with Security objects.

#### Example 3: Take 10 stocks that are the furthest above their 10-day SMA of volume

The process to get the 10-day SMA stock volume is the same process as in Example 2. First, you should define a SelectionData class that performs the averaging. For this example, the following class will serve this purpose:

class SelectionData(object):
def __init__(self, symbol, period):
self.symbol = symbol
self.volume = 0
self.volume_ratio = 0
self.sma = SimpleMovingAverage(period)

def update(self, time, price, volume):
self.volume = volume
if self.sma.Update(time, volume):
# get ratio of this volume bar vs previous 10 before it.
self.volume_ratio = volume / self.sma.Current.Value
private class SelectionData
{
public decimal VolumeRatio;
public SelectionData(Symbol symbol, int period)
{
Symbol = symbol;
VolumeSma = new SimpleMovingAverage(period);
}
public bool Update(DateTime time, decimal value)
{
VolumeRatio = value / VolumeSma.Current.Value;
}
}

This class tracks the ratio of today's volume relative to historical volumes. You can use this ratio to select assets that are above their 10-day simple moving average and sort the results by the ones that have had the biggest jump since yesterday.

def FundamentalFilterFunction(self, fundamental: List[Fundamental]) -> List[Symbol]:
for f in fundamental:        if f.Symbol not in self.stateData:
self.stateData[f.Symbol] = SelectionData(f.Symbol, 10)
avg = self.stateData[f.Symbol]

# filter the values of selectionData(sd) above SMA
values = [sd for sd in self.stateData.values() if sd.volume_ratio > 1]

# sort sd by the largest % jump in volume.
values.sort(key=lambda sd: sd.volume_ratio, reverse=True)

# return the top 10 symbol objects
return [ sd.symbol for sd in values[:10] ]


private IEnumerable<Symbol> FundamentalFilterFunction(IEnumerable<Fundamental> fundamental) {
return (from f in fundamental
let avg = _stateData.GetOrAdd(f.Symbol, sym => new SelectionData(10))
where avg.Update(f.EndTime, f.Volume)
where avg.VolumeRatio > 1
orderby avg.VolumeRatio descending
select f.Symbol).Take(10);
}

#### Example 4: Take the top 10 "fastest moving" stocks with a 50-Day EMA > 200 Day EMA

You can construct complex universe filters with the SelectionData helper class pattern. To view a full example of this algorithm, see the EmaCrossUniverseSelectionAlgorithmEmaCrossUniverseSelectionAlgorithm in the LEAN GitHub repository or take the related Boot Camp lesson.

#### Example 5: Piotroski F-Score

To view this example, see the Piotroski F-Score Investing Research post.

You can also see our Videos. You can also get in touch with us via Discord.