🚀 AI One-Click Generation of quantconnect Strategy Code

How to Combine Daily and Minute Data in Your QuantConnect Trading Strategy

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

Problem Description

How can I use daily data for signals and minute data for execution in my algorithm?

Solution

To use daily data for signals and minute data for execution in QuantConnect, you should follow this architectural pattern:

  1. Subscribe to Minute Resolution: Set your asset subscription to Resolution.MINUTE. This ensures your on_data method triggers every minute, allowing for precise execution.
  2. Create a Consolidator: Use a TradeBarConsolidator to aggregate the minute bars into daily bars.
  3. Register Indicators to the Consolidator: Attach your indicators (e.g., SMA, RSI) to the daily consolidator. This ensures the indicators only update once a day using the aggregated daily data, rather than every minute.

Strategy Example

The following algorithm demonstrates this approach. It calculates a 20-day Simple Moving Average (SMA) using Daily bars but checks for entry/exit conditions and executes trades using Minute bars.

# region imports
from AlgorithmImports import *
# endregion

class DailySignalMinuteExecution(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2023, 1, 1)
        self.set_end_date(2023, 12, 1)
        self.set_cash(100000)

        # 1. Subscribe to the asset with Minute resolution for execution
        self.symbol = self.add_equity("SPY", Resolution.MINUTE).symbol

        # 2. Define the indicator (Empty at first)
        self.sma_daily = SimpleMovingAverage(20)

        # 3. Create a Consolidator to aggregate Minute data into Daily data
        # This creates a bar representing 1 day of data
        daily_consolidator = TradeBarConsolidator(timedelta(days=1))

        # 4. Bind an event handler to the consolidator (Optional, for logging/debugging)
        daily_consolidator.data_consolidated += self.on_daily_bar_close

        # 5. Register the indicator to the consolidator
        # This ensures the SMA only updates when a full Daily bar is formed
        self.register_indicator(self.symbol, self.sma_daily, daily_consolidator)

        # 6. Add the consolidator to the subscription manager
        self.subscription_manager.add_consolidator(self.symbol, daily_consolidator)

        # Warm up the indicator using historical daily data
        self.warm_up_indicator(self.symbol, self.sma_daily, Resolution.DAILY)

    def on_data(self, data: Slice):
        """
        This runs every MINUTE. We use this for execution logic.
        """
        if not self.sma_daily.is_ready or self.symbol not in data:
            return

        # Get current minute price
        current_price = data[self.symbol].close
        
        # Get the latest daily indicator value
        daily_sma_value = self.sma_daily.current.value

        # Execution Logic:
        # We are comparing the Minute price against the Daily SMA
        if not self.portfolio.invested:
            if current_price > daily_sma_value:
                self.set_holdings(self.symbol, 1.0)
                self.debug(f"BUY at {self.time} | Price: {current_price} | Daily SMA: {daily_sma_value}")
        
        elif self.portfolio.invested:
            if current_price < daily_sma_value:
                self.liquidate(self.symbol)
                self.debug(f"SELL at {self.time} | Price: {current_price} | Daily SMA: {daily_sma_value}")

    def on_daily_bar_close(self, sender, bar):
        """
        This runs once a DAY when the daily bar is consolidated.
        Useful for logging or resetting daily variables.
        """
        self.plot("Indicators", "Daily SMA", self.sma_daily.current.value)

Key Components Explained

  1. self.add_equity(..., Resolution.MINUTE):
    This is the most critical step. By setting the resolution to Minute, the LEAN engine feeds data to on_data every minute. If you set this to Daily, you would not be able to execute intraday.

  2. TradeBarConsolidator(timedelta(days=1)):
    This object takes the stream of minute bars and "glues" them together. It waits until 24 hours (or a trading day) have passed, creates a single TradeBar, and then releases it.

  3. self.register_indicator(...):
    Standard indicators in QuantConnect update automatically with the data resolution of the security. By explicitly registering the indicator to the daily_consolidator, we force the indicator to ignore the raw minute stream and only update when the consolidator produces a daily bar.

  4. self.warm_up_indicator(...):
    Since the indicator needs 20 days of data to be ready, and we are running on minute resolution, waiting for 20 days of minute data to consolidate would take too long in a live scenario. This helper function fetches historical daily data immediately to prime the indicator.

Q&A

Q: Can I use self.history instead of consolidators?
A: Yes. You can request self.history(self.symbol, 20, Resolution.DAILY) inside on_data or a Scheduled Event. However, using Consolidators is generally more efficient computationally than requesting a history dataframe every single minute.

Q: Does the daily bar close at market close or midnight?
A: The timedelta(days=1) consolidator typically creates bars based on a 24-hour period. If you specifically need the bar to close exactly at Market Close (e.g., 4:00 PM ET), you should use the self.consolidate helper with a calendar rule, or a ScheduledEvent to sample the data at that specific time.

Q: Can I mix resolutions for different assets?
A: Yes. You can have SPY on Minute resolution and AAPL on Daily resolution in the same algorithm. However, on_data will trigger based on the finest resolution available (Minute).