Universes

Key Concepts

Introduction

Universe selection is the process of selecting a basket of assets you may trade. Dynamic universe selection increase diversification and decrease selection bias in your algorithm.

How Universe Selection Works

When you add a universe to your algorithm, LEAN sends a large dataset into a filter function you define. Your filter function needs to return a list of Symbol objects. LEAN automatically subscribes to these new symbols and adds them to your algorithm. Your algorithm can do almost anything inside your filter functions, but the goal should be to narrow down the set of securities to the securities that are most applicable for your algorithm.

Selection Functions

The following example filter function selects the 100 most liquid US Equities.

public class MyFundamentalUniverseAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        UniverseSettings.Asynchronous = true;
        AddUniverse(FundamentalFilterFunction);
    }

    private IEnumerable<Symbol> FundamentalFilterFunction(IEnumerable<Fundamental> fundamental)
    {
        return (from c in fundamental
            orderby c.DollarVolume descending
            select c.Symbol).Take(100);
    }
}
class MyFundamentalUniverseAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.universe_settings.asynchronous = True
        self.add_universe(self.fundamental_filter_function)

    def fundamental_filter_function(self, fundamental: List[Fundamental]) -> List[Symbol]:
        sorted_by_dollar_volume = sorted(fundamental, key=lambda x: x.dollar_volume, reverse=True) 
        return [c.symbol for c in sorted_by_dollar_volume[:100]]

To learn how to define filter functions for other asset classes, custom data universes, or alternative data universes, see the following pages in this Universes chapter.

Security Changed Events

When your universe adds and removes assets, LEAN notifies your algorithm through the OnSecuritiesChangedon_securities_changed event handler. The event handler receives a SecurityChanges object, which contains references to the added and removed securities. To access the added securities, check the changes.AddedSecurities property. To access the removed securities, check the changes.RemovedSecurities property.

public override void OnSecuritiesChanged(SecurityChanges changes)
{
    foreach (var security in changes.AddedSecurities)
    {
        Debug($"{Time}: Added {security.Symbol}");
    }
    foreach (var security in changes.RemovedSecurities)
    {
        Debug($"{Time}: Removed {security.Symbol}");
        
        if (security.Invested)
        {
            Liquidate(security.Symbol, "Removed from Universe");
        }
    }
}
def on_securities_changed(self, changes: SecurityChanges) -> None:
    for security in changes.added_securities:
        self.debug(f"{self.time}: Added {security.symbol}")

    for security in changes.removed_securities:
        self.debug(f"{self.time}: Removed {security.symbol}")
        
        if security.invested:
            self.liquidate(security.symbol, "Removed from Universe")

The preceding example liquidates securities that leave the universe. In this case, LEAN creates a market on open order and frees up buying power when the market opens.

A convenient way to track the securities that are currently in the universe is to use the NotifiedSecurityChanges class.

A convenient way to track the securities that are currently in the universe is to maintain a self._securities list.

private readonly HashSet<Security> _securities = new();

public override void OnSecuritiesChanged(SecurityChanges changes)
{
    NotifiedSecurityChanges.UpdateCollection(_securities, changes);
}
# In Initialize
self._securities = []

def on_securities_changed(self, changes: SecurityChanges) -> None:
    for security in changes.removed_securities:
        if security in self.securities:
            self._securities.remove(security)
            
    self._securities.extend(changes.added_securities)

Custom Security Properties

If you need to save data or create objects for each security in the universe, add custom members to the respective Security objectscast the Security objects to dynamic objects and then save custom members to them. This technique is useful if you want to track stop loss levels or add indicators for each asset in the universe.

public override void OnSecuritiesChanged(SecurityChanges changes)
{
    foreach (var security in changes.AddedSecurities)
    {
        var dynamicSecurity = security as dynamic;

        // Create an indicator
        dynamicSecurity.Indicator = SMA(security.Symbol, 10);

        // Warm up the indicator
        WarmUpIndicator(security.Symbol, dynamicSecurity.Indicator);
    }

    foreach (var security in changes.RemovedSecurities)
    {
        DeregisterIndicator((security as dynamic).Indicator);
    }
}
def OnSecuritiesChanged(self, changes: SecurityChanges) -> None:
    for security in changes.AddedSecurities:
        # Create an indicator
        security.indicator = self.sma(security.Symbol, 10)

        # Warm up the indicator
        self.WarmUpIndicator(security.Symbol, security.indicator)

    for security in changes.RemovedSecurities:
        self.DeregisterIndicator(security.indicator)

Select Current Constituents

If you don't want to make any changes to the current universe, return Universe.Unchanged from your filter functions.

public class MyUniverseAlgorithm : QCAlgorithm 
{
    public override void Initialize()
    {
        UniverseSettings.Asynchronous = true;
        AddUniverse(MyFundamentalFilterFunction);
    }

    IEnumerable<Symbol> MyFundamentalFilterFunction(IEnumerable<Fundamental> fundamental) 
    {
        return Universe.Unchanged;
    }
}
class MyUniverseAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.universe_settings.asynchronous = True
        self.add_universe(self.my_fundamental_filter_function)

    def my_fundamental_filter_function(self, fundamental: List[Fundamental]) -> List[Symbol]:
        return Universe.UNCHANGED

Universe Manager

The universe manager tracks all the universes in your algorithm. If you add multiple universe, you can access the constituents of each individual universe. To access the constituents of a universe in a multi-universe algorithm, save references to each universe when you add them.

private Universe _universe;

// In Initialize
UniverseSettings.Asynchronous = true;
_universe = AddUniverse(MyFundamentalFilterFunction);

// In OnData
var universeMembers = UniverseManager[_universe.Configuration.Symbol].Members;
foreach (var kvp in universeMembers)
{
    var symbol = kvp.Key;
    var security = kvp.Value;
}
# In Initialize
self.universe_settings.asynchronous = True
self._universe = self.add_universe(self.my_fundamental_filter_function)

# In OnData
universe_members = self.universe_manager[self.universe.configuration.symbol].members
for kvp in universe_members:
    symbol = kvp.key
    security = kvp.value

When you remove an asset from a universe, LEAN usually removes the security from the Members collection and removes the security subscription. However, it won't remove the security in any of the following situations:

  • You own the security.
  • You have an open order for the security.
  • The security wasn't in the universe long enough to meet the MinimumTimeInUniverseminimum_time_in_universe setting.

To get only the assets that are currently in the universe, see Selected Securities.

Active Securities

The ActiveSecuritiesactive_securities property of the algorithm class contains all of the assets currently in your algorithm. It is a dictionary where the key is a Symbol and the value is a Security. When you remove an asset from a universe, LEAN usually removes the security from the ActiveSecuritiesactive_securities collection and removes the security subscription. However, it won't remove the security in any of the following situations:

  • You own the security.
  • You have an open order for the security.
  • The security wasn't in the universe long enough to meet the MinimumTimeInUniverseminimum_time_in_universe setting.

When LEAN removes the security, the Security object remains in the Securitiessecurities collection for record-keeping purposes, like tracking fees and trading volume.

To get only the assets that are currently in the universe, see Selected Securities.

Selected Securities

The Selected property of your Universe contains references to all the assets that are currently in the universe. The Universe.Selected property differs from the Universe.Members property because the Universe.Members property can contain more assets than Universe.Selected. The QCAlgorithm.ActiveSecurities is a collection of Universe.Members of all universes. To access the Universe object, save a reference to the result of the AddUniverseadd_universe method. The following algorithm demonstrates how to use the Universe.Selected property to create simple rebalancing strategies:

public class SimpleRebalancingAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        var symbol = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
        var dateRule = DateRules.WeekStart(symbol);
        UniverseSettings.Schedule.On(dateRule);
        var universe = AddUniverse(Universe.DollarVolume.Top(5));
        Schedule.On(
            dateRule,
            TimeRules.AfterMarketOpen(symbol, 30),
            () => SetHoldings(
                universe.Selected.Select(symbol => new PortfolioTarget(symbol, 1.0m/universe.Selected.Count)).ToList(),
                true
            )
        );
    }
}
class SimpleRebalancingAlgorithm(QCAlgorithm):

    def initialize(self):
        symbol = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
        date_rule = self.date_rules.week_start(symbol)
        self.universe_settings.schedule.on(date_rule)
        universe = self.add_universe(self.universe.dollar_volume.top(5))
        self.schedule.on(
            date_rule,
            self.time_rules.after_market_open(symbol, 30),
            lambda: self.set_holdings(
                [PortfolioTarget(symbol, 1/len(universe.selected)) for symbol in universe.selected], 
                True
            )
        )

Derivative Universes

In a regular universe, you select a basket of assets from the entire universe of securities. In a derivative universe, you select a basket of contracts for an underlying asset. The following derivative universes are available:

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

Did you find this page helpful?

Contribute to the documentation: