Universes

Equity CFD

Introduction

An Equity CFD universe lets you select a set of Equity CFD assets. To select the underlying Equities, you can use a fundamental universe to select assets based on corporate fundamental data, an ETF constituents universe to select the CFD versions of stocks in an exchange-traded fund, or an alternative data universe to select assets based on alternative data. This feature is powerful for European clients seeking to trade US ETF products.

Only the Interactive Brokers CFD integration supports trading Stock-CFD products. QuantConnect doesn't have historical data for Interactive Brokers CFD products; however, you can use the LiveMode flag to swap to the CFD equivalents for live trading. In live trading, you must include Interactive Brokers as a data provider to trade Equity-CFD products.

Create Universes Using Fundamentals

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. In live mode, call the Symbol.Create method to swap for a CFD version of the same Symbol. Don't call AddCfd in the filter function.

public class MyUniverseAlgorithm : QCAlgorithm {
    private Universe _universe;
    public override void Initialize() 
    {
        UniverseSettings.Asynchronous = true;
        _universe = AddUniverse(FundamentalFilterFunction);
    }
        
    private IEnumerable<Symbol> FundamentalFilterFunction(IEnumerable<Fundamental> fundamental) 
    {
        var symbols = (from f in fundamental
                where f.HasFundamentalData
                select f.Symbol);

        if (LiveMode)
        {
            return symbols.Select(x => QuantConnect.Symbol.Create(x.Value, SecurityType.Cfd, Market.InteractiveBrokers));
        } 

        return symbols;
    }
}
class MyUniverseAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.universe_settings.asynchronous = True
        self.universe = self.add_universe(self.fundamental_function)
    
    def fundamental_function(self, fundamental: List[Fundamental]) -> List[Symbol]:
        symbols = [c.symbol for c in fundamental if c.has_fundamental_data]
        if self.live_mode:
            return [Symbol.create(x.value, SecurityType.CFD, Market.INTERACTIVE_BROKERS) for x in symbols]
        return symbols

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
UniverseSettings.Asynchronous = true;
_universe = AddUniverse(
    fundamental =>
    {
        var symbols = (from f in fundamental
            where f.Price > 10 && f.HasFundamentalData && !Double.IsNaN(f.ValuationRatios.PERatio)
            orderby f.DollarVolume descending
            select f).Take(100)
            .OrderBy(f => f.ValuationRatios.PERatio).Take(10)
            .Select(f => f.Symbol);
                
        if (LiveMode)
        {
            return symbols.Select(x => QuantConnect.Symbol.Create(x.Value, SecurityType.Cfd, Market.InteractiveBrokers));
        }
        
        return symbols;
    });
# In Initialize:
self.universe_settings.asynchronous = True
self.universe = self.add_universe(self.fundamental_selection_function)
    
def fundamental_selection_function(self, fundamental: List[Fundamental]) -> List[Symbol]:
    filtered = [f for f in fundamental if f.price > 10 and f.has_fundamental_data and not np.isnan(f.valuation_ratios.pe_ratio)]
    sorted_by_dollar_volume = sorted(filtered, key=lambda f: f.dollar_volume, reverse=True)[:100]
    sorted_by_pe_ratio = sorted(sorted_by_dollar_volume, key=lambda f: f.valuation_ratios.pe_ratio, reverse=False)[:10]
    symbols = [f.symbol for f in sorted_by_pe_ratio]
    if self.live_mode:
        return [Symbol.create(x.value, SecurityType.CFD, Market.INTERACTIVE_BROKERS) for x in symbols]
    return symbols

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.

Create Universes using ETF Constituents

To add an ETF Constituents universe, in the Initialize method, call the Universe.ETF method with a filter function, and pass it to the AddUniverse method. The filter function receives a list of ETFConstituentUniverse 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. In live mode, call the Symbol.Create method to swap for a CFD version of the same Symbol. Don't call AddCfd in the filter function.

public class MyUniverseAlgorithm : QCAlgorithm {
    private Universe _universe;
    public override void Initialize() 
    {
        UniverseSettings.Asynchronous = true;
        _universe = Universe.ETF("SPY", UniverseSettings, ETFConstituentsFilter);
        AddUniverse(_universe);
    }
        
    private IEnumerable<Symbol> ETFConstituentsFilter(IEnumerable<ETFConstituentUniverse> constituents)
    {
        // Get the 10 securities with the largest weight in the index
        var symbols = constituents.OrderByDescending(c => c.Weight).Take(10).Select(c => c.Symbol);
        if (LiveMode)
        {
            return symbols.Select(x => QuantConnect.Symbol.Create(x.Value, SecurityType.Cfd, Market.InteractiveBrokers));
        }
        
        return symbols;
    }
}
class MyUniverseAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.universe_settings.asynchronous = True
        self.universe = self.universe.etf("SPY", self.universe_settings, self.etf_constituents_filter)
        self.add_universe(self.universe)
    
    def etf_constituents_filter(self, constituents: List[ETFConstituentUniverse]) -> List[Symbol]:
        # Get the 10 securities with the largest weight in the index
        selected = sorted([c for c in constituents if c.weight], key=lambda c: c.weight, reverse=True)[:10]
        symbols = [c.symbol for c in selected]
        if self.live_mode:
            return [Symbol.create(x.value, SecurityType.CFD, Market.INTERACTIVE_BROKERS) for x in symbols]
        return symbols

Selection Frequency

Equity universes run on a daily basis by default. To adjust the selection schedule, see Schedule.

Live Trading Considerations

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

You can adapt the examples of the Universes > Equity section of this documentation.

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: