Hi,

I am getting errors in my Algo.

Unknown datetime string format, unable to parse: CMB WI5URZHSTPBA|CMB R735QTJ8XC9X
  at pandas._libs.tslibs.parsing.parse_datetime_string_with_reso
  File "parsing.pyx" in parsing.pyx: line 312

The algo worked as expected before I have added possibility to buy options instead of equities.

I am sending the code since I canćt attach backtest with the error:

from AlgorithmImports import *
from System.Collections.Generic import List

import numpy as np
import pandas as pd
import statistics as stat
from scipy import stats
import decimal


class GeekyTanShark(QCAlgorithm):

    def Initialize(self):
        # set up
        self.SetStartDate(2017, 1, 1)
        self.SetEndDate(2017, 4, 1)
        self.SetCash(1000000)

        # init 
        self.Data = {}
        self.volumes = {}
        self.adv = {}
        self.time = -1
        self.rebalancing = False
        self.backtestSymbolsPerDay = {}
        self.current_universe = []

        # PARAMTERS
        self.strategy = "3ATH"              # possible values: "3ATH", "ROLATH"
        self.stop_loss_factor = 20          # facotr x std (*)
        self.profit_take_factor = 20        # facotr x std (*)
        self.breakeven = True               # add breakeven option to the algo
        self.longonly = False                # False if we want to apply ATL
        self.add_bond = False               # should we invest in bond in fix proportion
        self.resolution = Resolution.Minute # universe resolution
        self.portfolio_const = "one_max"         # How to contruct portfolio. Can be "fixed" "one_max", "pw"
        self.add_linear_trend = True        # should linear regression be estimated before entry 
        self.universe = "liq"            # type of universe we use in algo. Can be: "custom", "liqvol", "manual", "liq"
        if self.add_bond:
            self.bond_share = 0.1           # share of bonds in portfolio
            self.bond = Symbol.Create('TLT', SecurityType.Equity, Market.USA)  # VFSTX, TLT
        # (*) parameters very important
        
        # UNIVERSE
        self.UniverseSettings.Resolution = self.resolution
        self.UniverseSettings.Leverage = 2
        self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw
        # self.UniverseSettings.ExtendedMarketHours = True # https://www.quantconnect.com/forum/discussion/5483/consolidation-several-sets-of-symbols/p1
        if self.universe == "liqvol" or self.universe == "liq":
            self.min_price = 10             # minimal price of the security
            self.num_coarse = 100           # number of companies to take into account, by dollar volume
            self.num_coarse_vol = 200       # number of companies by volume
            self.vol_width = 22             # window size for calculating sum of volatility
            self.AddUniverse(self.CoarseSelectionFunction)
        elif self.universe == "custom":
            self.AddUniverse("my-blob-universe", self.SelectSymbols)
        elif self.universe == "manual":
            # tickers = ["COST", "LMT", "PGR", "SPG", "AAPL", "V", "MCO"]
            # tickers = ["SPY"]
            # self.symbols = [ Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in tickers]
            tickers = ["GBPUSD", "EURUSD", "AUDUSD", "USDJPY", "GBPJPY", "USDCHF"] # , "EURUSD", "AUDUSD", "USDJPY", "GBPJPY", "USDCHF"
            self.symbols = [ Symbol.Create(ticker, SecurityType.Forex, Market.Oanda) for ticker in tickers]
            # self.SetUniverseSelection(ManualUniverseSelectionModel(self.symbols))
            self.AddUniverse(self.CoarseSelectionFunction)
        # define type of prices
        # self.SetSecurityInitializer(self.CustomSecurityInitializer)
        self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))

        self.SetWarmUp(22 * 12, Resolution.Daily)
        
    def CoarseSelectionFunction(self, coarse):

        # return self.symbols
        
        # 1) Liquid
        if self.universe == "liq":
            # monthly rebalancing
            if self.time == self.Time.month:
                self.rebalancing = False
                return Universe.Unchanged
            self.time = self.Time.month
            self.rebalancing = True

            # choose most liquid stocks with with prie greater than 10
            sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
            filtered = [ x.Symbol for x in sortedByDollarVolume  if x.Price > self.min_price and x.DollarVolume > 1000000]
            
            return filtered[:self.num_coarse]
        
        # 2) Liquid and low volatile
        # update 
        if not self.adv:
            for sec in coarse:
                if sec in self.adv:
                    # Update with newest dollar volume
                    self.adv[sec.Symbol].Update(sec.AdjustedPrice, sec.Volume)
        
        if self.time == self.Time.month: #  and self.out_of_market:
            self.rebalance = False
            return Universe.Unchanged

        self.rebalance = True
        self.time = self.Time.month
        self.step = 0

        # coarse coarse
        coarse = [x for x in coarse if x.HasFundamentalData and x.Price > self.min_price]
        sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)[:2000]

        for sec in sortedByDollarVolume:
            if sec not in self.adv:
                # initiate a new instance of the class
                self.adv[sec.Symbol] = AverageDollarVolume(self.vol_width)
            
                # warm up
                history = self.History(sec.Symbol, self.vol_width, Resolution.Daily)
                if history.shape[0] == 0:
                    continue
                for index, bar in history.loc[sec.Symbol].iterrows():     # leave the last row
                    self.adv[sec.Symbol].Update(bar.close, bar.volume)
            
            # # Update with newest dollar volume
            # self.adv[sec.Symbol].Update(sec.AdjustedPrice, sec.Volume)
        
        # Sort by SMA of dollar volume and take top self.num_coarse
        sortedBySMADV = sorted(self.adv.items(), key=lambda x: x[1].Value, reverse=True)[:self.num_coarse]
        # sortedBySMADV = sorted(self.adv, key=lambda x: x[1].Value, reverse=True)[:self.num_coarse]
        # self.Debug(f"Stocks: {sortedBySMADV[0]}")
        
        # Sort by SMA of volatility and take top self.num_coarse
        # sortedBySMADV = sorted(sortedBySMADV, key=lambda x: x[1].Vol, reverse=False)[:self.num_coarse_vol] # ? DOESNT WORK ??????????
        # self.Debug(f"Stocks: {sortedBySMADV}")

        # Get Symbol object (the key of dict)
        self.filtered = [x[0] for x in sortedBySMADV]
        
        # add bond to universe
        # self.filtered.append(self.bond)
        # self.Debug(f"first: {self.filtered[0]}")
        # self.Debug(f"last: {self.filtered[-1]}")
        
        return self.filtered
    
    def SelectSymbols(self, date):
        
        # if self.time == self.Time.month: #  and self.out_of_market:
        #     self.rebalance = False
        #     return Universe.Unchanged

        # self.rebalance = True
        # self.time = self.Time.month
        # self.step = 0
        
        # handle live mode file format
        if self.LiveMode:
            # fetch the file from dropbox
            str = self.Download("https://www.dropbox.com/s/2l73mu97gcehmh7/daily-stock-picker-live.csv?dl=1")
            # if we have a file for today, return symbols, else leave universe unchanged
            self.current_universe = str.split(',') if len(str) > 0 else self.current_universe
            return self.current_universe

        # backtest - first cache the entire file
        if len(self.backtestSymbolsPerDay) == 0:

            # str = self.Download("https://www.dropbox.com/s/ae1couew5ir3z9y/daily-stock-picker-backtest.csv?dl=1", headers)
            str = self.Download("https://contentiobatch.blob.core.windows.net/qc-backtest/universe.csv")
            for line in str.splitlines():
                data = line.split(',')
                self.backtestSymbolsPerDay[data[0]] = data[1:]

        # index = date.strftime("%Y%m%d")
        # self.current_universe = self.backtestSymbolsPerDay.get(index, self.current_universe)
        # [self.Debug(x) for x in self.current_universe]
        # self.current_universe = [Symbol.Create(x, SecurityType.Equity, Market.USA) for x in self.current_universe if x not in ["|", " "]]
        
        # return self.current_universe
        
        index = date.strftime("%Y%m%d")
        if index not in self.backtestSymbolsPerDay:
            return Universe.Unchanged
        tickers = self.backtestSymbolsPerDay[index]
        # self.current_universe = [Symbol.Create(x, SecurityType.Equity, Market.USA) for x in tickers if x not in ["|", " "]]
        # [self.Debug(f"{date}: {x}") for x in self.current_universe]
        self.current_universe = self.backtestSymbolsPerDay.get(index, self.current_universe)
        
        # add bond to universe
        if self.add_bond:
            self.current_universe.append(self.bond.Value)
        # [self.Debug(f"{x}") for x in self.current_universe]

        return self.current_universe

    def OnSecuritiesChanged(self, changes):
        # added securities
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            if symbol not in self.Data:
                self.Data[symbol] = SymbolData(self, symbol)

        # action on removed securities
        for security in changes.RemovedSecurities:
            symbol = security.Symbol
            # if symbol in self.Data:
            #     if self.Data.pop(symbol, None) is not None:
            #         self.Liquidate(symbol, 'Removed from universe')

    def OnData(self, data):

        # stop time is time after which we don't trade
        stop_time = self.Time.replace(hour=15, minute=55)
        if self.Time > stop_time:
            return

        # buy bond
        if self.add_bond:
            if not self.Portfolio[self.bond].Invested:
                self.SetHoldings(self.bond, self.bond_share)

        # check invested stocks
        invested_long = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.IsLong] # we need this object for pw portfolio construction
        invested_long_len = len(invested_long)

        # update windows
        for symbol in self.Data.keys():
            # check if there is the data for the symbol: if not continue    
            if not data.Bars.ContainsKey(symbol): continue
            if not data.ContainsKey(symbol): continue
            if data[symbol] is None: continue
            if not self.Data[symbol].close_window_day.IsReady: continue
            if not self.Data[symbol].high_window_month.IsReady: continue
            if not self.Data[symbol].high_window_week.IsReady: continue

            # util values
            close_current = data[symbol].Close
            rolling_month_high = max(list(self.Data[symbol].high_window_day)[1:self.Data[symbol].high_window_day.Count])
            week_high = self.Data[symbol].high_window_week[0]
            month_high = self.Data[symbol].high_window_month[0]
            day_high = self.Data[symbol].high_window_day[0]
            momentun_1 = self.Data[symbol].close_window_month[0] / self.Data[symbol].close_window_month[1] - 1
            momentun_2 = self.Data[symbol].close_window_month[1] / self.Data[symbol].close_window_month[2] - 1
            momentun_3 = self.Data[symbol].close_window_month[2] / self.Data[symbol].close_window_month[3] - 1
            higher_high_month_1 = self.Data[symbol].high_window_month[0] > self.Data[symbol].high_window_month[1]
            higher_high_month_2 = self.Data[symbol].high_window_month[1] > self.Data[symbol].high_window_month[2]
            higher_high_month_3 = self.Data[symbol].high_window_month[2] > self.Data[symbol].high_window_month[3]
            higher_high_1 = self.Data[symbol].high_window_day[0] > self.Data[symbol].high_window_day[1]
            higher_high_2 = self.Data[symbol].high_window_day[1] > self.Data[symbol].high_window_day[2]
            higher_high_3 = self.Data[symbol].high_window_day[2] > self.Data[symbol].high_window_day[3]
            
            # use this if we want to apply ATL
            if not self.longonly:
                week_low = self.Data[symbol].low_window_week[0]
                month_low = self.Data[symbol].low_window_month[0]
                day_low = self.Data[symbol].low_window_day[0]
                lower_low_1 = self.Data[symbol].low_window_day[0] < self.Data[symbol].low_window_day[1]
                lower_low_2 = self.Data[symbol].low_window_day[1] < self.Data[symbol].low_window_day[2]
                lower_low_3 = self.Data[symbol].low_window_day[2] < self.Data[symbol].low_window_day[3]
                lower_low_month_1 = self.Data[symbol].low_window_month[0] < self.Data[symbol].low_window_month[1]
                lower_low_month_2 = self.Data[symbol].low_window_month[1] < self.Data[symbol].low_window_month[2]
                lower_low_month_3 = self.Data[symbol].low_window_month[2] < self.Data[symbol].low_window_month[3]

            # alpha
            if self.strategy == "3ATH":
                signal = close_current > week_high and (close_current / week_high - 1) < 0.1 and close_current > month_high and (close_current / month_high - 1) < 0.1 and close_current > day_high and momentun_1 > 0 and momentun_2 > 0 and momentun_3 > 0 and higher_high_1 and higher_high_2 and higher_high_3 and higher_high_month_1 and higher_high_month_2 and higher_high_month_3
                # ave price for short TP
                if signal:
                    self.Data[symbol].ath3_event_prices.append(close_current)
            elif self.strategy == "ROLLATH":
                signal = close_current > rolling_month_high
            if not self.longonly:
                signal_short = close_current < week_low and close_current < month_low and close_current < day_low and momentun_1 < 0 and momentun_2 < 0 and momentun_3 < 0 and (week_low / close_current - 1) < 0.05  and (month_low / close_current - 1) < 0.05 and lower_low_1 and lower_low_2 and lower_low_3 and higher_high_month_1 and higher_high_month_2 and higher_high_month_3
                if signal_short:
                    self.Debug(f"SHORT {symbol} at {self.Time}")

            # 3ATH
            if not self.Portfolio[symbol].Invested and signal and (self.Portfolio.MarginRemaining > 5000 or self.portfolio_const == "pw"):
                if self.add_linear_trend:
                    
                    # linear regression calculation
                    y = list(self.Data[symbol].close_window_day)[1:self.Data[symbol].close_window_day.Count]
                    x = np.arange(len(y))
                    y.reverse()
                    y = np.array(y)
                    log_y = np.log(y)
                    slope, intercept, r_value, p_value, std_err = stats.linregress(x, log_y)
                    # self.Debug(f"R value: {r_value}")
                    
                    if r_value < 0.5:
                        return

                # DEBUG
                self.Debug(
                        f"Symbol {symbol}, MinClose {close_current}, WeekHigh {week_high}, MonthHigh {month_high} DayHigh {day_high}, High1 {self.Data[symbol].high_window_day[0]}, High2 {self.Data[symbol].high_window_day[1]}, High3 {self.Data[symbol].high_window_day[2]}" 
                    )

                # get options data
                contracts=self.OptionChainProvider.GetOptionContractList(symbol, self.Time)
                
                # selects the type of option to be Call contract, then selects all contracts that meet our expiration criteria
                uppertargetStrike=(close_current * (1 + 0.2))
                minContractExpiry = 30
                maxContractExpiry = 60
                call = [x for x in contracts if x.ID.OptionRight ==OptionRight.Call and \
                                                x.ID.StrikePrice > uppertargetStrike and \
                                                minContractExpiry < (x.ID.Date - self.Time).days <= maxContractExpiry] # expiration not longer than 30 days
                if not call:
                   return
                self.Debug(f"Call: {call}")

                #sorts contracts by closet expiring date and closest strike price (sorts in ascending order)
                call = sorted(sorted(call, key = lambda x: x.ID.Date), 
                    key = lambda x: x.ID.StrikePrice)
                if len(call) == 0: continue

                option = self.AddOptionContract(call[0], Resolution.Minute)
				# option.PriceModel = QuantConnect.Securities.Option.OptionPriceModels.BlackScholes()
                
                # orders
                # self.Debug(f"Call: {call}")
                self.Debug(f"Call 0: {option.Symbol}")
                self.MarketOrder(option.Symbol, 10)

            # 3ATL
            elif self.longonly == False and not self.Portfolio[symbol].Invested and signal_short and self.Portfolio.MarginRemaining > 5000 and not self.Portfolio[symbol].IsShort:
                
                if self.add_linear_trend:
                    
                    # linear regression calculation
                    y = list(self.Data[symbol].close_window_day)[1:self.Data[symbol].close_window_day.Count]
                    x = np.arange(len(y))
                    y.reverse()
                    y = np.array(y)
                    log_y = np.log(y)
                    slope, intercept, r_value, p_value, std_err = stats.linregress(x, log_y)

                    self.Debug(f"Symbol: {symbol}, R^2 {r_value}")
                    if abs(r_value) < 0.75:
                        continue

                # standard deviation
                std_ = stat.stdev(list(self.Data[symbol].close_window_day)[1:self.Data[symbol].close_window_day.Count])
                # bet size
                confidence = abs(r_value)
                
                if self.portfolio_const == "fixed":
                    if confidence > 0.75 and confidence < 0.8:
                        quantity = 0.5
                    elif confidence >= 0.8 and confidence < 0.85:
                        quantity = 0.55
                    elif confidence >= 0.85 and confidence < 0.9:
                        quantity = 0.6
                    elif confidence >= 0.9 and confidence < 0.95:
                        quantity = 0.65
                    elif confidence >= 0.95 and confidence < 0.99:
                        quantity = 0.7
                    elif confidence >= 0.99:
                        quantity = 0.75
                    quantity = self.CalculateOrderQuantity(symbol, quantity)
                    if (quantity * data[symbol].Close) > self.Portfolio.MarginRemaining:
                        quantity = (self.Portfolio.MarginRemaining / data[symbol].Close) - 1

                # TP
                ath3_prices_history = self.Data[symbol].ath3_event_prices
                ath3_prices_history = [x for x in ath3_prices_history if x < close_current]
                if ath3_prices_history:
                    short_tp = ath3_prices_history[-1]
                else:
                    short_tp =  data[symbol].High - (std_ * 1)
                
                # orders
                self.MarketOrder(symbol, -quantity, tag = "3ATL SHORT")
                self.Data[symbol].stop_order_ticket = self.StopMarketOrder(symbol, quantity, data[symbol].High + (std_ * 1))
                self.LimitOrder(symbol, quantity, short_tp)
                
            elif self.Portfolio[symbol].Invested:
                if self.breakeven:
                    if self.Portfolio[symbol].IsLong:
                        if self.Data[symbol].breakeven_set:
                            continue
                        else:
                            mean_daily_return = np.mean(np.abs(np.diff(np.log(np.flip(np.array(list(self.Data[symbol].close_window_day))))))) # 1% * 2, P = 100$; 100$ > 102$ > SL = 100
                            if (self.Portfolio[symbol].Price / self.Securities[symbol].Holdings.AveragePrice - 1) < (mean_daily_return * 2):
                                # drawdown = (data[symbol].Low / algorithm.Securities[symbol].Holdings.AveragePrice) - 1
                                # if drawdown < self.maximumDrawdownPercent:
                                #     self.Liquidate(symbol)
                                continue
                            else:
                                # Updating an Order:
                                
                                ###### DEBUG #######
                                self.Debug(f"{self.Securities[symbol].Holdings.AveragePrice}")
                                self.Debug(f"{self.Portfolio[symbol].IsLong}")
                                self.Debug(f"{self.Data[symbol].stop_order_ticket}")
                                ###### DEBUG #######
                                
                                updateOrderFields = UpdateOrderFields()
                                # updateOrderFields.StopPrice = decimal.Decimal(self.Securities[symbol].Holdings.AveragePrice)
                                updateOrderFields.StopPrice = self.Securities[symbol].Holdings.AveragePrice
                                updateOrderFields.Tag = "Updated Stop order"
                                self.Data[symbol].stop_order_ticket.Update(updateOrderFields)
                                # 
                                # self.StopMarketOrder(symbol, -self.Securities[symbol].Holdings.Quantity, self.Securities[symbol].Holdings.AveragePrice)
                                self.Data[symbol].breakeven_set = True
                    if self.Portfolio[symbol].IsShort:
                        if self.Data[symbol].breakeven_set:
                            continue
                        else:
                            mean_daily_return = np.mean(np.abs(np.diff(np.log(np.flip(np.array(list(self.Data[symbol].close_window_day))))))) # 1% * 2, P = 100$; 100$ > 102$ > SL = 100
                            if (self.Securities[symbol].Holdings.AveragePrice / self.Portfolio[symbol].Price  - 1) < (mean_daily_return * 2):
                                continue
                            else:
                                # update stop loss
                                updateOrderFields = UpdateOrderFields()
                                # updateOrderFields.StopPrice = decimal.Decimal(self.Securities[symbol].Holdings.AveragePrice)
                                updateOrderFields.StopPrice = self.Securities[symbol].Holdings.AveragePrice
                                updateOrderFields.Tag = "Updated Stop order"
                                self.Data[symbol].stop_order_ticket.Update(updateOrderFields)
                                self.Data[symbol].breakeven_set = True

        if self.portfolio_const == "pw" and len(invested_long) > 0 and len(invested_long) > invested_long_len:
            self.Debug(f"len(invested_long) {len(invested_long)}")
            self.Debug(f"invested_long_len {invested_long_len}")
            for symbol_ in invested_long:
                quantity = self.CalculateOrderQuantity(symbol_, 1 / len(invested_long))
                close_current = data[symbol_].Close
                if self.Portfolio[symbol_].Quantity == 0:
                    self.Data[symbol_].stop_loss_price = close_current - (close_current * (self.stop_loss_factor / 100))
                    self.StopMarketOrder(symbol_, -quantity, self.Data[symbol_].stop_loss_price, tag = "Initial stop order")
                    self.Data[symbol_].profit_take_price =  close_current + (close_current * (self.profit_take_factor / 100))
                    self.LimitOrder(symbol_, -quantity, self.Data[symbol_].profit_take_price, tag = "Initial limit order")
                    self.SetHoldings(symbol_, 1 / len(invested_long), tag = "3ATH BUY")
                elif self.Portfolio[symbol_].Quantity > 0:
                    self.Transactions.CancelOpenOrders(symbol_)
                    self.StopMarketOrder(symbol_, -quantity, self.Data[symbol_].stop_loss_price)
                    self.LimitOrder(symbol_, -quantity, self.Data[symbol_].profit_take_price)
                    self.SetHoldings(symbol_, 1 / len(invested_long), tag = "3ATH BUY")
                    self.Debug(self.Transactions.CancelOpenOrders(symbol_))
                    # # update stop loss
                    # updateOrderFields = UpdateOrderFields()
                    # updateOrderFields.StopPrice = self.Securities[symbol_].Holdings.AveragePrice
                    # updateOrderFields.Quantity = quantity
                    # updateOrderFields.Tag = "Updated Stop order"
                    # self.Data[symbol_].stop_order_ticket.Update(updateOrderFields)
                    # # update profit take
                    # updateOrderFields = UpdateOrderFields()
                    # updateOrderFields.LimitPrice = self.Securities[symbol_].Holdings.AveragePrice
                    # updateOrderFields.Quantity = quantity
                    # updateOrderFields.Tag = "Updated Limit order"
                    # self.Data[symbol_].limit_order_ticket.Update(updateOrderFields)

    def OnOrderEvent(self, orderEvent):
        order = self.Transactions.GetOrderById(orderEvent.OrderId)
        
        if order.Status == OrderStatus.Filled:
            if order.Type == OrderType.Limit or order.Type == OrderType.StopMarket or order.Type == OrderType.MarketOnOpen:
                self.Transactions.CancelOpenOrders(order.Symbol)
                self.Data.pop(order.Symbol.Value, None)

        # if order.Status == OrderStatus.Canceled:
            # self.Log(str(orderEvent))


class SymbolData(object):
    def __init__(self, algorithm, symbol):
        self.symbol = symbol
        self.algorithm = algorithm
        self.breakeven_set = False
        self.stop_order_ticket = None
        self.ath3_event_prices = []
        # for pw
        self.limit_order_ticket = None
        self.stop_loss_price = None
        self.profit_take_price = None

        # define windows
        self.close_window_day = RollingWindow[float](22)
        self.high_window_day = RollingWindow[float](22)
        self.low_window_day = RollingWindow[float](22)
        self.volume_window_day = RollingWindow[float](22)
        self.high_window_week = RollingWindow[float](5)
        self.low_window_week = RollingWindow[float](5)
        self.high_window_month = RollingWindow[float](5)
        self.low_window_month = RollingWindow[float](5)
        self.close_window_month = RollingWindow[float](5)

        # consolidators
        
        self.dayConsolidator = TradeBarConsolidator(Resolution.Daily)
        self.weekConsolidator = TradeBarConsolidator(Calendar.Weekly)
        self.monthConsolidator = TradeBarConsolidator(Calendar.Monthly)
        # self.dayConsolidator = QuoteBarConsolidator(Resolution.Daily)
        # self.weekConsolidator = QuoteBarConsolidator(Calendar.Weekly)
        # self.monthConsolidator = QuoteBarConsolidator(Calendar.Monthly)

        self.dayConsolidator.DataConsolidated += self.OnDataConsolidatedDaily
        self.weekConsolidator.DataConsolidated += self.OnDataConsolidatedWeek
        self.monthConsolidator.DataConsolidated += self.OnDataConsolidatedMonth

        algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.dayConsolidator)
        algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.weekConsolidator)
        algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.monthConsolidator)

        # warm up
        history = self.algorithm.History([self.symbol], 22 * 12, Resolution.Daily)
        if history.shape[0] == 0:
            self.algorithm.Log('DataFrame is empty!')
            return
        for tuple in history.loc[self.symbol].itertuples():
            tradebar = TradeBar(tuple.Index, self.symbol, tuple.open, tuple.high, tuple.low, tuple.close, tuple.volume)
            # tradebar = QuoteBar(tuple.Index, self.symbol, tuple.open, tuple.high, tuple.low, tuple.close)
            # tradebar.Symbol = self.symbol 
            self.dayConsolidator.Update(tradebar)
            self.weekConsolidator.Update(tradebar)
            self.monthConsolidator.Update(tradebar)

    def update(self, close, high, volume):
        pass
        # self.close_window.Add(close)
        # self.high_window.Add(high)
        self.volume_window.Add(volume)
        
    def OnDataConsolidatedDaily(self, sender, consolidated):
        self.high_window_day.Add(consolidated.High)
        self.low_window_day.Add(consolidated.Low)
        self.close_window_day.Add(consolidated.Close)
        # self.volume_window_day.Add(consolidated.Volume)

    def OnDataConsolidatedWeek(self, sender, consolidated):
        self.high_window_week.Add(consolidated.High)
        self.low_window_week.Add(consolidated.Low)
        
    def OnDataConsolidatedMonth(self, sender, consolidated):
        self.high_window_month.Add(consolidated.High)
        self.low_window_month.Add(consolidated.Low)
        self.close_window_month.Add(consolidated.Close)


class SymbolDataCoarse(object):
    def __init__(self, algorithm, symbol):
        self.symbol = symbol
        self.algorithm = algorithm
        self.volume_window_day = RollingWindow[float](22)
        history = self.algorithm.History([self.symbol], 22, Resolution.Hour)
        if history.shape[0] == 0:
            self.algorithm.Log('DataFrame is empty!')
        if history.loc[self.symbol].shape[0] < 22:
            self.mean_volume = 0    
        for time, row in history.loc[self.symbol].iterrows():
            self.volume_window_day.Add(row["volume"])
        self.mean_volume = self.average(list(self.volume_window_day))

    def update(self, vol):
        self.volume_window_day.Add(vol)
        self.mean_volume = self.average(list(self.volume_window_day))

    def average(self, lst):
        return sum(lst) / len(lst)


class AverageDollarVolume(PythonIndicator):  # Average Dollar Volume
    def __init__(self, SMA):
        self.dv = RollingWindow[float](SMA)
        self.vol = RollingWindow[float](SMA)
        self.Value = 0
        self.Vol = 0
    
    def Update(self, price, volume):
        self.dv.Add(price * volume)
        self.vol.Add(price)

        if self.dv.IsReady and self.vol.IsReady:
            self.Value = pd.Series(self.dv).mean()
            self.Vol = stat.stdev(list(self.vol))
            return True   
            
        return False