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
live_mode
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
initialize
method, pass a filter function to the AddUniverse
add_universe
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
Symbol.create
method to swap for a CFD version of the same Symbol
. Don't call AddCfd
add_cfd
in the filter function.
// Create a universe for CFD securities based on fundamental data. public class MyUniverseAlgorithm : QCAlgorithm { private Universe _universe; public override void Initialize() { UniverseSettings.Asynchronous = true; // Pass the filter function as an argument to the AddUniverse method. _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; } }
# Create a universe for CFD securities based on fundamental data. class MyUniverseAlgorithm(QCAlgorithm): def initialize(self) -> None: self.universe_settings.asynchronous = True # Pass the filter function as an argument to the AddUniverse method. 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.
// Select the top 50 by dollar volume and then select the top 10 by their PE ratio. 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; });
# Select the top 50 by dollar volume and then select the top 10 by their PE ratio. 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
initialize
method, call the Universe.ETF
universe.etf
method with a filter function, and pass it to the AddUniverse
add_universe
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
Symbol.create
method to swap for a CFD version of the same Symbol
. Don't call AddCfd
add_cfd
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.