Hey Everyone,

I’m encountering a timing issue in my algorithm that involves the interaction between custom daily bars being consolidated and the on_data method. I'm subscribing to minute resolution data for a single stock, then consolidating daily bars using the minute bars. It seems that daily bars can be consolidated before the actual trading day ends. In one instance (2023-01-12 16:00:00), my consolidator event handler ran at 16:00 before the last on_data method call of the trading day, and accidentally triggered a trade. This creates an inconsistency in daily open/high/low values and can incorrectly trigger orders at the end of the day in my code. 

 Sharing a code snippet below to paint the picture. Am I doing something wrong or is this a bug? Any solutions appreciated!

 

# region imports
from AlgorithmImports import *
# endregion

class SwimmingLightBrownCobra(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2023, 1, 10)
        self.set_end_date(2023, 1, 16)
        self.set_cash(100000)
        baba = self.add_equity("BABA", Resolution.MINUTE)
        baba.set_data_normalization_mode(DataNormalizationMode.SPLIT_ADJUSTED)
        self.baba = baba.symbol

        # Attributes for setups
        self.setup_type = None
        self.entry_price = None
        self.stop_price = None
        self.target_price = None
        self.have_setup = 0
        self.ready_for_setups = False
        self.order_ticket = None
        self.target_order_ticket = None
        self.stop_order_ticket = None

        # Data Subscriptions - Daily, Weekly
        self.daily_consolidator = self.consolidate(self.baba, Resolution.DAILY, self.on_daily_consolidated)
        self.weekly_consolidator = self.consolidate(self.baba, Calendar.WEEKLY, self.on_weekly_consolidated)

        # Warm Up Rolling Windows
        historical_trade_bars = self.history[TradeBar](self.baba, 200, Resolution.DAILY)
        for trade_bar in historical_trade_bars:

            # Warm up consolidators
            self.daily_consolidator.update(trade_bar)
            self.weekly_consolidator.update(trade_bar)
        
        # Start looking for setups
        self.ready_for_setups = True

    def on_data(self, data: Slice):
        if self.baba in data.bars:
            self.log("self.baba in data.bars")
            current_bar = data.bars[self.baba]

            # Look for trades if not currently in a trade
            if not self.portfolio.invested:
                
                # Check if order already placed
                if self.order_ticket is None:
                        
                    # Bullish setup
                    if self.have_setup > 0:
                        self.order_ticket = self.stop_market_order(self.baba, 10, self.entry_price)
                        self.log("Setting up a bullish order")
                        self.log(f"Entry Price: {self.entry_price}")
                        self.log(f"Stop Loss Price: {self.stop_price}")
                        self.log(f"Target Price: {self.target_price}")

                    # Bearish setup
                    elif self.have_setup < 0:
                        self.order_ticket = self.stop_market_order(self.baba, -10, self.entry_price)
                        self.log("Setting up a bearish order")
                        self.log(f"Entry Price: {self.entry_price}")
                        self.log(f"Stop Loss Price: {self.stop_price}")
                        self.log(f"Target Price: {self.target_price}")

                    else:
                        return
        else:
            self.log(f"No data for {self.time}")

    def on_order_event(self, order_event):
            if order_event.status == OrderStatus.FILLED:

                # Log the order we filled
                self.log("Order was filled")
                self.log(order_event)
                
                # Entered the trade, setting target and stop
                if order_event.order_id == self.order_ticket.order_id:
                    self.target_order_ticket = self.limit_order(order_event.symbol, -order_event.fill_quantity, self.target_price)
                    self.stop_order_ticket = self.stop_market_order(order_event.symbol, -order_event.fill_quantity, self.stop_price)
                    self.log("Setting target and stop loss orders")
                
                # Reached target, exiting trade
                elif self.target_order_ticket is not None and order_event.order_id == self.target_order_ticket.order_id:
                    self.stop_order_ticket.cancel()
                    self.log("Reached target, exiting trade; target order ticket below")
                    self.log(self.target_order_ticket)

                # Hit our stop, exiting trade
                elif self.stop_order_ticket is not None and order_event.order_id == self.stop_order_ticket.order_id:
                    self.target_order_ticket.cancel()
                    self.log("Hit our stop, exiting trade; stop order ticket below")
                    self.log(self.stop_order_ticket)
            
            elif order_event.status == OrderStatus.SUBMITTED:
                self.log("Submitted an order")
                self.log(order_event)
            
            else:
                self.log("Order event status was different than filled or submitted")
                self.log(order_event)
                self.log(order_event.status)

    def on_daily_consolidated(self, bar):
        # Manage orders
        if self.order_ticket is not None:

            # Cancel any outstanding orders
            if self.order_ticket.status == OrderStatus.SUBMITTED:
                self.log(f"Canceled order: {self.order_ticket}")
                self.order_ticket.cancel()
                self.order_ticket = None
            
            # Reset for next day if we made a trade
            elif self.order_ticket.status == OrderStatus.FILLED and not self.portfolio.invested:
                self.order_ticket = None
                self.log("the order status for self.order_ticket was filled and the portfolio was not invested")
        else:
            self.log("Log - self.order_ticket is None")
        
        # Update rolling window
        self.window_daily.add(bar)

        # Check setups only after warm-up is complete
        if self.ready_for_setups:
            self.have_setup = self.check_setups("daily")

    def on_weekly_consolidated(self, bar):
        self.window_weekly.add(bar)