Securities
Requesting Data
Introduction
When you add a security to your algorithm, your algorithm creates a data subscription and receives data updates for that security or custom data source.
Add Assets
To create an Equity subscription, call the add_equity
method and pass the ticker
argument. The ticker
argument represents the current ticker.
# Add the SPY ETF. equity = self.add_equity("SPY")
The add_equity
method creates a subscription for a single Equity asset and adds it to your user-defined universe.
For more information about adding assets, see Asset Classes.
Add Universes
Universe selection is the process of selecting a basket of assets you may trade. When you add a universe to your algorithm, LEAN sends a large dataset into a filter function you define. LEAN automatically subscribes to these new assets and adds them to your algorithm.
# Use the _fundamental_filter_function to add the 100 most liquid stocks to the universe. class MyFundamentalUniverseAlgorithm(QCAlgorithm): def initialize(self) -> None: self.universe_settings.asynchronous = True self.add_universe(self._fundamental_filter_function) # Get the top 100 stocks by dollar volume. 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]]
For more information about universes, see Universes.
Resolutions
Resolution is the duration of time that's used to sample a data source. Market data is sampled and saved in disk with five resolutions. The Resolution
enumeration has the following members:
Resolution.TICK
Resolution.SECOND
Resolution.MINUTE
Resolution.HOUR
Resolution.DAILY
For more information about the resolutions of each asset class, follow these steps:
- Open the Asset Classes documentation.
- Click an asset class.
- Click .
- Scroll down to the Resolutions section.
You can subscribe to daily resolution for an asset for updating indicator and subscribe to another asset for denser resolution for trading using the indicator.
def initialize(self): self.add_equity("VIX", Resolution.DAILY) self.add_equity("SPY", Resolution.MINUTE)
To get data with multiple or customizable resolutions for an asset, use consolidators.
Fill Forward
Fill forward means if there is no data point for the current slice, LEAN uses the previous data point. Fill forward is the default data setting. If you disable fill forward, you may get stale fills or you may see trade volume as zero.
For more information about how to enable and disable fill forward for each asset class, follow these steps:
- Open the Asset Classes documentation.
- Click an asset class.
- Click .
- Scroll down to the Fill Forward section.
Example: Disable Fill Forward Data
For some illiquid securities or alternative data, using forward filled data might not be an accurate estimation nor usable information. To avoid this, disable fill forward.
def initialize(self): self.add_data(BrainSentiment7Days, symbol, fill_forward=False)
Security Changed Events
When you add and remove assets, LEAN notifies your algorithm through the on_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, iterate the changes.added_securities
property. To get the removed securities, iterate the changes.removed_securities
property.
# Use on_securities_changed to know when an asset is added or removed. def on_securities_changed(self, changes: SecurityChanges) -> None: # Iterate through the added assets. for security in changes.added_securities: self.debug(f"{self.time}: Added {security.symbol}") # Iterate through the removed assets. 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. You can use this event to create indicators when a new security enters the universe.
Examples
The following examples demonstrate some common practices on the subject of requesting data.
Example 1: Add Linked Alternative Data for Universe Constituents
Many traders select universe constituents and then allocate positions with two independent sets of logic.
Position sizing usually requires additional information, like alternative data factors.
To manage alternative data subscriptions for all the universe constituents, subscribe and unsubscribe from the data in the
on_securities_changed
method.
The following example demonstrates adds the
KavoutCompositeFactorBundle
when assets enter the universe.
class RequestSecuritiesDataAlgorithm(QCAlgorithm): def initialize(self) -> None: # Add a universe of the 10 most liquid US Equities. self.add_universe(self.universe.dollar_volume.top(10)) def on_data(self, slice: Slice) -> None: # Invest by the updated Kavout Factor data. factor_data = slice.get(KavoutCompositeFactorBundle) if factor_data: sorted_by_factor_score = sorted(factor_data.items(), key=lambda x: x[1].growth + x[1].value_factor + x[1].quality + x[1].momentum + x[1].low_volatility, reverse=True)[:10] top_factor_targets = [PortfolioTarget(x[0].underlying, 0.1) for x in sorted_by_factor_score] self.set_holdings(top_factor_targets) def on_securities_changed(self, changes: SecurityChanges) -> None: # Iterate securities that entered the universe. for security in changes.added_securities: # Subscribe to the factor data for the new security. # Save the alternative data symbol in the security object. security.alt_data_symbol = self.add_data(KavoutCompositeFactorBundle, security.symbol, Resolution.DAILY).symbol # Iterate securities that left the universe. for security in changes.removed_securities: # Unsubscribe from the altnerative data updates. self.remove_security(security.alt_data_symbol)
Example 2: Add Linked Custom Data
QuantConnect Cloud has a lot of data, but not everything. To import some external data into your algorithm, define a custom data source . The following algorithm loads Bitstamp's BTCUSD trading activity from a CSV file and plots it:
# Define the algorithm. class LinkedCustomDataExampleAlgorithm(QCAlgorithm): def initialize(self): self.set_start_date(2011, 9, 13) self.set_end_date(2021, 6, 20) # Add Bitcoin and the custom dataset. btc = self.add_crypto('BTCUSD') btc.data_symbol = self.add_data(Bitstamp, btc.symbol.value, Resolution.DAILY).symbol # Plot the price from the custom dataset. self.plot_indicator('BTC Price', self.identity(btc.data_symbol)) # Define the custom data source. class Bitstamp(PythonData): # Define the get_source method to load the data from its location. def get_source(self, config, date, is_live_mode): source = "https://raw.githubusercontent.com/QuantConnect/Documentation/master/Resources/datasets/custom-data/bitstampusd.csv" # REMOTE_FILE in the next line means the data file in online storage. return SubscriptionDataSource(source, SubscriptionTransportMedium.REMOTE_FILE) # Define the reader method to parse the CSV rows. def reader(self, config, line, date, is_live_mode): # Ignore empty rows. if not line.strip(): return None # Instantiate a new data object. coin = Bitstamp() coin.symbol = config.symbol # Ignore non-numeric lines. if not line[0].isdigit(): return None # Split the CSV row by its commas. data = line.split(',') # Ignore invalid data. coin.value = float(data[4]) if coin.value == 0: return None # Parse the row. coin.time = datetime.strptime(data[0], "%Y-%m-%d") coin.end_time = coin.time + timedelta(1) coin["Open"] = float(data[1]) coin["High"] = float(data[2]) coin["Low"] = float(data[3]) coin["Close"] = coin.value coin["VolumeBTC"] = float(data[5]) coin["VolumeUSD"] = float(data[6]) coin["WeightedPrice"] = float(data[7]) return coin