Hi,

For a multiple symbol QCAlgorithm strategy that is running on consolidated bars, what is the correct way of doing it?

In the SymbolData object way:

class MultipleTickerSingleTechnicalIndicatorWithResampling(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2022, 2, 1)  # Set Start Date
        self.SetEndDate(2022, 3, 31)  # Set End Date
        self.SetCash(100000)  # Set Strategy Cash

        ## PARAMETERS
        self.DebugMode = True


        self.ema_fast = int(self.GetParameter("ema_fast"))
        self.ema_slow = int(self.GetParameter("ema_slow"))
        self.consolidate_bar_count = int(self.GetParameter("consolidate_bar_count"))

        ## UNIVERSE
        self.tickers = ['ADAUSDT','ALGOUSDT','ATOMUSDT','AVAXUSDT','AXSUSDT','BCHUSDT','BTCUSDT','DOGEUSDT','DOTUSDT','ETHUSDT']

        ## DATA LOADING
        self.symbol_data = {}
        for ticker in self.tickers:
            security = self.AddData(type=BinanceTradeBarData, ticker=ticker, resolution=Resolution.Minute)
            self.symbol_data[ticker] = SymbolData(
                algorithm = self,
                symbol = security.Symbol, 
                ema_fast = self.ema_fast, 
                ema_slow = self.ema_slow,
                consolidate_bar_count = self.consolidate_bar_count
                )

    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Filled:
            self.Debug(f"Order: {orderEvent.Symbol.Value} | {orderEvent.FillQuantity} | {orderEvent.UtcTime}")

    def OnData(self, data: PythonSlice) -> None:

        for ticker in self.tickers:
            symbol_data_single = self.symbol_data[ticker]
            symbol_data_single.consolidator.Update(data[ticker])
        
    def OnDataConsolidated(self, sender, consolidated_bar:TradeBar):
        self.Debug(f"Consolidated data: {consolidated_bar.Time}-{consolidated_bar.EndTime} {consolidated_bar.ToString()}")



		# strategy logic and order creation with .Liquidate() and .SetHoldings() here


class SymbolData(object):
    def __init__(self, algorithm:QCAlgorithm, symbol, ema_fast:int=50, ema_slow:int=200, consolidate_bar_count:int = 5):
        self.symbol = symbol
        # indicators
        self.fast = ExponentialMovingAverage(ema_fast)
        self.slow = ExponentialMovingAverage(ema_slow)
        # consolidator
        self.consolidator = TradeBarConsolidator(timedelta(minutes=consolidate_bar_count))
        self.consolidator.DataConsolidated += algorithm.OnDataConsolidated
        algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.consolidator)
        # update indicators with consolidated_bar
        algorithm.RegisterIndicator(self.symbol, self.fast, self.consolidator)
        algorithm.RegisterIndicator(self.symbol, self.fast, self.consolidator)
        self.signal = 0

    def update(self, time, value):
        fast_ema_ready = self.fast.Update(time, value)
        slow_ema_ready = self.slow.Update(time, value)
        if fast_ema_ready and slow_ema_ready:
            fast = self.fast.Current.Value
            slow = self.slow.Current.Value
            self.signal = (fast - slow) / ((fast + slow) / 2.0)

or doing the manual update within OnDataConsolidated (the consolidated bar handler):

class MultipleTickerSingleTechnicalIndicatorWithResampling(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2022, 2, 1)  # Set Start Date
        self.SetEndDate(2022, 3, 31)  # Set End Date
        self.SetCash(100000)  # Set Strategy Cash

        ## PARAMETERS
        self.DebugMode = True

        self.ema_fast = int(self.GetParameter("ema_fast"))
        self.ema_slow = int(self.GetParameter("ema_slow"))
        self.consolidate_bar_count = int(self.GetParameter("consolidate_bar_count"))

        ## UNIVERSE
        self.tickers = ['ADAUSDT','ALGOUSDT','ATOMUSDT','AVAXUSDT','AXSUSDT','BCHUSDT','BTCUSDT','DOGEUSDT','DOTUSDT','ETHUSDT']

        ## DATA LOADING
        self.symbol_data = {}
        for ticker in self.tickers:
            security = self.AddData(type=BinanceTradeBarData, ticker=ticker, resolution=Resolution.Minute)
            self.symbol_data[ticker] = SymbolData(
                algorithm = self,
                symbol = security.Symbol, 
                ema_fast = self.ema_fast, 
                ema_slow = self.ema_slow,
                consolidate_bar_count = self.consolidate_bar_count
                )

    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Filled:
            self.Debug(f"Order: {orderEvent.Symbol.Value} | {orderEvent.FillQuantity} | {orderEvent.UtcTime}")

    def OnData(self, data: PythonSlice) -> None:

        for ticker in self.tickers:
            symbol_data_single = self.symbol_data[ticker]
            symbol_data_single.update(data[ticker].EndTime,data[ticker].Price)
            symbol_data_single.consolidator.Update(data[ticker])
        
    def OnDataConsolidated(self, sender, consolidated_bar:TradeBar):
        self.Debug(f"Consolidated data: {consolidated_bar.Time}-{consolidated_bar.EndTime} {consolidated_bar.ToString()}")




        # update indicators with consolidated_bar
        symbol_data_single = self.symbol_data[consolidated_bar.Symbol.Value]
        symbol_data_single.update(consolidated_bar.EndTime,consolidated_bar.Price)



		# strategy logic and order creation with .Liquidate() and .SetHoldings() here


class SymbolData(object):
    def __init__(self, algorithm:QCAlgorithm, symbol, ema_fast:int=50, ema_slow:int=200, consolidate_bar_count:int = 5):
        self.symbol = symbol
        # indicators
        self.fast = ExponentialMovingAverage(ema_fast)
        self.slow = ExponentialMovingAverage(ema_slow)
        # consolidator
        self.consolidator = TradeBarConsolidator(timedelta(minutes=consolidate_bar_count))
        self.consolidator.DataConsolidated += algorithm.OnDataConsolidated
        algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.consolidator)

        self.signal = 0

    def update(self, time, value):
        fast_ema_ready = self.fast.Update(time, value)
        slow_ema_ready = self.slow.Update(time, value)
        if fast_ema_ready and slow_ema_ready:
            fast = self.fast.Current.Value
            slow = self.slow.Current.Value
            self.signal = (fast - slow) / ((fast + slow) / 2.0)

 

Any help is appreciated.

Author