book
Checkout our new book! Hands on AI Trading with Python, QuantConnect, and AWS Learn More arrow

Indicators

Automatic Indicators

Introduction

Automatic indicators are indicators that automatically update from the underlying security data. Automatic indicators do everything that manual indicators do, but with automatic updates registered for you.

Naming Convention

The method to create an automatic indicator is usually named after the acronym of the indicator name. For example, to create an automatic simple moving average indicator, use the sma method.

Create Automatic Indicators

To create automatic indicators, call the indicator helper method from the QCAlgorithm class. The indicator helper methods create an indicator object, hooks it up for automatic updates, and returns it so you can used it in your algorithm. To view the helper method for each indicator, see Supported Indicators. In most cases, you should call the helper method in the initialize method.

The indicator resolution must be greater than or equal to the resolution of the security subscription. For instance, if your security subscription is for minute resolution data, the indicator resolution should be minute, hour, or daily resolution.

Select Language:
# In Initialize()
symbol = self.add_equity("SPY").symbol

#  - Create an indicator
self._sma = self.sma(symbol, 20, Resolution.DAILY)

#  - Create a candlestick pattern
patterns = CandlestickPatterns(self)
self.two_crows = patterns.two_crows(self._symbol)

When you create an indicator with a helper method, the indicator is given a default name. You can track indicators by their name. The default name for the SimpleMovingAverage indicator is "sma(period,ticker_resolution)". For example, in the preceding code snippet, the SimpleMovingAverage indicator is named "sma(20,SPY_day)". To get the name of an indicator, inspect its name property.

Select Language:
self.log(self.sma.name)
self.log(self.two_crows.name)

Alternative Price Fields

Data point indicators use only a single price data in their calculations. By default, those indicators use the closing price. For assets with TradeBar data, that price is the TradeBar close price. For assets with QuoteBar data, that price is the mid-price of the bid closing price and the ask closing price. To create an indicator with the other fields like the OPEN, HIGH, LOW, or CLOSE, provide a selector argument to the indicator helper method.

Select Language:
# Define a 10-period daily RSI indicator with shortcut helper method
# Select the Open price to update the indicator
self._rsi = self.rsi("SPY", 10,  MovingAverageType.SIMPLE, Resolution.DAILY, Field.OPEN)

The Field class has the following selector properties:

Warm Up Indicators

Indicators compute their value based on historical data. Before you start trading with an indicator, warm it up. There are several ways to warm-up automatic indicators.

Algorithm Warm-up

You can set an algorithm warm-up period to warm up the indicators. When you set an algorithm warm-up period, the engine pumps data in and automatically updates all the indicators from before the start date. To ensure that all the indicators are ready after the algorithm warm-up period, choose a look-back period that contains sufficient data.

Select Language:
# In Initialize
symbol = self.add_equity("SPY").symbol
self._sma = self.sma(symbol, 20, Resolution.DAILY)
self.set_warm_up(20, Resolution.DAILY)

# In OnData
if self.is_warming_up:
    return

Manual Indicator Warm-up

You can manually warm up indicators with a history request.

Select Language:
# In Initialize
symbol = self.add_equity("SPY").symbol
self._sma = self.sma(symbol, 20, Resolution.DAILY)

history = self.history(symbol, 20, Resolution.DAILY)
if not history.empty:
    for time, row in history.loc[symbol].iterrows():
        self._sma.update(time, row.close)

Automatic Indicator Warm-up

You can set the self.settings.automatic_indicator_warm_up property to true before you create most indicators to automatically warm them up. This technique doesn't work for all indicators.

Select Language:
# In Initialize
symbol = self.add_equity("SPY").symbol
self.settings.automatic_indicator_warm_up = True
self._sma = self.sma(symbol, 20, Resolution.DAILY)

Warm-up Helper Method

If an indicator inherits the IIndicatorWarmUpPeriodProvider class, you can warm it up with the warm_up_indicator method.

Select Language:
self._sma = self.sma(self._symbol, 20)
self.warm_up_indicator(self._symbol, self._sma)

To warm up the indicator with a resolution that's different from the security resolution, pass a resolution or timedelta argument to the warm_up_indicator method. The resolution you provide should be greater than or equal to the security resolution. For example, if the security has minute resolution data, you should warm up the indicator with data that spans at least one minute. If the indicator resolution is different from the security resolution, provide the indicator resolution as the argument to properly warm up the indicator.

Select Language:
# Warm up with daily bars
self.warm_up_indicator(self._symbol, self._sma, Resolution.DAILY)

# Warm up with 3-day bars
self.warm_up_indicator(self._symbol, self._sma, timedelta(days=3))

The warm_up_indicator method uses the default value of the historical data to warm up the indicator. In most cases, this is the closing price. To warm up the indicator with a different data field, pass a Field argument to the method.

Select Language:
self.warm_up_indicator(self._symbol, self._sma, Resolution.DAILY, Field.HIGH)

Some indicators require the prices of two assets to compute their value (for example, Beta). In this case, pass a list of the Symbol objects to the method.

Select Language:
self._spy = self.add_equity("SPY").symbol
self._aapl = self.add_equity('AAPL').symbol
self._beta = self.B(self._aapl, self._spy, 21, Resolution.DAILY)
self.warm_up_indicator([self._aapl, self._spy], self._beta, Resolution.DAILY)

Timing Considerations

In some cases, you might create and warm up the indicator during its sampling period. For example, say the security resolution is minute, the indicator resolution is daily, and you create and warm-up the indicator at noon without using the set_warm_up method. In this example, the history request that gathers data to warm up the indicator won't contain any data from the current day and the consolidator that updates the indicator also won't aggregate any data from before noon. It doesn't cause issues if the indicator only uses the close price to calculate the indicator value (like the simple moving average indicator) because the first consolidated bar that updates the indicator will have the correct close price. However, if the indicator uses more than just the close price to calculate its value (like the True Range indicator), the open, high, and low values of the first consolidated bar may be incorrect, causing the initial indicator values to be incorrect.

Deregister Indicators

To stop the automatic updates of an indicator, pass the indicator to the deregister_indicator property method.

Select Language:
self.deregister_indicator(self._sma)
# Alias:
# self.unregister_indicator(self._sma)

Common Mistakes

Avoid the following common mistakes when you use automatic indicators.

Using Indicator Values Before the Indicator Is Warmed Up

Indicators can provide inaccurate output values before they are warmed up. To avoid issues, always check the is_ready flag before you use indicator output values.

Select Language:
# is_ready signals whether the indicator values are accurate and ready to use.
if self.indicator.is_ready:
    value = self.indicator.current.value

Manually Registering an Automatic Indicator for Updates

If you create an automatic indicator and then register it for automatics updates or call the update method, the indicator receives multiple input values during each update cycle. To avoid issues, create automatic indicators but don't register them for automatic updates or call the update method.

Select Language:
# Automatic indicator short-cuts create the indicator and register it for data updates.
self.indicator = self.sma(self._symbol, 5)

# Don't register the automatic indicators for data. They automatically get data.
# self.register_indicator(self._symbol, self.indicator, Resolution.DAILY)

Examples

The following examples demonstrate some common practices for using automatic indicators.

Example 1: Trade With Automatic Indicators in a Dynamic Universe

The following algorithm selects a universe of the 20 most liquid US Equities each day. At the start of each trading session, it then forms an equal-weighted portfolio of the stocks that have price > EMA > SMA , which indicates an upward accelerating trend. As assets enter the universe, it creates automatic indicators for them. As assets leave the universe, it deregisters the indicators.

Select Language:
class AutomaticIndicatorAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2021, 1, 1)
        self.set_end_date(2021, 2, 1)

        # Add a universe of the 20 most liquid stocks to trade trends more efficiently.
        self._universe = self.add_universe(self.universe.dollar_volume.top(20))

        # Set a Scheduled Event to rebalance at the start of each day with the daily indicator signals.
        self.schedule.on(self.date_rules.every_day(), self.time_rules.at(9, 31), self._rebalance)
                
    def _rebalance(self) -> None:
        # Buy the stocks where price is above EMA and EMA is above SMA, meaning its trend is upward and accelerating.
        securities = [self.securities[symbol] for symbol in self._universe.selected]
        symbols_to_buy = [
            security.symbol for security in securities 
            if security.price > security.ema.current.value > security.sma.current.value
        ]

        # Equally invest in the selected stocks to evenly distribute the capital risk.
        count = len(symbols_to_buy)
        if count:
            targets = [PortfolioTarget(symbol, 1 / count) for symbol in symbols_to_buy]
            # Liquidate the positions that are no longer popular or in an uptrend.
            self.set_holdings(targets, liquidate_existing_holdings=True)

    def on_securities_changed(self, changes: SecurityChanges) -> None:
        for security in changes.added_securities:
            symbol = security.symbol
            # Create EMA & SMA indicators to generate trade signals. Use duck typing to save the indicator instances.
            security.ema = self.ema(symbol, 20, Resolution.DAILY)
            security.sma = self.sma(symbol, 20, Resolution.DAILY)

            # Warm up the indicators so they are ready to use immediately.
            self.warm_up_indicator(symbol, security.ema, Resolution.DAILY)
            self.warm_up_indicator(symbol, security.sma, Resolution.DAILY)

        for security in changes.removed_securities:
            # Stop updating the indicators of assets that leave the universe to release computation resources.
            self.deregister_indicator(security.ema)
            self.deregister_indicator(security.sma)

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: