I add 1 hour frequence bars data and consolidated into 4 hours bars, but when I add a breakpoint to check the data in OnData, I find "self.Time" is out of consolidated Bar's "Open time" and "Close time"; 

Please check my code and set a breakpoint on line 57 and then run it step by step; most time you would see in OnData "self.TIme"/"data.TIme" is out of symbolData.Bars[0]'s time range as below picture.

188056_1646362119.jpg

 I think on above piture, “self.Time” and “data.Time” are both the current one hour bar's Open Time and their values shoud be [conBar.Time, conBar.EndTime), but in the fact, their values are out of this range.

I guess maybe this is because of Time Zone problem, but I can't confirm and don't know how to correct it.

from collections import deque
from AlgorithmImports import *


class ConsolidatedIndicators(QCAlgorithm):
    def Initialize(self):
        self.SetTimeZone("UTC")
        self.SetStartDate(2021, 2, 25)
        # self.SetEndDate(2022, 3, 2)
        self.SetBrokerageModel(BrokerageName.Binance, AccountType.Cash)
        self.SetAccountCurrency("USDT")
        self.SetCash(100000)
        self.SetBenchmark(Symbol.Create("BTCUSDT", SecurityType.Crypto, Market.Binance))
        self.Data = {}
        self.symbols = {'BTCUSDT': 'BTCUSDT', 'ETHUSDT': 'ETHUSDT', 'XRPUSDT': 'XRPUSDT', 'ADAUSDT': 'ADAUSDT',
                        'DOTUSDT': 'DOTUSDT', 'MATICUSDT': 'MATICUSDT', 'ATOMUSDT': 'ATOMUSDT', 'LINKUSDT': 'LINKUSDT',
                        'TRXUSDT': 'TRXUSDT', 'FILUSDT': 'FILUSDT', 'LTCUSDT': 'LTCUSDT', 'ETCUSDT': 'ETCUSDT',
                        'BCHUSDT': 'BCHUSDT'}
        BarPeriod = TimeSpan.FromHours(4)
        coins = list(self.symbols.keys())
        for si in coins:
            try:
                crypto = self.AddCrypto(si, Resolution.Hour, Market.Binance)
                self.Data[si] = SymbolData(crypto.Symbol, BarPeriod)
                self.Securities[si].SetFeeModel(CustomFeeModel())
            except:
                self.symbols.pop(si)
                self.Log(f"can't load {si}")

        for symbol, symbolData in self.Data.items():
            symbolData.Indicators['CCI'] = IndicatorCCI()
            symbolData.Indicators['REV'] = IndicatorReverse()
            consolidator = TradeBarConsolidator(
                BarPeriod) if symbolData.Symbol.SecurityType == SecurityType.Crypto else QuoteBarConsolidator(BarPeriod)
            consolidator.DataConsolidated += self.OnDataConsolidated
            self.SubscriptionManager.AddConsolidator(symbolData.Symbol, consolidator)
        self.SetWarmup(200, Resolution.Hour)

    def OnDataConsolidated(self, sender, bar):
        self.Data[bar.Symbol.Value].Bars.Add(bar)
        for _, indi in self.Data[bar.Symbol.Value].Indicators.items():
            indi.Update(bar)

    def OnData(self, data):
        if self.IsWarmingUp:
            return
        symbolData = self.Data['BTCUSDT']
        conBar = symbolData.Bars[0]

        for symbol in self.Data.keys():
            symbolData = self.Data[symbol]
            if symbolData.IsReady() and symbolData.WasJustUpdated(data.Time):
                pass
            else:
                self.Log(f"{symbol} not has been prepared.")
                return
        self.Log('Run Once.')


class SymbolData(object):

    def __init__(self, symbol, barPeriod, windowSize=5):
        self.Symbol = symbol
        self.BarPeriod = barPeriod
        self.Bars = RollingWindow[IBaseDataBar](windowSize)
        self.Indicators = {}

    def IsReady(self):
        if self.Bars.IsReady:
            for _, indi in self.Indicators.items():
                if not indi.IsReady:
                    return False
        else:
            return False
        return True

    def WasJustUpdated(self, current):
        return self.Bars.Count > 0 and self.Bars[0].Time <= current - self.BarPeriod < self.Bars[0].EndTime


class CustomFeeModel:
    def GetOrderFee(self, parameters):
        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.001
        return OrderFee(CashAmount(fee, 'USDT'))


class IndicatorCCI:
    def __init__(self, name='CCI', period=20):
        self.Name = name
        self.period = period
        self.Time = datetime.min
        self.Value = 0
        self.IsReady = False
        self.closes = deque(maxlen=self.period)
        self.oldest_close = None
        self.MA = deque(maxlen=self.period)
        self.MA_plus_abs = deque(maxlen=self.period)
        self.oldest_MA_plus_abs = None
        self.MD = None

    def Update(self, input):
        closei = input.Close
        self.closes.append(closei)
        self.Time = input.EndTime
        if len(self.closes) == self.period:
            if self.oldest_close is None:
                self.MA.append(sum(self.closes) / self.period)
                self.MA_plus_abs.append(abs(self.MA[-1] - closei))
                self.oldest_close = self.closes[0]
            else:
                self.MA.append(self.MA[-1] + (closei - self.oldest_close) / self.period)
                self.MA_plus_abs.append(abs(self.MA[-1] - closei))
                self.oldest_close = self.closes[0]

        if len(self.MA_plus_abs) == self.period:
            if self.oldest_MA_plus_abs is None:
                self.IsReady = True
                self.MD = sum(self.MA_plus_abs) / self.period
            else:
                self.MD += (self.MA_plus_abs[-1] - self.oldest_MA_plus_abs) / self.period
            self.oldest_MA_plus_abs = self.MA_plus_abs[0]
            self.Value = ((input.High + input.Low + closei) / 3 - self.MA[-1]) / self.MD


class IndicatorReverse:
    def __init__(self, name='Reverse', period=10):
        self.Name = name
        self.period = period
        self.Time = datetime.min
        self.Value = 0
        self.IsReady = False
        self.closes = deque(maxlen=self.period)

    def Update(self, input):
        self.closes.append(input.Close)
        self.Time = input.EndTime
        if not self.IsReady:
            if len(self.closes) < self.period:
                return
            else:
                self.IsReady = True
        self.Value = self.closes[-1] / self.closes[0] - 1.0