I wrote this but instead of buying when stocks are oversold and selling when stocks are over bought, the algo buys when stocks are overbought and price is > sma and sell when stocks are oversold and price is < sma.  I used tech stocks. It was an error at first but then I rationalized it by thinking that stocks are traded algorithmically so much that stocks have a little more volatility that can be taken advantage at highs and lows.  It was fun to write

 

# region imports

from AlgorithmImports import *

# endregion


 

class AlertMagentaParrot(QCAlgorithm):

    def Initialize(self) -> None:

        self.SetStartDate(2017, 1, 1)

        self.SetEndDate(2020, 12, 31)

        self.SetCash(50000)


 

        # Add symbols

        self.docu_symbol = self.AddEquity("DOCU", Resolution.Daily).Symbol

        self.amd_symbol = self.AddEquity("AMD", Resolution.Daily).Symbol

        self.nflx_symbol = self.AddEquity("NFLX", Resolution.Daily).Symbol

        self.tsla_symbol = self.AddEquity("TSLA", Resolution.Daily).Symbol

        self.goog_symbol = self.AddEquity("GOOG", Resolution.Daily).Symbol


 

        # RSI for DOCU

        self.docu_rsi = self.RSI(self.docu_symbol, 3)

        self.docu_periods_above_70 = 0

        self.docu_periods_below_30 = 0


 

        # RSI for AMD

        self.amd_rsi = self.RSI(self.amd_symbol, 3)

        self.amd_periods_above_70 = 0

        self.amd_periods_below_30 = 0


 

        # RSI for nflx

        self.nflx_rsi = self.RSI(self.nflx_symbol, 3)

        self.nflx_periods_above_70 = 0

        self.nflx_periods_below_30 = 0


 

         # RSI for tsla

        self.tsla_rsi = self.RSI(self.tsla_symbol, 3)

        self.tsla_periods_above_70 = 0

        self.tsla_periods_below_30 = 0


 

         # RSI for GOOG

        self.goog_rsi = self.RSI(self.goog_symbol, 3)

        self.goog_periods_above_70 = 0

        self.goog_periods_below_30 = 0


 

        self.sma_period = 21

        self.docu_sma_symbol = self.docu_symbol  # SMA based on DOCU, you can change this if needed

        self.amd_sma_symbol = self.amd_symbol # SMA based on amd

        self.nflx_sma_symbol = self.nflx_symbol # SMA based on nflx

        self.tsla_sma_symbol = self.tsla_symbol # sma based on tsla

        self.goog_sma_symbol = self.goog_symbol # sma based on goog


 

        # SMA runs every day after market open

        self.Schedule.On(self.DateRules.EveryDay(self.docu_sma_symbol),

                          self.TimeRules.AfterMarketOpen(self.docu_sma_symbol, 1),

                          self.Rebalance)


 

        self.Schedule.On(self.DateRules.EveryDay(self.amd_sma_symbol),

                          self.TimeRules.AfterMarketOpen(self.amd_sma_symbol, 1),

                          self.Rebalance)


 

        self.Schedule.On(self.DateRules.EveryDay(self.nflx_sma_symbol),

                          self.TimeRules.AfterMarketOpen(self.nflx_sma_symbol, 1),

                          self.Rebalance)

                         

        self.Schedule.On(self.DateRules.EveryDay(self.tsla_sma_symbol),

                          self.TimeRules.AfterMarketOpen(self.tsla_sma_symbol, 1),

                          self.Rebalance)


 

        self.Schedule.On(self.DateRules.EveryDay(self.goog_sma_symbol),

                          self.TimeRules.AfterMarketOpen(self.goog_sma_symbol, 1),

                          self.Rebalance)


 

       


 

    def OnData(self, slice: Slice) -> None:

        # Check if there is enough data to compute SMA

        if self.IsWarmingUp:

            return


 

        # Check if the symbols are in the slice

        if self.docu_sma_symbol not in slice.Keys or self.docu_symbol not in slice.Keys:

            return

       

        if self.amd_sma_symbol not in slice.Keys or self.amd_symbol not in slice.Keys:

            return


 

        if self.nflx_sma_symbol not in slice.Keys or self.nflx_symbol not in slice.Keys:

            return


 

        if self.tsla_sma_symbol not in slice.Keys or self.tsla_symbol not in slice.Keys:

            return


 

        if self.goog_sma_symbol not in slice.Keys or self.goog_symbol not in slice.Keys:

            return


 

        # Access historical data for SMA calculation

        docu_history = self.History(self.docu_symbol, self.sma_period, Resolution.Daily)

        amd_history = self.History(self.amd_symbol, self.sma_period, Resolution.Daily)

        nflx_history = self.History(self.nflx_symbol, self.sma_period, Resolution.Daily)

        tsla_history = self.History(self.tsla_symbol, self.sma_period, Resolution.Daily)

        goog_history = self.History(self.goog_symbol, self.sma_period, Resolution.Daily)


 

        # Calculate SMA for DOCU

        if not docu_history.empty:

            docu_sma = docu_history["close"].mean()

            docu_current_price = slice.Bars[self.docu_symbol].Close


 

            # Buying and Selling Logic for DOCU (similar logic can be applied to amd)

            if self.docu_rsi.Current.Value > 70:

                self.docu_periods_above_70 += 1

                if self.docu_periods_above_70 == 2 and docu_current_price > docu_sma:

                    self.LimitOrder("DOCU", 100, docu_current_price)

                   

            else:

                self.docu_periods_above_70 = 0


 

            if self.docu_rsi.Current.Value < 30:

                self.docu_periods_below_30 += 1

                if self.docu_periods_below_30 == 2 and docu_current_price < docu_sma:

                    if self.Portfolio[self.docu_symbol].Quantity >= 100:

                        self.LimitOrder("DOCU", -100, docu_current_price)

                   

            else:

                self.docu_periods_below_30 = 0


 

        # Calculate SMA for amd (similar logic can be applied to DOCU)

        if not amd_history.empty:

            amd_sma = amd_history["close"].mean()

            amd_current_price = slice.Bars[self.amd_symbol].Close


 

            # Buying and Selling Logic for amd

            if self.amd_rsi.Current.Value > 70:

                self.amd_periods_above_70 += 1

                if self.amd_periods_above_70 == 2 and amd_current_price > amd_sma:

                    self.LimitOrder("AMD", 40, amd_current_price)

                 

            else:

                self.amd_periods_above_70 = 0


 

            if self.amd_rsi.Current.Value < 30:

                self.amd_periods_below_30 += 1

                if self.amd_periods_below_30 == 2 and amd_current_price < amd_sma:

                    if self.Portfolio[self.amd_symbol].Quantity >= 40:

                        self.LimitOrder("AMD", -40, amd_current_price)

                   

            else:

                self.amd_periods_below_30 = 0


 

        # Calculate SMA for nflx(similar logic can be applied to nflx)

        if not nflx_history.empty:

            nflx_sma = nflx_history["close"].mean()

            nflx_current_price = slice.Bars[self.nflx_symbol].Close


 

            # Buying and Selling Logic for amd

            if self.nflx_rsi.Current.Value > 70:

                self.nflx_periods_above_70 += 1

                if self.nflx_periods_above_70 == 2 and nflx_current_price > nflx_sma:

                    self.LimitOrder("nflx", 10, nflx_current_price)

                   

            else:

                self.nflx_periods_above_70 = 0


 

            if self.nflx_rsi.Current.Value < 30:

                self.nflx_periods_below_30 += 1

                if self.nflx_periods_below_30 == 2 and nflx_current_price < nflx_sma:

                    if self.Portfolio[self.nflx_symbol].Quantity >= 10:

                        self.LimitOrder("nflx", -10, nflx_current_price)

                 

            else:

                self.nflx_periods_below_30 = 0


 

        # Calculate SMA for tsla

        if not tsla_history.empty:

            tsla_sma = tsla_history["close"].mean()

            tsla_current_price = slice.Bars[self.tsla_symbol].Close


 

            # Buying and Selling Logic for tsla (similar logic can be applied to amd)

            if self.tsla_rsi.Current.Value > 70:

                self.tsla_periods_above_70 += 1

                if self.tsla_periods_above_70 == 2 and tsla_current_price > tsla_sma:

                    self.LimitOrder("tsla", 21, tsla_current_price)

                   

            else:

                self.tsla_periods_above_70 = 0


 

            if self.tsla_rsi.Current.Value < 30:

                self.tsla_periods_below_30 += 1

                if self.tsla_periods_below_30 == 2 and tsla_current_price < tsla_sma:

                    if self.Portfolio[self.tsla_symbol].Quantity >= 21:

                        self.LimitOrder("tsla", -21, tsla_current_price)

                   

            else:

                self.tsla_periods_below_30 = 0


 

        # Calculate SMA for GOOG

        if not goog_history.empty:

            goog_sma = goog_history["close"].mean()

            goog_current_price = slice.Bars[self.goog_symbol].Close


 

            # Buying and Selling Logic for goog (similar logic can be applied to amd)

            if self.goog_rsi.Current.Value > 70:

                self.goog_periods_above_70 += 1

                if self.goog_periods_above_70 == 2 and goog_current_price > goog_sma:

                    self.LimitOrder("GOOG", 65, goog_current_price)

                   

            else:

                self.goog_periods_above_70 = 0


 

            if self.goog_rsi.Current.Value < 30:

                self.goog_periods_below_30 += 1

                if self.goog_periods_below_30 == 2 and goog_current_price < goog_sma:

                    if self.Portfolio[self.goog_symbol].Quantity >= 65:

                        self.LimitOrder("GOOG", -65, goog_current_price)

                   

            else:

                self.goog_periods_below_30 = 0


 

    def Rebalance(self):

        # Rebalance logic goes here

        pass

       

        if self.docu_rsi.IsReady:

            # The current value of self.rsi is represented by self.rsi.Current.Value

            self.Plot("RelativeStrengthIndex", "rsi", self.docu_rsi.Current.Value)

            # Plot all attributes of self.rsi

            self.Plot("RelativeStrengthIndex", "averagegain", self.docu_rsi.AverageGain.Current.Value)

            self.Plot("RelativeStrengthIndex", "averageloss", self.docu_rsi.AverageLoss.Current.Value)


 

        if self.amd_rsi.IsReady:

            # The current value of self.rsi is represented by self.rsi.Current.Value

            self.Plot("RelativeStrengthIndex", "rsi", self.amd_rsi.Current.Value)

            # Plot all attributes of self.rsi

            self.Plot("RelativeStrengthIndex", "averagegain", self.amd_rsi.AverageGain.Current.Value)

            self.Plot("RelativeStrengthIndex", "averageloss", self.amd_rsi.AverageLoss.Current.Value)

       

        if self.nflx_rsi.IsReady:

            # The current value of self.rsi is represented by self.rsi.Current.Value

            self.Plot("RelativeStrengthIndex", "rsi", self.nflx_rsi.Current.Value)

            # Plot all attributes of self.rsi

            self.Plot("RelativeStrengthIndex", "averagegain", self.nflx_rsi.AverageGain.Current.Value)

            self.Plot("RelativeStrengthIndex", "averageloss", self.nflx_rsi.AverageLoss.Current.Value)


 

        if self.tsla_rsi.IsReady:

            # The current value of self.rsi is represented by self.rsi.Current.Value

            self.Plot("RelativeStrengthIndex", "rsi", self.tsla_rsi.Current.Value)

            # Plot all attributes of self.rsi

            self.Plot("RelativeStrengthIndex", "averagegain", self.tsla_rsi.AverageGain.Current.Value)

            self.Plot("RelativeStrengthIndex", "averageloss", self.tsla_rsi.AverageLoss.Current.Value)


 

        if self.goog_rsi.IsReady:

            # The current value of self.rsi is represented by self.rsi.Current.Value

            self.Plot("RelativeStrengthIndex", "rsi", self.goog_rsi.Current.Value)

            # Plot all attributes of self.rsi

            self.Plot("RelativeStrengthIndex", "averagegain", self.goog_rsi.AverageGain.Current.Value)

            self.Plot("RelativeStrengthIndex", "averageloss", self.goog_rsi.AverageLoss.Current.Value)