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

Consolidating Data

Consolidator History

Introduction

This page explains how to save and access historical consolidated bars.

Save Consolidated Bars

To access historical bars that were passed to your consolidation handler, save the bars as you receive them. You can use a RollingWindow to save the consolidated bars and easily access them later on in your algorithm.

Select Language:
# Create a class member to store the RollingWindow
self._window = RollingWindow[TradeBar](2)

# In the consolidation handler, add consolidated bars to the RollingWindow
def _consolidation_handler(self, sender: object, consolidated_bar: TradeBar) -> None:
    self._window.add(consolidated_bar)

Get Historical Bars

If you save consolidated bars in a RollingWindow, you can access them by indexing the RollingWindow. RollingWindow objects operate on a first-in, first-out process to allow for reverse list access semantics. Index 0 refers to the most recent item in the window and the largest index refers to the last item in the window.

Select Language:
most_recent_bar = self._window[0]
previous_bar = self._window[1]
oldest_bar = self._window[self._window.count-1]

To get the consolidated bar that was most recently removed from the RollingWindow, use the most_recently_removed property.

Select Language:
removed_bar = self._window.most_recently_removed

Examples

The following examples demonstrate some common practices for consolidator history.

Example 1: Price Action

The following algorithm trades breakout price action on the SPY five-minute trade bar. To do so, we must create a five-minute trade bar consolidator and a rolling window to hold 3 trade bars to check if the trade conditions are fulfilled.

Select Language:
class ConsolidatorHistoryAlgorithm(QCAlgorithm):
    # To hold 3 consolidated trade bars to identify a breakout pattern.
    windows = RollingWindow[TradeBar](3)

    def initialize(self) -> None:
        self.set_start_date(2021, 10, 1)
        self.set_end_date(2022, 1, 1)
        
        # Request SPY data for signal generation and trading.
        self.spy = self.add_equity("SPY", Resolution.MINUTE).symbol

        # The breakout is based on a 5-minute consolidated trade bar.
        consolidator = TradeBarConsolidator(timedelta(minutes=5))
        # Subscribe for automatically updating the consolidator with SPY data.
        self.subscription_manager.add_consolidator(self.spy, consolidator)
        # Add a consolidator handler to check that the breakout condition is fulfilled and traded.
        consolidator.data_consolidated += self.on_consolidated

        self.set_warm_up(timedelta(15))

    def on_consolidated(self, sender: object, bar: TradeBar) -> None:
        self.windows.add(bar)

        if self.windows.is_ready:
            # Buy if the breakout price action is fulfilled.
            # 1. Increasing price trend.
            # 2. The last 3 bars are green.
            # 3. The 3rd and 2nd last bars range is decreasing.
            # 4. The last bar exceeds the 2nd last bar by double the 2nd last bar's range.
            second_last_range = self.windows[1].close - self.windows[1].open
            if bar.close > self.windows[1].close and self.windows[1].close > self.windows[2].close and\
            self.windows[2].close > self.windows[2].open and self.windows[1].close > self.windows[1].open and\
            self.windows[0].close > self.windows[0].open and self.windows[2].close - self.windows[2].open > second_last_range and\
            bar.close > self.windows[1].close + 2 * second_last_range:
                self.set_holdings(self.spy, 0.5)

    def on_order_event(self, order_event: OrderEvent) -> None:
        if order_event.status == OrderStatus.FILLED:
            if order_event.ticket.order_type == OrderType.MARKET:
                # Stop loss order at 1%.
                stop_price = order_event.fill_price * 0.99 if order_event.fill_quantity > 0 else order_event.fill_price * 1.01
                self.stop_market_order(self.spy, -self.portfolio[self.spy].quantity, stop_price)
                # Take profit order at 2%.
                take_profit_price = order_event.fill_price * 1.02 if order_event.fill_quantity > 0 else order_event.fill_price * 0.98
                self.limit_order(self.spy, -self.portfolio[self.spy].quantity, take_profit_price)
            elif order_event.ticket.order_type == OrderType.STOP_MARKET or order_event.ticket.order_type == OrderType.LIMIT:
                # Cancel any open order if stop loss or take profit order filled.
                self.transactions.cancel_open_orders()

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: