Overall Statistics
Total Trades
88
Average Win
0.04%
Average Loss
-0.03%
Compounding Annual Return
-0.217%
Drawdown
0.700%
Expectancy
-0.158
Net Profit
-0.239%
Sharpe Ratio
-15.113
Sortino Ratio
-10.17
Probabilistic Sharpe Ratio
3.881%
Loss Rate
61%
Win Rate
39%
Profit-Loss Ratio
1.18
Alpha
-0.054
Beta
-0
Annual Standard Deviation
0.004
Annual Variance
0
Information Ratio
-1.817
Tracking Error
0.107
Treynor Ratio
427.794
Total Fees
$0.00
Estimated Strategy Capacity
$430000.00
Lowest Capacity Asset
GD R735QTJ8XC9X
Portfolio Turnover
1.83%
# region imports
from AlgorithmImports import *
from symbol_data import SymbolData
from position_manager import PositionManager
from tickers import tickers
# endregion

class IchimokuMomentum(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2023, 1, 1)
        self.SetCash(1000000)

        self.SetWarmUp(timedelta(days=60))
        
        # Timeframes
        self.slow_resolution = 60 # in minutes 
        self.fast_resolution = 5 # in minutes
        
        self.adx_period = 14
        self.adx_threshold = 20

        self.tenkan_period = 9
        self.kijun_period = 26
        
        self.kumo_cloud_signal_enabled = False

        # invests in the new position with 1% of the total portfolio value (including cash and securities)
        self.fixed_percentage_positioning = 0.01

        self.stop_loss_pct = 0.02
        self.take_profit_pct = 0.02

        self.use_exit_signals = True
        self.use_sl_and_tp = False

        # Kelly Params
        self.use_kelly_criterion_sizing = True
        self.win_rate = 0.5
        self.average_win = 0.015
        self.average_loss = 0.01
        self.proportion_of_portfolio = 0.5 # i.e. multiply kelly result by 1/2
        ### 

        self.symbols = {}
        self.position_managers = {}

        self.debug = True

        tickers = ["GD"] #, "FSLR", "META", "LUV", "NVDA"]
        
        for ticker in tickers:

            security = self.AddEquity(ticker, Resolution.Minute)

            # TD Ameritrade Fee Model
            security.SetFeeModel(TDAmeritradeFeeModel())
            security.SetSlippageModel(VolumeShareSlippageModel())

            symbol = security.Symbol

            self.symbols[symbol] = SymbolData(self,
                                             symbol, 
                                             self.fast_resolution, 
                                             self.slow_resolution, 
                                             self.adx_period,
                                             self.adx_threshold, 
                                             self.tenkan_period, 
                                             self.kijun_period,
                                             self.kumo_cloud_signal_enabled)

            self.position_managers[symbol] = PositionManager(self, symbol)

    def OnData(self, data: Slice):

        if self.IsWarmingUp:
            return

        for symbol, manager in self.position_managers.items():
            if self.symbols[symbol].is_ready:
                manager.update_position()

    def OnOrderEvent(self, orderEvent):
        if self.use_sl_and_tp: 
            self.position_managers[orderEvent.Symbol].check_bracket_order_state(orderEvent)

    def debug_with_flag(self, message):
        if self.debug:
            self.Debug(message)
#region imports
from AlgorithmImports import *
#endregion

class PositionManager:
    '''Manages orders for a symbol
    '''
    def __init__(self, algorithm, symbol):
        
        self.algorithm = algorithm
        self.symbol = symbol

        self.stop_ticket = None
        self.profit_ticket = None
        
    
    def bracket_order(self, quantity, stop_loss, take_profit):

        self.algorithm.MarketOrder(self.symbol, quantity, None, "bracket entry")

        if self.algorithm.use_sl_and_tp:
            self.stop_ticket = self.algorithm.StopMarketOrder(self.symbol, -quantity, stop_loss,  "bracket stop loss")

            self.profit_ticket = self.algorithm.LimitOrder(self.symbol, -quantity, take_profit, "bracket take profit")

       
    def check_bracket_order_state(self, orderevent):

        if orderevent.Status is not OrderStatus.Filled:
            return

        if self.stop_ticket and orderevent.OrderId == self.stop_ticket.OrderId:
                self.profit_ticket.Cancel()
                self.profit_ticket = None
                self.stop_ticket = None
                return

        if self.profit_ticket and orderevent.OrderId == self.profit_ticket.OrderId:
                self.stop_ticket.Cancel()
                self.profit_ticket = None
                self.stop_ticket = None
                return


    def update_position(self):

        if self.algorithm.Portfolio[self.symbol].Invested:

            if self.algorithm.use_exit_signals:

                #  ICHIMOKU EXIT SIGNALS 
                if self.algorithm.Portfolio[self.symbol].IsLong:
                    if self.algorithm.symbols[self.symbol].is_long_exit_signal:
                        self.algorithm.Liquidate(self.symbol, "long exit signal")

                        self.algorithm.Debug(f"{self.algorithm.Time} - long exit signal {self.symbol}")
                        self.cancel_all_legs()
                else:
                    if self.algorithm.symbols[self.symbol].is_short_exit_signal:
                        self.algorithm.Liquidate(self.symbol, "short exit signal")

                        self.algorithm.Debug(f"{self.algorithm.Time} - short exit signal {self.symbol}")
                        self.cancel_all_legs()     

        else:

            if self.algorithm.symbols[self.symbol].is_long_entry_signal:
                
                market_price = self.algorithm.Securities[self.symbol].Price 
                stop_loss = market_price * (1 - self.algorithm.stop_loss_pct)
                take_profit = market_price * (1 + self.algorithm.take_profit_pct)

                quantity = self.calculate_size(market_price)
                symb = self.algorithm.symbols[self.symbol]

                self.algorithm.debug_with_flag(f"Long entry for {quantity} shares of {self.symbol} @ {market_price} - stop: {stop_loss} - tp: {take_profit} 1 hr close: {symb.slow_window[0].Close} adx: [{symb.adx_window[1].Value}, {symb.adx_window[0].Value}] - tenkan_slow: [{symb.ichimoku_tenkan_slow_window[0]}] - spanB_fast: [{symb.ichimoku_spanB_fast_window[3]}, {symb.ichimoku_spanB_fast_window[2]}, {symb.ichimoku_spanB_fast_window[1]}, {symb.ichimoku_spanB_fast_window[0]}] - tenkan_fast: [{symb.ichimoku_tenkan_fast_window[3]}, {symb.ichimoku_tenkan_fast_window[2]}, {symb.ichimoku_tenkan_fast_window[1]}, {symb.ichimoku_tenkan_fast_window[0]}]")
                self.bracket_order(quantity, stop_loss, take_profit)
            
            elif self.algorithm.symbols[self.symbol].is_short_entry_signal:

                market_price = self.algorithm.Securities[self.symbol].Price 
                stop_loss = market_price * (1 + self.algorithm.stop_loss_pct)
                take_profit = market_price * (1 - self.algorithm.take_profit_pct)

                quantity = self.calculate_size(market_price)

                symb = self.algorithm.symbols[self.symbol]

                self.algorithm.debug_with_flag(f"Short entry for {quantity} shares of {self.symbol} @ {market_price} - stop: {stop_loss} - tp: {take_profit} 1 hr close: {symb.slow_window[0].Close} adx: [{symb.adx_window[1].Value}, {symb.adx_window[0].Value}] - tenkan_slow: [{symb.ichimoku_tenkan_slow_window[0]}] - spanB_fast: [{symb.ichimoku_spanB_fast_window[3]}, {symb.ichimoku_spanB_fast_window[2]}, {symb.ichimoku_spanB_fast_window[1]}, {symb.ichimoku_spanB_fast_window[0]}] - tenkan_fast: [{symb.ichimoku_tenkan_fast_window[3]}, {symb.ichimoku_tenkan_fast_window[2]}, {symb.ichimoku_tenkan_fast_window[1]}, {symb.ichimoku_tenkan_fast_window[0]}]")
                self.bracket_order(-quantity, stop_loss, take_profit)
    
    def calculate_size(self, market_price):
        margin = None
        if self.algorithm.use_kelly_criterion_sizing:
            win_ratio = self.algorithm.average_win / self.algorithm.average_loss

            kelly_percent = self.algorithm.win_rate - ((1 - self.algorithm.win_rate) / win_ratio)
            
            margin = kelly_percent * self.algorithm.proportion_of_portfolio * self.algorithm.Portfolio.TotalPortfolioValue

        else:

            margin = self.algorithm.Portfolio.TotalPortfolioValue * self.algorithm.fixed_percentage_positioning

        quantity = margin // market_price

        return quantity
            

    @property
    def order_id(self):
        return self.entry_ticket.OrderId

    def cancel_all_legs(self):
        try:
            self.stop_ticket.Cancel()
            self.profit_ticket.Cancel()
        except:
            self.algorithm.Liquidate(self.symbol, "Bracket Order Error 4")

#region imports
from AlgorithmImports import *
#endregion

class SymbolData:
    
    def __init__(self, 
                    algorithm, 
                    symbol, 
                    fast_resolution, 
                    slow_resolution, 
                    adx_period,
                    adx_threshold,
                    tenkan_period,
                    kijun_period,
                    kumo_cloud_signal_enabled,
                    senkou_span_b_period = 52,
                    cloud_displacement = 26,
                    window_length=78):

        self.algorithm = algorithm
        self.symbol = symbol
        self.adx_threshold = adx_threshold
        self.tenkan_period = tenkan_period
        self.kijun_period = kijun_period
        self.senkou_span_b_period = senkou_span_b_period
        self.cloud_displacement = cloud_displacement

        self.kumo_cloud_signal_enabled = kumo_cloud_signal_enabled
        
        ## Bars

        self.fast_resolution = fast_resolution
        self.slow_resolution = slow_resolution
        
        self.fast_consolidator = TradeBarConsolidator(fast_resolution)
        self.slow_consolidator = TradeBarConsolidator(slow_resolution)
        
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.fast_consolidator)
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.slow_consolidator)
    
        self.fast_consolidator.DataConsolidated += self.__on_fast_bar
        self.slow_consolidator.DataConsolidated += self.__on_slow_bar
        
        self.fast_window = RollingWindow[TradeBar](window_length)
        self.slow_window = RollingWindow[TradeBar](window_length)

        ## ADX

        self.adx = AverageDirectionalIndex(adx_period)
        self.adx.Updated += self.__adx_update_handler
        self.adx_window = RollingWindow[IndicatorDataPoint](window_length)
        self.algorithm.RegisterIndicator(self.symbol, self.adx, self.slow_consolidator)

        # Ichimoku

        self.ichimoku_tenkan_fast_window = RollingWindow[float](window_length)
        self.ichimoku_spanA_fast_window = RollingWindow[float](window_length)
        self.ichimoku_spanB_fast_window = RollingWindow[float](window_length)

        self.ichimoku_tenkan_slow_window = RollingWindow[float](window_length)
        self.ichimoku_spanA_slow_window = RollingWindow[float](window_length)
        self.ichimoku_spanB_slow_window = RollingWindow[float](window_length)

    # DEPRECATED SEE: @calc_ichimoku_fast
    # def calc_ichimoku(self, bars):
        
    #     highs = [bar.High for bar in bars]
    #     lows = [bar.Low for bar in bars]

    #     df = pd.DataFrame({"high": highs, "low": lows})

    #     # Tenkan 
    #     tenkan_sen_high = df['high'].rolling( window=self.tenkan_period ).max()
    #     tenkan_sen_low = df['low'].rolling( window=self.tenkan_period ).min()
    #     df['tenkan_sen'] = (tenkan_sen_high + tenkan_sen_low) /2
    #     # Kijun 
    #     kijun_sen_high = df['high'].rolling( window=self.kijun_period ).max()
    #     kijun_sen_low = df['low'].rolling( window=self.kijun_period ).min()
    #     df['kijun_sen'] = (kijun_sen_high + kijun_sen_low) / 2
    #     # Senkou Span A 
    #     df['senkou_span_a'] = ((df['tenkan_sen'] + df['kijun_sen']) / 2).shift(self.cloud_displacement)
    #     # Senkou Span B 
    #     senkou_span_b_high = df['high'].rolling( window=self.senkou_span_b_period ).max()
    #     senkou_span_b_low = df['low'].rolling( window=self.senkou_span_b_period ).min()
    #     df['senkou_span_b'] = ((senkou_span_b_high + senkou_span_b_low) / 2).shift(self.cloud_displacement)

    #     row = df.iloc[-1]
    #     return row["tenkan_sen"], row["kijun_sen"], row["senkou_span_a"], row["senkou_span_b"]

    def calc_ichimoku_fast(self, bars):

        high = [bar.High for bar in bars]
        low = [bar.Low for bar in bars]

        tenkan_window=self.tenkan_period
        kijun_window=self.kijun_period
        senkou_span_b_window = self.senkou_span_b_period
        cloud_displacement = self.cloud_displacement
        chikou_shift = -26

        shifted_tenkan_window_start = len(low) - cloud_displacement - tenkan_window
        tenkan_sen_high_shifted = max(high[shifted_tenkan_window_start:shifted_tenkan_window_start+tenkan_window+1])
        tenkan_sen_low_shifted = min(low[shifted_tenkan_window_start:shifted_tenkan_window_start+tenkan_window+1])

        tenkan_sen_shifted = (tenkan_sen_high_shifted + tenkan_sen_low_shifted) / 2

        # Kijun 
        shifted_kijun_window_start = len(low) - cloud_displacement - kijun_window
        kijun_high_shifted = max(high[shifted_kijun_window_start:shifted_kijun_window_start+kijun_window+1])
        kijun_low_shifted = min(low[shifted_kijun_window_start:shifted_kijun_window_start+kijun_window+1])


        kijun_shifted = (kijun_high_shifted + kijun_low_shifted) / 2
        # Senkou Span A 
        senkou_span_a = ((tenkan_sen_shifted + kijun_shifted) / 2)
        # Senkou Span B 

        
        span_b_window_start = len(low) - cloud_displacement - senkou_span_b_window
        span_b_high = max(high[span_b_window_start:span_b_window_start+senkou_span_b_window+1])
        span_b_low = min(low[span_b_window_start:span_b_window_start+senkou_span_b_window+1])
        senkou_span_b = ((span_b_high + span_b_low) / 2)





        tenkan_window_start = len(low) - tenkan_window
        tenkan_sen_high = max(high[tenkan_window_start:tenkan_window_start+tenkan_window+1])
        tenkan_sen_low = min(low[tenkan_window_start:tenkan_window_start+tenkan_window+1])

        tenkan_sen = (tenkan_sen_high + tenkan_sen_low) / 2

        # Kijun 
        kijun_window_start = len(low) - kijun_window
        kijun_high = max(high[kijun_window_start:kijun_window_start+kijun_window+1])
        kijun_low = min(low[kijun_window_start:kijun_window_start+kijun_window+1])


        kijun = (kijun_high + kijun_low) / 2

        return tenkan_sen, kijun, senkou_span_a, senkou_span_b

    @property
    def is_long_entry_signal(self):

        #ichimoku signal
        fast_tenkan_3bars_ago = self.ichimoku_tenkan_fast_window[2]
        fast_tenkan_4bars_ago = self.ichimoku_tenkan_fast_window[3]
        fast_spanB_3bars_ago = self.ichimoku_spanB_fast_window[2]
        fast_spanB_4bars_ago = self.ichimoku_spanB_fast_window[3]

        ichimoku_signal = fast_tenkan_4bars_ago > fast_spanB_4bars_ago and fast_tenkan_3bars_ago < fast_spanB_3bars_ago

        # ADX crossover

        adx_above_threshold = self.adx.Current.Value > self.adx_threshold
        
        adx_greater_than_previous = self.adx_window[0].Value > self.adx_window[1].Value

        # Price

        last_close_above_slow_tenkan = self.slow_window[0].Close > self.ichimoku_tenkan_slow_window[0]

        signal = ichimoku_signal and adx_above_threshold and adx_greater_than_previous and last_close_above_slow_tenkan

        if self.kumo_cloud_signal_enabled:
            
            kumo_signal = self.slow_window[0].Close > self.ichimoku_spanA_slow_window[0] and \
                            self.slow_window[0].Close > self.ichimoku_spanB_slow_window[0]
            
            signal = signal and kumo_signal

        return signal

    @property
    def is_short_entry_signal(self):

        #ichimoku signal
        fast_tenkan_3bars_ago = self.ichimoku_tenkan_fast_window[2]
        fast_tenkan_4bars_ago = self.ichimoku_tenkan_fast_window[3]
        fast_spanB_3bars_ago = self.ichimoku_spanB_fast_window[2]
        fast_spanB_4bars_ago = self.ichimoku_spanB_fast_window[3]

        ichimoku_signal = fast_tenkan_4bars_ago < fast_spanB_4bars_ago and fast_tenkan_3bars_ago > fast_spanB_3bars_ago

        # ADX crossover

        adx_above_threshold = self.adx.Current.Value > self.adx_threshold
        
        adx_greater_than_previous = self.adx_window[0].Value > self.adx_window[1].Value

        # Price

        last_close_below_slow_tenkan = self.slow_window[0].Close < self.ichimoku_tenkan_slow_window[0]

        signal = ichimoku_signal  and adx_above_threshold and adx_greater_than_previous and last_close_below_slow_tenkan
        
        if self.kumo_cloud_signal_enabled:
            
            kumo_signal = self.slow_window[0].Close < self.ichimoku_spanA_slow_window[0] and \
                            self.slow_window[0].Close < self.ichimoku_spanB_slow_window[0]
            
            signal = signal and kumo_signal

        return signal

    @property
    def is_long_exit_signal(self):
        
        tenkan_crosses_above_spanB = self.ichimoku_tenkan_fast_window[1] < self.ichimoku_spanB_fast_window[1] and \
        self.ichimoku_tenkan_fast_window[0] > self.ichimoku_spanB_fast_window[0]

        return tenkan_crosses_above_spanB

    @property
    def is_short_exit_signal(self):
        
        tenkan_crosses_below_spanB = self.ichimoku_tenkan_fast_window[1] > self.ichimoku_spanB_fast_window[1] and \
        self.ichimoku_tenkan_fast_window[0] < self.ichimoku_spanB_fast_window[0]

        return tenkan_crosses_below_spanB


    def remove_consolidators(self):
        algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.fast_consolidator)
        algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.slow_consolidator)
    
    def __on_fast_bar(self, sender, bar):
        self.fast_window.Add(bar)

        if self.fast_window.IsReady:
            tenkan, kijun, span_a, span_b = self.calc_ichimoku_fast(self.fast_window)
            self.ichimoku_tenkan_fast_window.Add(tenkan)
            self.ichimoku_spanA_fast_window.Add(span_a) # SPAN A
            self.ichimoku_spanB_fast_window.Add(span_b) # SPAN B
    
    def __on_slow_bar(self, sender, bar):
        self.slow_window.Add(bar)
        # self.adx.Update(bar)

        if self.slow_window.IsReady:
            tenkan, kijun, span_a, span_b = self.calc_ichimoku_fast(self.slow_window)
            self.ichimoku_tenkan_slow_window.Add(tenkan)
            self.ichimoku_spanA_slow_window.Add(span_a) # SPAN A
            self.ichimoku_spanB_slow_window.Add(span_b) # SPAN B
            
    def __adx_update_handler(self, indicator, IndicatorDataPoint):
        if self.adx.IsReady:
            self.adx_window.Add(self.adx.Current)

    @property
    def is_ready(self):
        return self.fast_window.IsReady and self.slow_window.IsReady and self.adx_window.IsReady and \
                    self.ichimoku_tenkan_fast_window.IsReady and self.ichimoku_spanA_slow_window.IsReady
           
#region imports
from AlgorithmImports import *
#endregion

tickers = [
"BLK",
"LRCX",
"ASML",
"NOW",
"ADBE",
"LLY",
"COST",
"INTU",
"KLAC",
"UNH",
"MPWR",
"SNPS",
"HUM",
"NVDA",
"URI",
"TMO",
"NFLX",
"HUBS",
"MCK",
"LMT",
"PH",
"LULU",
"CHTR",
"LIN",
"SPGI",
"ODFL",
"MA",
"DE",
"MSFT",
"BRK/B",
"MCO",
"VRTX",
"GS",
# "META",
# "AON",
# "ACN",
# "MSI",
# "HD",
# "ISRG",
# "SYK",
# "MCD",
# "APD",
# "ROK",
# "SHW",
# "AMGN",
# "CDNS",
# "FDX",
# "V",
# "CAT",
# "AJG",
# "GD",
# "WTW",
# "PANW",
# "HCA",
# "ITW",
# "VRSK",
# "STZ",
# "SBAC",
# "BDX",
# "TSLA",
# "PXD",
# "WDAY",
# "ADP",
# "BIIB",
# "ETN",
# "TT",
# "CMI",
# "CB",
# "CRM",
# "UNP",
# "CDW",
# "ADSK",
# "ANET",
# "SGEN",
# "VMC",
# "CME",
# "VRSN",
# "DHR",
# "NSC",
# "BA",
# "IQV",
# "CRWD",
# "MAR",
# "TSCO",
# "LOW",
# "NXPI",
# "EFX",
# "AMT",
# "MMC",
# "HSY",
# "HON",
# "AAPL",
# "TEAM",
# "LHX",
# "ZS",
# "ECL",
# "PWR",
# "ADI",
# "ZTS",
# "VEEV",
# "SPOT",
# "LNG",
# "TRV",
# "WM",
# "AVB",
# "PEP",
# "HLT",
# "FERG",
# "SNOW",
# "PGR",
# "AXP",
# "RSG",
# "WMT",
# "NUE",
# "TTWO",
# "AMAT",
# "AME",
# "IBM",
# "PG",
# "FANG",
# "TXN",
# "JPM",
# "SPLK",
# "JNJ",
# "RMD",
# "TMUS",
# "UPS",
# "MPC",
# "AMZN",
# "CVX",
# "HES",
# "GOOG",
# "ABBV",
# "GOOGL",
# "PPG",
# "DLR",
# "WCN",
# "ALL",
# "EA",
# "KEYS",
# "TEL",
# "AWK",
# "EXR",
# "TGT",
# "PNC",
# "QCOM",
# "YUM",
# "DHI",
# "LEN",
# "ABNB",
# "FI",
# "MTB",
# "EL",
# "VLO",
# "KMB",
# "CEG",
# "EOG",
# "ROST",
# "AMD",
# "GE",
# "DG",
# "PAYX",
# "WAB",
# "ORCL",
# "A",
# "DLTR",
# "PSX",
# "PDD",
# "NTES",
# "ICE",
# "COP",
# "GPN",
# "ZBH",
# "PLD",
# "BIDU",
# "DDOG",
# "NKE",
# "SBUX",
# "COF",
# "DXCM",
# "CCI",
# "BX",
# "RCL",
# "DTE",
# "CAH",
# "XOM",
# "MRK",
# "XYL",
# "ABT",
# "NVO",
# "ETR",
# "TSM",
# "TROW",
# "LYB",
# "MMM",
# "DASH",
# "DIS",
# "NVS",
# "CHD",
# "PM",
# "ED",
# "PCAR",
# "DUK",
# "APH",
# "LYV",
# "TJX",
# "EMR",
# "WELL",
# "APO",
# "DFS",
# "WEC",
# "CSGP",
# "MCHP",
# "AFL",
# "RTX",
# "MS",
# "APTV",
# "BABA",
# "CBRE",
# "AEP",
# "AEE",
# "MU",
# "MRNA",
# "HIG",
# "CL",
# "MDT",
# "GILD",
# "ADM",
# "CNC",
# "DELL",
# "SRE",
# "GEHC",
# "CP",
# "NET",
# "SYY",
# "MDLZ",
# "DD",
# "SO",
# "IR",
# "ON",
# "CTSH",
# "CVS",
# "FTV",
# "EW",
# "SHOP",
# "TTD",
# "KKR",
# "EIX",
# "OKE",
# "GIS",
# "SHEL",
# "AIG",
# "CNQ",
# "AZN",
# "MET",
# "XEL",
# "FAST",
# "OXY",
# "ES",
# "KO",
# "PYPL",
# "NEE",
# "SQ",
# "MNST",
# "BSX",
# "MRVL",
# "UBER",
# "FIS",
# "O",
# "CARR",
# "SLB",
# "JCI",
# "HWM",
# "DOW",
# "BMY",
# "FTNT",
# "CPRT",
# "LVS",
# "CSCO",
# "D",
# "C",
# "DVN",
# "INTC",
# "KR",
# "WFC",
# "CMCSA",
# "MO",
# "EBAY",
# "EXC",
# "LI",
# "RBLX",
# "SE",
# "USB",
# "HAL",
# "NEM",
# "VZ",
# "FCX",
# "DAL",
# "BP",
# "WMB",
# "KHC",
# "BKR",
# "ENB",
# "SU",
# "KDP",
# "TFC",
# "CSX",
# "PINS",
# "PFE",
# "BAC",
# "HPQ",
# "JD",
# "GM"
]