🚀 AI One-Click Generation of quantconnect Strategy Code

How to Add Indicators like Bollinger Bands, RSI, and MACD in QuantConnect

quantconnect | Published on: 2025/12/2
The following content is generated by EasyQuant .

Problem Description

How do I add a Bollinger Band indicator to my trading algorithm?

Solution

To add a Bollinger Band indicator in QuantConnect using the Python API, you use the self.bb helper method within the initialize function.

Here is a complete, runnable example of a Mean Reversion strategy using Bollinger Bands.

Bollinger Band Strategy Implementation

# region imports
from AlgorithmImports import *
# endregion

class BollingerBandAlgorithm(QCAlgorithm):

    def initialize(self):
        # 1. Set Setup parameters
        self.set_start_date(2023, 1, 1)
        self.set_end_date(2024, 1, 1)
        self.set_cash(100000)

        # 2. Add Security
        self.symbol = self.add_equity("SPY", Resolution.DAILY).symbol

        # 3. Create the Bollinger Band Indicator
        # Parameters: Symbol, Period, k (StdDev multiplier), MovingAverageType, Resolution
        self.bollinger = self.bb(self.symbol, 20, 2, MovingAverageType.SIMPLE, Resolution.DAILY)

        # 4. Set WarmUp to ensure indicator is ready immediately upon start
        self.set_warm_up(20)

    def on_data(self, data: Slice):
        # Ensure data exists for the symbol and indicator is ready
        if not self.bollinger.is_ready or self.symbol not in data:
            return

        # 5. Access Indicator Values
        # The main .current.value is the Middle Band (Moving Average)
        middle_band = self.bollinger.current.value
        
        # Access Upper and Lower bands specifically
        upper_band = self.bollinger.upper_band.current.value
        lower_band = self.bollinger.lower_band.current.value
        
        current_price = self.securities[self.symbol].price

        # 6. Trading Logic (Mean Reversion)
        
        # If not invested, check for entry signals
        if not self.portfolio.invested:
            # Buy if price drops below the lower band (oversold)
            if current_price < lower_band:
                self.set_holdings(self.symbol, 1.0)
                self.debug(f"Buy at {current_price} | Lower Band: {lower_band}")

        # If invested, check for exit signals
        else:
            # Sell if price rises above the upper band (overbought)
            if current_price > upper_band:
                self.liquidate(self.symbol)
                self.debug(f"Sell at {current_price} | Upper Band: {upper_band}")

        # Optional: Plotting for visual debugging
        self.plot("Trade Plot", "Price", current_price)
        self.plot("Trade Plot", "Upper", upper_band)
        self.plot("Trade Plot", "Lower", lower_band)

Key Implementation Details

  1. Creation (self.bb):
    The method signature is self.bb(symbol, period, k, moving_average_type, resolution).

    • period: The lookback period for the moving average (standard is 20).
    • k: The number of standard deviations for the bands (standard is 2).
    • moving_average_type: Usually MovingAverageType.SIMPLE or MovingAverageType.EXPONENTIAL.
  2. Accessing Values:
    The Bollinger Band object is a composite indicator.

    • self.bollinger.current.value: Returns the Middle Band value.
    • self.bollinger.upper_band.current.value: Returns the Upper Band value.
    • self.bollinger.lower_band.current.value: Returns the Lower Band value.
  3. Warm Up:
    Using self.set_warm_up(20) ensures that the algorithm processes historical data before the start date so the indicator is ready to use immediately on the first day of the backtest.


Q&A: Common Questions about Bollinger Bands in QuantConnect

Q: How do I use an Exponential Moving Average (EMA) for the middle band instead of Simple?
A: Change the MovingAverageType parameter in the initialization:

self.bollinger = self.bb(self.symbol, 20, 2, MovingAverageType.EXPONENTIAL, Resolution.DAILY)

Q: How can I get historical values of the Bollinger Bands (e.g., yesterday's value)?
A: You can use the Window functionality of indicators.

  1. In initialize: self.bollinger.window.size = 2
  2. In on_data: Access yesterday's upper band via self.bollinger.upper_band[1]. Note that index 0 is current, and 1 is the previous bar.

Q: Can I manually update the indicator with data from a different source?
A: Yes. If you are not using the helper self.bb method (which auto-updates), you can instantiate the class BollingerBands manually and call self.bollinger.update(time, price) inside on_data. However, the helper method used in the example above is recommended for standard equity/forex data.

Q: Why is self.bollinger.is_ready returning False?
A: The indicator requires at least period amount of data points to calculate the first value. If you set the period to 20, the indicator will not be ready until it has received 20 bars of data. Using self.set_warm_up(20) resolves this for the start of the simulation.