Overall Statistics
Total Trades
58
Average Win
1.96%
Average Loss
-0.83%
Compounding Annual Return
211.714%
Drawdown
15.700%
Expectancy
0.495
Net Profit
14.570%
Sharpe Ratio
4.115
Probabilistic Sharpe Ratio
74.355%
Loss Rate
56%
Win Rate
44%
Profit-Loss Ratio
2.36
Alpha
1.523
Beta
0.537
Annual Standard Deviation
0.328
Annual Variance
0.108
Information Ratio
5.144
Tracking Error
0.325
Treynor Ratio
2.513
Total Fees
$71.38
Estimated Strategy Capacity
$58000.00
Lowest Capacity Asset
TYO UBTUG7D0B7TX
from AlgorithmImports import *
from collections import deque


class CustomDrawdown():



    def __init__(self, algorithm, symbol, drawdown_period):
        self.algorithm = algorithm
        self.drawdown_period = drawdown_period 
        self.High_Queue = deque(maxlen=self.drawdown_period)
        self.Low_Queue = deque(maxlen=self.drawdown_period)
        self.symbol = symbol
        self.Current_Value = None
      

        self.First_Intraday_Update_Of_Day = True
        self.Last_Main_Bar = None
     

        self.New_Main_Bar = True
        self.WarmUP = True
        self.Updated_Today = False
        

    
    def Receive_Main_Bar(self, bar):
        if not self.First_Intraday_Update_Of_Day:
            del self.High_Queue[0]
            del self.Low_Queue[0]
            self.New_Main_Bar = True
        self.High_Queue.appendleft(bar.High)
        self.Low_Queue.appendleft(bar.Low)
       
        


        if len(self.High_Queue) == self.drawdown_period and len(self.Low_Queue) == self.drawdown_period:
            self.Calculate_Drawdown()
    

    def Receive_Sub_Bar(self, high, low):
        if len(self.High_Queue) == self.drawdown_period and len(self.Low_Queue) == self.drawdown_period:
            if self.First_Intraday_Update_Of_Day:
                self.Last_Main_High = self.High_Queue[0]
                self.Last_Main_Low = self.Low_Queue[0]
          
                self.High_Queue.appendleft(high)
                self.Low_Queue.appendleft(low)
                self.First_Intraday_Update_Of_Day = False
            else:
                del self.High_Queue[0]
                del self.Low_Queue[0]
                self.High_Queue.appendleft(high)
                self.Low_Queue.appendleft(low)


            self.Calculate_Drawdown()
                


    

    def Calculate_Drawdown(self):
       
        
        #Drawdown needs to check that the LOW occurs AFTER the high! LOL
       
        if len(self.High_Queue) == self.drawdown_period and len(self.Low_Queue) == self.drawdown_period:
            
            high = 0
            idx = None

            #if self.algorithm.Time.hour < 23 and self.algorithm.Time.hour > 14 and self.symbol == "SPY" and self.drawdown_period == 8:
                #self.algorithm.Debug(f"H {self.High_Queue} {self.symbol}")
                #self.algorithm.Debug(f"L {self.Low_Queue} {self.symbol}")
            for i in range(0, len(self.High_Queue)):
                if self.High_Queue[i] > high:
                    high = self.High_Queue[i]
                    idx = i

            low = 100000000
            for i in range(0, idx+1):
                if self.Low_Queue[i] < low:
                    low = self.Low_Queue[i]
            #if self.algorithm.Time.hour < 23 and self.algorithm.Time.hour > 14 and self.symbol == "SPY" and self.drawdown_period == 8:
                #self.algorithm.Debug(f"HH {high} LL {low}")
            hh = high
            ll = low
            self.Current_Value = abs((ll - hh) / hh)
           
           
            if self.New_Main_Bar:
                self.First_Intraday_Update_Of_Day = True
                

            self.New_Main_Bar = False
from AlgorithmImports import *
from collections import deque


class Intraday_Updating_SMA():



    def __init__(self, algorithm, sma_period):
        self.algorithm = algorithm
        self.sma_period = sma_period
        self.Bar_Queue = deque(maxlen=self.sma_period)

        self.Current_Value = None
      

        self.First_Intraday_Update_Of_Day = True
        self.Last_Main_Bar = None
        
        self.Updated_Today = False

        self.New_Main_Bar = True
        self.WarmUP = True
        

    
    def Receive_Main_Bar(self, bar):
        if not self.First_Intraday_Update_Of_Day:
            del self.Bar_Queue[0]
            self.New_Main_Bar = True
        self.Bar_Queue.appendleft(bar.Close)
       
        


        if len(self.Bar_Queue) == self.sma_period:
            self.Calculate_SMA()
    

    def Receive_Sub_Bar(self, bar):
        if len(self.Bar_Queue) == self.sma_period:
            if self.First_Intraday_Update_Of_Day:
                self.Last_Main_Bar = self.Bar_Queue[0]
          
                self.Bar_Queue.appendleft(bar)
                self.First_Intraday_Update_Of_Day = False
            else:
                del self.Bar_Queue[0]
                self.Bar_Queue.appendleft(bar)


            self.Calculate_SMA()
                


    

    def Calculate_SMA(self):
       
        
  
    
        if len(self.Bar_Queue) == self.sma_period:
         
            self.Current_Value = sum(self.Bar_Queue) / len(self.Bar_Queue)
           
           
            if self.New_Main_Bar:
                self.First_Intraday_Update_Of_Day = True
                

            self.New_Main_Bar = False
           

   





from AlgorithmImports import *
from collections import deque


class Intraday_Updating_Cumulative_Return():



    def __init__(self, algorithm, return_period):
        self.algorithm = algorithm
        self.return_period = return_period +1
        self.Bar_Queue = deque(maxlen=self.return_period)

        self.Current_Value = None
      

        self.First_Intraday_Update_Of_Day = True
        self.Last_Main_Bar = None
     

        self.New_Main_Bar = True
        self.WarmUP = True
        self.Updated_Today = False
        

    
    def Receive_Main_Bar(self, bar):
        if not self.First_Intraday_Update_Of_Day:
            del self.Bar_Queue[0]
            self.New_Main_Bar = True
        self.Bar_Queue.appendleft(bar.Close)
       
        


        if len(self.Bar_Queue) == self.return_period:
            self.Calculate_Cumulative_Return()
    

    def Receive_Sub_Bar(self, bar):
        if len(self.Bar_Queue) == self.return_period:
            if self.First_Intraday_Update_Of_Day:
                self.Last_Main_Bar = self.Bar_Queue[0]
          
                self.Bar_Queue.appendleft(bar)
                self.First_Intraday_Update_Of_Day = False
            else:
                del self.Bar_Queue[0]
                self.Bar_Queue.appendleft(bar)


            self.Calculate_Cumulative_Return()
                


    

    def Calculate_Cumulative_Return(self):
       
        
  
    
        if len(self.Bar_Queue) == self.return_period:
         
            self.Current_Value = (self.Bar_Queue[0] - self.Bar_Queue[self.return_period-1]) / self.Bar_Queue[self.return_period-1]
           
           
            if self.New_Main_Bar:
                self.First_Intraday_Update_Of_Day = True
                

            self.New_Main_Bar = False
           

   





"""
**
* TQQQ_OG_ganesh v2  https://app.composer.trade/symphony/aPKwOIvIgAVB8q0NUSj3/details

*
*                  
* Description:      This Strategy rebalances ETF's based on various Indicators
**
"""







from AlgorithmImports import *
from custom_sma import Intraday_Updating_SMA
from custom_cumulative_return import Intraday_Updating_Cumulative_Return
from custom_rsi import Intraday_Updating_RSI
from custom_drawdown import CustomDrawdown
import config


class  ETF_Rebalancing(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(config.BACKTEST_START_YEAR, config.BACKTEST_START_MONTH, config.BACKTEST_START_DAY)   # Set Backtest Start Date
        self.SetEndDate(config.BACKTEST_END_YEAR, config.BACKTEST_END_MONTH, config.BACKTEST_END_DAY)           # Set Backtest End Date       
        self.SetCash(config.BACKTEST_ACCOUNT_CASH)                                                              # Set Backtest Strategy Cash

        self.Rebalance_Threshold = config.REBALANCE_THRESHOLD/100
        self.UniverseSettings.Leverage = 4
        self.TECL = None
        self.SOXL = None
        self.FAS = None
        self.TQQQ = None
        self.UPRO = None
        self.TMF = None
        self.USDO = None
        self.SQQQ = None
        self.TBF = None
        self.BIL = None
        self.PHDG = None
        self.TMV = None
        self.UDOW = None
        self.MOAT = None
        self.BRKB = None  
        self.USMV = None
        self.SPY = None
        self.QQQ = None
        self.SPXL = None
        self.DBC = None
        self.DBA = None
        self.ICSH = None
        self.TYD = None
        self.URTY = None
        self.XLU = None
        self.NUGT = None
        self.TYO = None
        self.VIXM = None
        self.IEF = None
        self.SOXS = None
        self.BND = None
        self.VTI = None
        self.SHY = None
        self.USDU = None
        self.TLT = None
        self.UVXY = None


        
     
        
        # if (config.CASH_BUFFER * ) != 0:
        #     (config.CASH_BUFFER * ) = (config.CASH_BUFFER * )/100
        # else:
        #     (config.CASH_BUFFER * ) = 0

      


        self.Sub_4_List = []


        self.Symbol_List = []
        self.ETFs = config.ETFS
        self.Trade_Decision_Time = config.TRADE_DECISION_TIME
        self.Order_Delay = config.ORDER_DELAY # Enable this for Delayed orders
        self.Update_Intraday = False
        self.Trade_Decision = False

        for etf in self.ETFs:
            try:
                self.Symbol_List.append(self.AddEquity(etf, Resolution.Minute, dataNormalizationMode=DataNormalizationMode.Adjusted).Symbol)
            except:
                self.Debug(f"Unable to add stock {etf} to the algorithm")


        self.Symbol_Dictionary = {}

        for symbol in self.Symbol_List:
            self.Symbol_Dictionary[symbol] = SymbolData(self, symbol)

        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", self.Trade_Decision_Time), self.Set_Update_Intraday)

        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", self.Trade_Decision_Time - self.Order_Delay), self.Delayed_Orders)

    def Set_Update_Intraday(self):
        self.Update_Intraday = True
        self.Trade_Decision = True



    def Orders(self):
        for symbol in self.Symbol_Dictionary.keys():
            Symbol_Object = self.Symbol_Dictionary[symbol]
            if Symbol_Object.Current_Position < (Symbol_Object.Counter - self.Rebalance_Threshold) or Symbol_Object.Current_Position > (Symbol_Object.Counter + self.Rebalance_Threshold):
                if Symbol_Object.Counter <= 0:
                    self.Liquidate(symbol)
                    
        
        if not config.USE_ORDER_DELAY:
            for symbol in self.Symbol_Dictionary.keys():
                Symbol_Object = self.Symbol_Dictionary[symbol]
                if Symbol_Object.Current_Position < (Symbol_Object.Counter - self.Rebalance_Threshold) or Symbol_Object.Current_Position > (Symbol_Object.Counter + self.Rebalance_Threshold):     
                    if Symbol_Object.Counter >= 0:
                        self.SetHoldings(symbol, Symbol_Object.Counter, tag=f"{Symbol_Object.Function}") # Disable this for Delayed orders
                elif not self.Portfolio[symbol].Invested and Symbol_Object.Current_Position == 0 and Symbol_Object.Counter > 0:
                    self.SetHoldings(symbol, Symbol_Object.Counter, tag=f"{Symbol_Object.Function}")
   

    # Enable this for Delayed orders
    def Delayed_Orders(self):
        if config.USE_ORDER_DELAY:
            for symbol in self.Symbol_Dictionary.keys():
                Symbol_Object = self.Symbol_Dictionary[symbol]
                if Symbol_Object.Current_Position < (Symbol_Object.Counter - self.Rebalance_Threshold) or Symbol_Object.Current_Position > (Symbol_Object.Counter + self.Rebalance_Threshold):     
                    if Symbol_Object.Counter >= 0:
                        self.SetHoldings(symbol, Symbol_Object.Counter, tag=f"{Symbol_Object.Function}") 
                elif not self.Portfolio[symbol].Invested and Symbol_Object.Current_Position == 0 and Symbol_Object.Counter > 0:
                    self.SetHoldings(symbol, Symbol_Object.Counter, tag=f"{Symbol_Object.Function}")


    def Main_Strategy(self):
       
       
        if self.SPY.Drawdown_8.Current_Value < 0.03:
         
            self.OG_v1_2_Risk_On_Off_Hedgefund()
            self.Hedged_Leveraged_Bonds_Stocks_V2()
        else:
            if self.SHY.Rsi_18.Current_Value > self.VTI.Rsi_20.Current_Value:
                self.V2_Fund_Surfing_Michael_B()
            else:
                self.QS_Pop_Bot_LETF_AWP()

    
    def OG_v1_2_Risk_On_Off_Hedgefund(self):
       
        if self.VIXM.Rsi_40.Current_Value > 69:
            self.Risk_Off_Market_Crash()
        else:
            if self.BND.Return_60.Current_Value > self.BIL.Return_60.Current_Value:
                self.Risk_On_Normal_Market_Conditions()
            else:
                if self.TLT.Return_20.Current_Value < self.BIL.Return_20.Current_Value:
                    self.Risk_Off_Rising_Rates()
                else:
                    self.Risk_On_Falling_Rates_HFEA()

      
    def Risk_Off_Market_Crash(self):
        self.SHY.Counter += 0.8 - (config.CASH_BUFFER * 0.8) 
    

    def Risk_On_Normal_Market_Conditions(self):
        self.Sub_Strategy_1()
        self.TMF.Counter += 0.36 - (config.CASH_BUFFER * 0.36)
    

    def Sub_Strategy_1(self):
      
        rsi_list = [(self.TECL, self.TECL.Rsi_10.Current_Value), 
                    (self.SOXL, self.SOXL.Rsi_10.Current_Value), 
                    (self.FAS, self.FAS.Rsi_10.Current_Value),
                    (self.TQQQ, self.TQQQ.Rsi_10.Current_Value),
                    (self.UPRO, self.UPRO.Rsi_10.Current_Value)
                    ]
                
        sorted_rsi_list = sorted(rsi_list, key=lambda x: x[1], reverse=False)
        counter_ = 0
        for symbol, symbol_return in sorted_rsi_list:
            if counter_ >= 3:
                break
            symbol.Counter += 0.146 - (config.CASH_BUFFER * 0.146) # Ganesh - Changed from 0.183 to 0.146
            counter_ += 1


    def Risk_Off_Rising_Rates(self):
        self.USDU.Counter += 0.4 - (config.CASH_BUFFER * 0.4) # Ganesh - Changed from 0.22 to 0.4
        self.Sub_Strategy_2()
    

    def Sub_Strategy_2(self):
        if self.SQQQ.Rsi_20.Current_Value < self.TBF.Rsi_20.Current_Value:
            self.SQQQ.Counter += 0.4 - (config.CASH_BUFFER * 0.4) # Ganesh - Changed from 0.22 to 0.4
        else:
            self.TBF.Counter += 0.4 - (config.CASH_BUFFER * 0.4)  # Ganesh - Changed from 0.22 to 0.4
    

    def Risk_On_Falling_Rates_HFEA(self):
        if self.SPY.Drawdown_10.Current_Value < 0.05:
            self.HFEA_Refined_Risk_On()
        else:
            self.HFEA_Refined_Risk_Off()
    

    def HFEA_Refined_Risk_On(self):
        self.UPRO.Counter += 0.44 - (config.CASH_BUFFER * 0.44)
        self.TMF.Counter += 0.36 - (config.CASH_BUFFER * 0.36)
    

    def HFEA_Refined_Risk_Off(self):
        self.BIL.Counter += 0.8 - (config.CASH_BUFFER * 0.8)  # Ganesh Updated self.Bil with self.BIL
    

    def Hedged_Leveraged_Bonds_Stocks_V2(self):
       
        if self.Securities["TLT"].Price > self.TLT.SMA_150.Current_Value:
           
            #self.Debug(f"TLT_Price & TLT.SMA_150 {self.Securities['TLT'].Price} & {self.TLT.SMA_150.Current_Value}")
            self.UPRO.Counter += 0.066 - (config.CASH_BUFFER * 0.066)
            self.UPRO.Function = "Hedged_Leveraged_Bonds_Stocks_V2 TLT > TLT_150_SMA"
            self.TMF.Counter += 0.066 - (config.CASH_BUFFER * 0.066)
            self.TMF.Function = "Hedged_Leveraged_Bonds_Stocks_V2 TLT > TLT_150_SMA"
            self.PHDG.Counter += 0.066 - (config.CASH_BUFFER * 0.066)
            self.PHDG.Function = "Hedged_Leveraged_Bonds_Stocks_V2 TLT > TLT_150_SMA"
        else:
            if self.Securities["TLT"].Price < self.TLT.SMA_23.Current_Value:
                #self.Debug(f"TLT_Price & TLT.SMA_23 {self.Securities['TLT'].Price} & {self.TLT.SMA_23.Current_Value}")
                return_list = [(self.TMV, self.TMV.Return_5.Current_Value), 
                                (self.UDOW, self.UDOW.Return_5.Current_Value), 
                                (self.BIL, self.BIL.Return_5.Current_Value),
                                ]
                
                sorted_return_list = sorted(return_list, key=lambda x: x[1], reverse=True)
                counter_ = 0
                for symbol, symbol_return in sorted_return_list:
                    if counter_ >= 2:
                        break
                    symbol.Counter += 0.1 - (config.CASH_BUFFER * 0.1)
                    symbol.Function = "Hedged_Leveraged_Bonds_Stocks_V2 TLT > TLT_23_SMA" 
                    counter_ += 1
            else:
                return_list = [(self.TMF, self.TMF.Return_30.Current_Value), 
                                (self.UPRO, self.UPRO.Return_30.Current_Value), 
                                (self.TMV, self.TMV.Return_30.Current_Value),
                                (self.MOAT, self.MOAT.Return_30.Current_Value),
                                (self.BRKB, self.BRKB.Return_30.Current_Value), # Ganesh - Updated self.B with self.BRKB
                                (self.USMV, self.USMV.Return_30.Current_Value)
                                ]
                
                sorted_return_list = sorted(return_list, key=lambda x: x[1], reverse=True)
                counter_ = 0
                for symbol, symbol_return in sorted_return_list:
                    if counter_ >= 1:
                        break
           
                    symbol.Counter += 0.2 - (config.CASH_BUFFER * 0.2)
                    symbol.Function = "Hedged_Leveraged_Bonds_Stocks_V2 TLT < TLT_23_SMA" 
                    counter_ += 1


    def V2_Fund_Surfing_Michael_B(self):
        if self.UVXY.Rsi_20.Current_Value < 70:
            self.Fund_Surf_Bottom_1_20d_RSI()
        else:
            self.TMV_TMF_Selector()
    

    def Fund_Surf_Bottom_1_20d_RSI(self):
        rsi_list = [(self.SOXL, self.SOXL.Rsi_20.Current_Value), 
                    (self.SHY, self.SHY.Rsi_20.Current_Value), 
                    (self.SPY, self.SPY.Rsi_20.Current_Value),
                    (self.QQQ, self.QQQ.Rsi_20.Current_Value),
                    (self.TECL, self.TECL.Rsi_20.Current_Value),
                    (self.TQQQ, self.TQQQ.Rsi_20.Current_Value),
                    (self.SPXL, self.SPXL.Rsi_20.Current_Value)
                    ]
                
        sorted_rsi_list = sorted(rsi_list, key=lambda x: x[1], reverse=False)
        counter_ = 0
        for symbol, symbol_return in sorted_rsi_list:
            if counter_ >= 1:       # Ganesh change from 3 to 1
                break
            symbol.Counter += 1 - (config.CASH_BUFFER * 1)
            counter_ += 1


    def TMV_TMF_Selector(self):
        if self.TMV.Drawdown_5.Current_Value < 0.1:
            if self.TMF.Drawdown_5.Current_Value < 0.1:   # Ganesh changed TMV to TMF
                self.Fund_Surf_Commodities_Bottom_2_5d_RSI()
            else:
                if self.TMF.Drawdown_5.Current_Value >= self.TMV.Drawdown_5.Current_Value:
                    self.TMF.Counter += 1 - (config.CASH_BUFFER * 1)
                else:
                    self.TMV.Counter += 1 - (config.CASH_BUFFER * 1)
        else:
            if self.TMF.Drawdown_5.Current_Value >= self.TMV.Drawdown_5.Current_Value:
                    self.TMF.Counter += 1 - (config.CASH_BUFFER * 1)
            else:
                self.TMV.Counter += 1 - (config.CASH_BUFFER * 1)


    def Fund_Surf_Commodities_Bottom_2_5d_RSI(self):
        rsi_list = [(self.SOXL, self.SOXL.Rsi_5.Current_Value), 
                    (self.SHY, self.SHY.Rsi_5.Current_Value), 
                    (self.SPY, self.SPY.Rsi_5.Current_Value),
                    (self.QQQ, self.QQQ.Rsi_5.Current_Value),
                    (self.TECL, self.TECL.Rsi_5.Current_Value),
                    (self.TQQQ, self.TQQQ.Rsi_5.Current_Value),
                    (self.UPRO, self.UPRO.Rsi_5.Current_Value),
                    (self.DBC, self.DBC.Rsi_5.Current_Value),
                    (self.DBA, self.DBA.Rsi_5.Current_Value)
                    ]
                
        sorted_rsi_list = sorted(rsi_list, key=lambda x: x[1], reverse=False)
        counter_ = 0
        for symbol, symbol_return in sorted_rsi_list:
            if counter_ >= 1:
                break
            symbol.Counter += 1 - (config.CASH_BUFFER * 1)
            counter_ += 1



    def QS_Pop_Bot_LETF_AWP(self):
        self.QQQ_Pop_Bot()
        self.SOXX_Pop_Bot()



    def QQQ_Pop_Bot(self):
        if self.TQQQ.Rsi_16.Current_Value > 78:
            self.SQQQ.Counter += 0.5 - (config.CASH_BUFFER * 0.5)
        else:
            if self.TQQQ.Rsi_15.Current_Value < 25:
                self.TQQQ.Counter += 0.5 - (config.CASH_BUFFER * 0.5)
            else:
                self.Left_AWP()
    

    def Left_AWP(self):
        if self.VIXM.Rsi_10.Current_Value > 75:
            self.ICSH.Counter += 0.5 - (config.CASH_BUFFER * 0.5)
        else:
            if self.IEF.Rsi_200.Current_Value > self.TLT.Rsi_200.Current_Value:
                self.TMF_Bull()
            else:
                if self.SPY.Rsi_60.Current_Value > 50:
                    self.TMV_Bull() 
                else:
                    self.TMV_Bear()
    

    # def TMF_Bull(self):   # Ganesh should be direct cash allocation, no RSI comparison required
    #     rsi_list = [(self.TMF, self.TMF.Rsi_5.Current_Value), 
    #                 (self.TYD, self.TYD.Rsi_5.Current_Value), 
    #                 (self.UPRO, self.UPRO.Rsi_5.Current_Value),
    #                 (self.UDOW, self.UDOW.Rsi_5.Current_Value),
    #                 (self.TQQQ, self.TQQQ.Rsi_5.Current_Value),
    #                 (self.URTY, self.URTY.Rsi_5.Current_Value),
    #                 (self.XLU, self.XLU.Rsi_5.Current_Value),
    #                 (self.NUGT, self.NUGT.Rsi_5.Current_Value),
    #                 (self.UPRO, self.UPRO.Rsi_5.Current_Value)
    #                 ]
                
    #     sorted_rsi_list = sorted(rsi_list, key=lambda x: x[1], reverse=False)
    #     counter_ = 0
    #     for symbol, symbol_return in sorted_rsi_list:
    #         if counter_ >= 9:
    #             break
    #         symbol.Counter += 0.055 - (config.CASH_BUFFER * )
    #         counter_ += 1

    def TMF_Bull(self): # Ganesh should be direct cash allocation, no RSI comparison required
        self.TMF.Counter += 0.055 - (config.CASH_BUFFER * 0.055)
        self.TYD.Counter += 0.055 - (config.CASH_BUFFER * 0.055)
        self.UPRO.Counter += 0.055 - (config.CASH_BUFFER * 0.055)
        self.UDOW.Counter += 0.055 - (config.CASH_BUFFER * 0.055)
        self.TQQQ.Counter += 0.055 - (config.CASH_BUFFER * 0.055)
        self.URTY.Counter += 0.055 - (config.CASH_BUFFER * 0.055)
        self.XLU.Counter += 0.055 - (config.CASH_BUFFER * 0.055)
        self.NUGT.Counter += 0.055 - (config.CASH_BUFFER * 0.055)                                                        
        self.UPRO.Counter += 0.055 - (config.CASH_BUFFER * 0.055)

    def TMV_Bull(self):
        self.TMV.Counter += 0.2 - (config.CASH_BUFFER * 0.2)
        self.USDU.Counter += 0.05 - (config.CASH_BUFFER * 0.05)
        self.XLU.Counter += 0.1 - (config.CASH_BUFFER * 0.1)
        self.NUGT.Counter += 0.05 - (config.CASH_BUFFER * 0.05)
        self.TYO.Counter += 0.1 - (config.CASH_BUFFER * 0.1)


    def TMV_Bear(self):
        self.TMV.Counter += 0.25 - (config.CASH_BUFFER * 0.25)
        self.USDU.Counter += 0.25 - (config.CASH_BUFFER * 0.25)


    def SOXX_Pop_Bot(self):
        if self.SOXL.Rsi_15.Current_Value > 80:
            self.SOXS.Counter += 0.5 - (config.CASH_BUFFER * 0.5)
        else:
            if self.SOXL.Rsi_10.Current_Value < 30:
                self.SOXL.Counter += 0.5 - (config.CASH_BUFFER * 0.5)
            else:
                self.Left_AWP()
        


    def Clear_Weightings(self):
        portfolio_value = self.Portfolio.TotalPortfolioValue
        for symbol in self.Symbol_Dictionary.keys():
            Symbol_Object = self.Symbol_Dictionary[symbol]
            Symbol_Object.Counter = 0
            symbol_holding = self.Portfolio[symbol].AbsoluteHoldingsValue
            allocation_per = symbol_holding / portfolio_value
            Symbol_Object.Current_Position = allocation_per


    def OnData(self, data: Slice):
        for symbol in self.Symbol_Dictionary.keys():
            Symbol_Object = self.Symbol_Dictionary[symbol]

            if Symbol_Object is None:continue
            
        
            if self.SHY is None and symbol == "SHY":
                self.SHY = Symbol_Object
            if self.TECL is None and symbol == "TECL":
                self.TECL = Symbol_Object
            if self.SOXL is None and symbol == "SOXL":
                self.SOXL = Symbol_Object
            if self.TQQQ is None and symbol == "TQQQ":
                self.TQQQ = Symbol_Object
            if self.UPRO is None and symbol == "UPRO":
                self.UPRO = Symbol_Object
            if self.TMF is None and symbol == "TMF":
                self.TMF = Symbol_Object
            if self.USDU is None and symbol == "USDU":
                self.USDU = Symbol_Object
            if self.SQQQ is None and symbol == "SQQQ":
                self.SQQQ = Symbol_Object
            if self.TBF is None and symbol == "TBF":
                self.TBF = Symbol_Object
            if self.BIL is None and symbol == "BIL":
                self.BIL = Symbol_Object
            if self.PHDG is None and symbol == "PHDG":
                self.PHDG = Symbol_Object				
            if self.TMV is None and symbol == "TMV":
                self.TMV = Symbol_Object				
            if self.UDOW is None and symbol == "UDOW":
                self.UDOW = Symbol_Object	
            if self.MOAT is None and symbol == "MOAT":
                self.MOAT = Symbol_Object	
            if self.BRKB is None and symbol == "BRK.B":
                self.BRKB = Symbol_Object
            if self.USMV is None and symbol == "USMV":
                self.USMV = Symbol_Object
            if self.SPY is None and symbol == "SPY":
                self.SPY = Symbol_Object
            if self.QQQ is None and symbol == "QQQ":
                self.QQQ = Symbol_Object
            if self.SPXL is None and symbol == "SPXL":
                self.SPXL = Symbol_Object
            if self.DBC is None and symbol == "DBC":
                self.DBC = Symbol_Object
            if self.DBA is None and symbol == "DBA":
                self.DBA = Symbol_Object
            if self.ICSH is None and symbol == "ICSH":
                self.ICSH = Symbol_Object
            if self.TYD is None and symbol == "TYD":
                self.TYD = Symbol_Object
            if self.URTY is None and symbol == "URTY":
                self.URTY = Symbol_Object
            if self.XLU is None and symbol == "XLU":
                self.XLU = Symbol_Object
            if self.NUGT is None and symbol == "NUGT":
                self.NUGT = Symbol_Object
            if self.TYO is None and symbol == "TYO":
                self.TYO = Symbol_Object
            if self.VIXM is None and symbol == "VIXM":
                self.VIXM = Symbol_Object	
            if self.IEF is None and symbol == "IEF":
                self.IEF = Symbol_Object
            if self.SOXS is None and symbol == "SOXS":
                self.SOXS = Symbol_Object
            if self.BND is None and symbol == "BND":
                self.BND = Symbol_Object
            if self.VTI is None and symbol == "VTI":
                self.VTI = Symbol_Object
            if self.FAS is None and symbol == "FAS":
                self.FAS = Symbol_Object
            if self.TLT is None and symbol == "TLT":
                self.TLT = Symbol_Object
            if self.UVXY is None and symbol == "UVXY":
                self.UVXY = Symbol_Object



        if self.Update_Intraday:
            if self.SHY is not None:
                self.SHY.Update_With_Intraday_Bar(self.Securities["SHY"].Close)
            if self.TECL is not None:
                self.TECL.Update_With_Intraday_Bar(self.Securities["TECL"].Close)
            if self.SOXL is not None:
                self.SOXL.Update_With_Intraday_Bar(self.Securities["SOXL"].Close)
            if self.FAS is not None:
                self.FAS.Update_With_Intraday_Bar(self.Securities["FAS"].Close)
            if self.TQQQ is not None:
                self.TQQQ.Update_With_Intraday_Bar(self.Securities["TQQQ"].Close)
            if self.UPRO is not None:
                self.UPRO.Update_With_Intraday_Bar(self.Securities["UPRO"].Close)
            if self.TMF is not None:
                self.TMF.Update_With_Intraday_Bar(self.Securities["TMF"].Close)
            if self.USDU is not None:
                self.USDU.Update_With_Intraday_Bar(self.Securities["USDU"].Close)
            if self.SQQQ is not None:
                self.SQQQ.Update_With_Intraday_Bar(self.Securities["SQQQ"].Close)
            if self.TBF is not None:
                self.TBF.Update_With_Intraday_Bar(self.Securities["TBF"].Close)
            if self.BIL is not None:
                self.BIL.Update_With_Intraday_Bar(self.Securities["BIL"].Close)
            if self.TMV is not None:
                self.TMV.Update_With_Intraday_Bar(self.Securities["TMV"].Close)
            if self.UDOW is not None:
                self.UDOW.Update_With_Intraday_Bar(self.Securities["UDOW"].Close)
            if self.MOAT is not None:
                self.MOAT.Update_With_Intraday_Bar(self.Securities["MOAT"].Close)
            if self.BRKB is not None:
                self.BRKB.Update_With_Intraday_Bar(self.Securities["BRK.B"].Close)	
            if self.USMV is not None:
                self.USMV.Update_With_Intraday_Bar(self.Securities["USMV"].Close)
            if self.SPY is not None:
                self.SPY.Update_With_Intraday_Bar(self.Securities["SPY"].Close)
            if self.QQQ is not None:
                self.QQQ.Update_With_Intraday_Bar(self.Securities["QQQ"].Close)
            if self.SPXL is not None:
                self.SPXL.Update_With_Intraday_Bar(self.Securities["SPXL"].Close)
            if self.DBC is not None:
                self.DBC.Update_With_Intraday_Bar(self.Securities["DBC"].Close)
            if self.DBA is not None:
                self.DBA.Update_With_Intraday_Bar(self.Securities["DBA"].Close)
            if self.ICSH is not None:
                self.ICSH.Update_With_Intraday_Bar(self.Securities["ICSH"].Close)
            if self.TYD is not None:
                self.TYD.Update_With_Intraday_Bar(self.Securities["TYD"].Close)
            if self.URTY is not None:
                self.URTY.Update_With_Intraday_Bar(self.Securities["URTY"].Close)
            if self.XLU is not None:
                self.XLU.Update_With_Intraday_Bar(self.Securities["XLU"].Close)
            if self.NUGT is not None:
                self.NUGT.Update_With_Intraday_Bar(self.Securities["NUGT"].Close)
            if self.TYO is not None:
                self.TYO.Update_With_Intraday_Bar(self.Securities["TYO"].Close)
            if self.VIXM is not None:
                self.VIXM.Update_With_Intraday_Bar(self.Securities["VIXM"].Close)
            if self.IEF is not None:
                self.IEF.Update_With_Intraday_Bar(self.Securities["IEF"].Close)
            if self.SOXS is not None:
                self.SOXS.Update_With_Intraday_Bar(self.Securities["SOXS"].Close)
            if self.BND is not None:
                self.BND.Update_With_Intraday_Bar(self.Securities["BND"].Close)
            if self.VTI is not None:
                self.VTI.Update_With_Intraday_Bar(self.Securities["VTI"].Close)
            if self.TLT is not None:
                self.TLT.Update_With_Intraday_Bar(self.Securities["TLT"].Close)
            if self.UVXY is not None:
                self.UVXY.Update_With_Intraday_Bar(self.Securities["UVXY"].Close)
         

       
            
        if self.SHY is None or self.TECL is None or self.SOXL is None or self.FAS is None or self.TQQQ is None or self.UPRO is None or self.TMF is None or self.USDU is None or self.SQQQ is None or self.TBF is None or self.BIL is None or self.PHDG is None or self.TMV is None or self.UDOW is None or self.MOAT is None or self.BRKB is None or self.USMV is None or self.SPY is None or self.QQQ is None or self.SPXL is None or self.DBC is None or self.DBA is None or self.ICSH is None or self.TYD is None or self.URTY is None or self.XLU is None or self.NUGT is None or self.TYO is None or self.VIXM is None or self.IEF is None or self.SOXS is None or self.BND is None or self.VTI is None or self.TLT is None or self.UVXY is None:
            return

        
        self.Update_Intraday = False
        
        if self.Trade_Decision:
            self.Clear_Weightings()
            self.Main_Strategy()
            self.Orders()

            self.Trade_Decision = False

class SymbolData():


    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol

        self.Daily_High = None
        self.Daily_Low = None
        
        self.Counter = 0
       
        self.Rsi_5_Period = config.RSI_5_PERIOD
        self.Rsi_10_Period = config.RSI_10_PERIOD
        self.Rsi_15_Period = config.RSI_15_PERIOD
        self.Rsi_16_Period = config.RSI_16_PERIOD
        self.Rsi_18_Period = config.RSI_18_PERIOD
        self.Rsi_20_Period = config.RSI_20_PERIOD 
        self.Rsi_40_Period = config.RSI_40_PERIOD       
        self.Rsi_60_Period = config.RSI_60_PERIOD
        self.Rsi_200_Period = config.RSI_200_PERIOD

        self.Return_5_Period = config.RETURN_5_PERIOD
        self.Return_10_Period = config.RETURN_10_PERIOD
        self.Return_15_Period = config.RETURN_15_PERIOD
        self.Return_20_Period = config.RETURN_20_PERIOD
        self.Return_30_Period = config.RETURN_30_PERIOD
        self.Return_60_Period = config.RETURN_60_PERIOD
        self.Return_70_Period = config.RETURN_70_PERIOD
        self.Return_200_Period = config.RETURN_200_PERIOD

        self.SMA_23_Period = config.SMA_23_PERIOD
        self.SMA_150_Period = config.SMA_150_PERIOD
        self.SMA_200_Period = config.SMA_200_PERIOD

        self.Custom_Drawdown_5_Period = config.CUSTOM_DRAWDOWN_5_PERIOD
        self.Custom_Drawdown_8_Period = config.CUSTOM_DRAWDOWN_8_PERIOD
        self.Custom_Drawdown_10_Period = config.CUSTOM_DRAWDOWN_10_PERIOD

        self.Function = ""
        self.Current_Position = 0

        self.Rsi_5 = Intraday_Updating_RSI(algorithm, self.Rsi_5_Period)
        self.Rsi_10 = Intraday_Updating_RSI(algorithm, self.Rsi_10_Period)
        self.Rsi_15 = Intraday_Updating_RSI(algorithm, self.Rsi_15_Period)
        self.Rsi_16 = Intraday_Updating_RSI(algorithm, self.Rsi_16_Period)
        self.Rsi_18 = Intraday_Updating_RSI(algorithm, self.Rsi_18_Period)
        self.Rsi_20 = Intraday_Updating_RSI(algorithm, self.Rsi_20_Period)  
        self.Rsi_40 =  Intraday_Updating_RSI(algorithm, self.Rsi_40_Period)    
        self.Rsi_60 = Intraday_Updating_RSI(algorithm, self.Rsi_60_Period)
        self.Rsi_200 = Intraday_Updating_RSI(algorithm, self.Rsi_200_Period)

        self.Return_5 = Intraday_Updating_Cumulative_Return(algorithm, self.Return_5_Period)
        self.Return_10 = Intraday_Updating_Cumulative_Return(algorithm, self.Return_10_Period)
        self.Return_15 = Intraday_Updating_Cumulative_Return(algorithm, self.Return_15_Period)
        self.Return_20 = Intraday_Updating_Cumulative_Return(algorithm, self.Return_20_Period)
        self.Return_30 = Intraday_Updating_Cumulative_Return(algorithm, self.Return_30_Period)
        self.Return_60 = Intraday_Updating_Cumulative_Return(algorithm, self.Return_60_Period)
        self.Return_70 = Intraday_Updating_Cumulative_Return(algorithm, self.Return_70_Period)
        self.Return_200 = Intraday_Updating_Cumulative_Return(algorithm, self.Return_200_Period)

        self.SMA_23 = Intraday_Updating_SMA(algorithm, self.SMA_23_Period)
        self.SMA_150 = Intraday_Updating_SMA(algorithm, self.SMA_150_Period)
        self.SMA_200 = Intraday_Updating_SMA(algorithm, self.SMA_200_Period)


        self.Drawdown_5 = CustomDrawdown(algorithm, symbol, self.Custom_Drawdown_5_Period)
        self.Drawdown_8 = CustomDrawdown(algorithm, symbol, self.Custom_Drawdown_8_Period)
        self.Drawdown_10 = CustomDrawdown(algorithm, symbol, self.Custom_Drawdown_10_Period)


        self.WarmUp = True


        self.Daily_Bar_Consolidator = TradeBarConsolidator(timedelta(days=1))
        self.algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.Daily_Bar_Consolidator)
        self.Daily_Bar_Consolidator.DataConsolidated += self.OnDataConsolidated

        history = self.algorithm.History[TradeBar](self.symbol, 400, Resolution.Daily)


        for bar in history:
            self.Daily_Bar_Consolidator.Update(bar)
        

        self.WarmUp = False



        self.Minute_Bar_Consolidator = TradeBarConsolidator(timedelta(minutes=1))
        self.algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.Minute_Bar_Consolidator)
        self.Minute_Bar_Consolidator.DataConsolidated += self.OnMinuteConsolidated


        self.algorithm.Schedule.On(self.algorithm.DateRules.EveryDay(), self.algorithm.TimeRules.AfterMarketOpen(self.symbol, -10), self.Reset_HL)


    def Reset_HL(self):
        self.Daily_High = None
        self.Daily_Low = None

    def OnMinuteConsolidated(self, sender, bar):
        if self.Daily_High is None:
            self.Daily_High = bar.High
        if self.Daily_Low is None:
            self.Daily_Low = bar.Low
        
        if self.Daily_High is not None and bar.High > self.Daily_High:
            self.Daily_High = bar.High
        if self.Daily_Low is not None and bar.Low < self.Daily_Low:
            self.Daily_Low = bar.Low


    def OnDataConsolidated(self, sender, bar):
        self.Rsi_5.Receive_Main_Bar(bar)
        self.Rsi_10.Receive_Main_Bar(bar)
        self.Rsi_15.Receive_Main_Bar(bar)
        self.Rsi_16.Receive_Main_Bar(bar)
        self.Rsi_18.Receive_Main_Bar(bar)
        self.Rsi_20.Receive_Main_Bar(bar)
        self.Rsi_40.Receive_Main_Bar(bar)
        self.Rsi_60.Receive_Main_Bar(bar)
        self.Rsi_200.Receive_Main_Bar(bar)

        self.Return_5.Receive_Main_Bar(bar)
        self.Return_10.Receive_Main_Bar(bar)
        self.Return_15.Receive_Main_Bar(bar)
        self.Return_20.Receive_Main_Bar(bar)
        self.Return_30.Receive_Main_Bar(bar)
        self.Return_60.Receive_Main_Bar(bar)
        self.Return_70.Receive_Main_Bar(bar)
        self.Return_200.Receive_Main_Bar(bar)

        self.SMA_23.Receive_Main_Bar(bar)
        self.SMA_150.Receive_Main_Bar(bar)
        self.SMA_200.Receive_Main_Bar(bar)

        self.Drawdown_5.Receive_Main_Bar(bar)
        self.Drawdown_8.Receive_Main_Bar(bar)
        self.Drawdown_10.Receive_Main_Bar(bar)


        self.Rsi_5.Updated_Today = True       
        self.Rsi_10.Updated_Today = True
        self.Rsi_15.Updated_Today = True
        self.Rsi_16.Updated_Today = True
        self.Rsi_18.Updated_Today = True
        self.Rsi_20.Updated_Today = True  
        self.Rsi_40.Updated_Today = True              
        self.Rsi_60.Updated_Today = True
        self.Rsi_200.Updated_Today = True

        self.Return_5.Updated_Today = True
        self.Return_10.Updated_Today = True
        self.Return_15.Updated_Today = True
        self.Return_20.Updated_Today = True
        self.Return_30.Updated_Today = True
        self.Return_60.Updated_Today = True
        self.Return_70.Updated_Today = True
        self.Return_200.Updated_Today = True

        self.SMA_23.Updated_Today = True
        self.SMA_150.Updated_Today = True
        self.SMA_200.Updated_Today = True

        self.Drawdown_5.Updated_Today = True
        self.Drawdown_8.Updated_Today = True
        self.Drawdown_10.Updated_Today = True

    def Update_With_Intraday_Bar(self, price):
        if not self.WarmUp:
            if self.Rsi_5.Updated_Today:
                self.Rsi_5.Receive_Sub_Bar(price)
            if self.Rsi_10.Updated_Today:
                self.Rsi_10.Receive_Sub_Bar(price)
            if self.Rsi_15.Updated_Today:
                self.Rsi_15.Receive_Sub_Bar(price)
            if self.Rsi_16.Updated_Today:
                self.Rsi_16.Receive_Sub_Bar(price)
            if self.Rsi_18.Updated_Today:
                self.Rsi_18.Receive_Sub_Bar(price)
            if self.Rsi_20.Updated_Today:
                self.Rsi_20.Receive_Sub_Bar(price)    
            if self.Rsi_40.Updated_Today:
                self.Rsi_40.Receive_Sub_Bar(price)                  
            if self.Rsi_60.Updated_Today:
                self.Rsi_60.Receive_Sub_Bar(price)
            if self.Rsi_200.Updated_Today:
                self.Rsi_200.Receive_Sub_Bar(price)

            if self.Return_5.Updated_Today:
                self.Return_5.Receive_Sub_Bar(price)
            if self.Return_10.Updated_Today:
                self.Return_10.Receive_Sub_Bar(price)
            if self.Return_15.Updated_Today:
                self.Return_15.Receive_Sub_Bar(price)
            if self.Return_20.Updated_Today:
                self.Return_20.Receive_Sub_Bar(price)
            if self.Return_30.Updated_Today:
                self.Return_30.Receive_Sub_Bar(price)
            if self.Return_60.Updated_Today:
                self.Return_60.Receive_Sub_Bar(price)
            if self.Return_70.Updated_Today:
                self.Return_70.Receive_Sub_Bar(price)
            if self.Return_200.Updated_Today:
                self.Return_200.Receive_Sub_Bar(price)
            
            if self.SMA_23.Updated_Today:
                self.SMA_23.Receive_Sub_Bar(price)
            if self.SMA_150.Updated_Today:
                self.SMA_150.Receive_Sub_Bar(price)
            if self.SMA_200.Updated_Today:
                self.SMA_200.Receive_Sub_Bar(price)

            if self.Drawdown_5.Updated_Today:
                self.Drawdown_5.Receive_Sub_Bar(self.Daily_High, self.Daily_Low)
            if self.Drawdown_8.Updated_Today:
                self.Drawdown_8.Receive_Sub_Bar(self.Daily_High, self.Daily_Low)
            if self.Drawdown_10.Updated_Today:
                self.Drawdown_10.Receive_Sub_Bar(self.Daily_High, self.Daily_Low)

    def Reset(self):
        self.Rsi_5.Updated_Today = False
        self.Rsi_10.Updated_Today = False
        self.Rsi_15.Updated_Today = False
        self.Rsi_16.Updated_Today = False
        self.Rsi_18.Updated_Today = False
        self.Rsi_20.Updated_Today = False
        self.Rsi_40.Updated_Today = False
        self.Rsi_60.Updated_Today = False
        self.Rsi_200.Updated_Today = False
        

        self.Return_5.Updated_Today = False
        self.Return_10.Updated_Today = False
        self.Return_15.Updated_Today = False
        self.Return_20.Updated_Today = False
        self.Return_30.Updated_Today = False
        self.Return_60.Updated_Today = False
        self.Return_70.Updated_Today = False
        self.Return_200.Updated_Today = False

        self.SMA_23.Updated_Today = False
        self.SMA_150.Updated_Today = False
        self.SMA_200.Updated_Today = False

        self.Drawdown_5.Updated_Today = False
        self.Drawdown_8.Updated_Today = False
        self.Drawdown_10.Updated_Today = False
#region imports
from AlgorithmImports import *
#endregion
"""


"""




BACKTEST_START_YEAR = 2022         # Set start Year of the Backtest
BACKTEST_START_MONTH = 1           # Set start Month of the Backtest
BACKTEST_START_DAY = 3              # Set start Day of the Backtest

BACKTEST_END_YEAR = 2022            # Set end Year of the Backtest
BACKTEST_END_MONTH = 2             # Set end Month of the Backtest       
BACKTEST_END_DAY = 15              # Set end Day of the Backtest

BACKTEST_ACCOUNT_CASH = 20000        # Set Backtest Strategy Cash


# List of ETF's that the algorithm will trade,
# !!! Changing these will break the code without the adequate changes in the main file
# If you need help in changing these please contact me
ETFS = ["SHY", "TECL", "SOXL", "FAS", "TQQQ", "UPRO", "TMF", "USDU", "SQQQ", "TBF", "BIL", "PHDG", "TMV", "UDOW", "MOAT", 
        "BRK.B", "USMV", "SPY", "QQQ", "SPXL", "DBC", "DBA", "ICSH", "TYD", "URTY", "XLU", "NUGT", "TYO", "VIXM", "IEF", 
        "SOXS","BND", "VTI", "TLT", "UVXY"]




REBALANCE_THRESHOLD = 5



# Cash Buffer in Percent, 0.05 = 5%
CASH_BUFFER = 0.05


# In minutes before market close
TRADE_DECISION_TIME = 2


USE_ORDER_DELAY = False
ORDER_DELAY = 0.3


# In minutes after original order
# If scheduled call is set to BeforeMarketClose keep the minus in the main file
# If scheduled call is set to AfterMarketOpen change the minus to a plus
# E.g. self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", self.Trade_Decision_Time - self.Order_Delay), self.Delayed_Orders)
# E.g. self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", self.Trade_Decision_Time + self.Order_Delay), self.Delayed_Orders)
# ORDER_DELAY = 1



# Period for the Daily RSI

RSI_5_PERIOD = 5
RSI_10_PERIOD = 10
RSI_15_PERIOD = 15
RSI_16_PERIOD = 16
RSI_18_PERIOD = 18
RSI_20_PERIOD = 20
RSI_40_PERIOD = 40
RSI_60_PERIOD = 60
RSI_200_PERIOD = 200



# Period for the Daily Cumulative Return

RETURN_5_PERIOD = 5
RETURN_10_PERIOD = 10
RETURN_15_PERIOD = 15
RETURN_20_PERIOD = 20
RETURN_30_PERIOD = 30
RETURN_60_PERIOD = 60
RETURN_70_PERIOD = 70
RETURN_200_PERIOD = 200



# Period for the Daily SMA

SMA_23_PERIOD = 23
SMA_150_PERIOD = 150
SMA_200_PERIOD = 200


CUSTOM_DRAWDOWN_5_PERIOD = 5
CUSTOM_DRAWDOWN_8_PERIOD = 8
CUSTOM_DRAWDOWN_10_PERIOD = 10
from AlgorithmImports import *
from collections import deque


class Intraday_Updating_RSI():



    def __init__(self, algorithm, rsi_period):
        self.algorithm = algorithm
        self.rsi_period = rsi_period
        self.Bar_Queue = deque(maxlen=2)
        self.Average_Gain_Queue = deque(maxlen=self.rsi_period)
        self.Average_Gain = None
        self.Average_Loss_Queue = deque(maxlen=self.rsi_period)
        self.Average_Loss = None
        self.Change = None
        self.Relative_Strength = None
        self.Current_Value = None
        self.Alpha = None
        self.Sum_Gain = 0
        self.Sum_Loss = 0

        self.First_Intraday_Update_Of_Day = True
        self.Last_Main_Bar = None
        self.Last_Sum_Gain = None
        self.Last_Sum_Loss = None

        self.New_Main_Bar = True
        self.WarmUP = True
        self.Previous_Value = None
        self.Updated_Today = False

    
    def Receive_Main_Bar(self, bar):
        if not self.First_Intraday_Update_Of_Day:
            del self.Bar_Queue[0]
            self.New_Main_Bar = True
        self.Bar_Queue.appendleft(bar.Close)
       
        


        if len(self.Bar_Queue) == 2:
            self.Calculate_Change()
    

    def Receive_Sub_Bar(self, bar):
        if len(self.Bar_Queue) == 2:
            if self.First_Intraday_Update_Of_Day:
                self.Last_Main_Bar = self.Bar_Queue[1]
                self.Last_Sum_Gain = self.Sum_Gain
                self.Last_Sum_Loss = self.Sum_Loss
                self.Bar_Queue.appendleft(bar)
                self.First_Intraday_Update_Of_Day = False
            else:
                del self.Bar_Queue[0]
                self.Bar_Queue.appendleft(bar)


            self.Calculate_Change()
                


    def Calculate_Change(self):
        self.Change = self.Bar_Queue[0] - self.Bar_Queue[1]

        self.Calculate_Average_Gain_Loss()
    

    def Calculate_Average_Gain_Loss(self):
        if self.Change >= 0:
            gain = self.Change
        else:
            gain = 0
        
        if self.Change < 0:
            loss = abs(self.Change)
        else:
            loss = 0
        
        self.Average_Gain_Queue.appendleft(gain)
        self.Average_Loss_Queue.appendleft(loss)
    
        if len(self.Average_Gain_Queue) == self.rsi_period and len(self.Average_Loss_Queue) == self.rsi_period:
            self.Alpha = 1/self.rsi_period
            self.Average_Gain = sum(self.Average_Gain_Queue) / len(self.Average_Gain_Queue)
            self.Average_Loss = sum(self.Average_Loss_Queue) / len(self.Average_Loss_Queue)
            if self.First_Intraday_Update_Of_Day:
                if self.Sum_Gain == 0:
                    if self.WarmUP:
                        self.Sum_Gain = self.Average_Gain
                    else:
                        self.Sum_Gain = self.Last_Sum_Gain
                else:
                    self.Sum_Gain = self.Alpha * gain + (1-self.Alpha) * self.Sum_Gain
                
                if self.Sum_Loss == 0:
                    if self.WarmUP:
                        self.Sum_Loss = self.Average_Loss
                    else:
                        self.Sum_Loss = self.Last_Sum_Loss
                else:
                    self.Sum_Loss = self.Alpha * loss + (1-self.Alpha) * self.Sum_Loss


            else:
                if self.Sum_Gain == 0:
                    self.Sum_Gain = self.Average_Gain
                else:
                    self.Sum_Gain = self.Alpha * gain + (1-self.Alpha) * self.Last_Sum_Gain
                
                if self.Sum_Loss == 0:
                    self.Sum_Loss = self.Average_Loss
                else:
                    self.Sum_Loss = self.Alpha * loss + (1-self.Alpha) * self.Last_Sum_Loss

                if self.New_Main_Bar:
                    self.First_Intraday_Update_Of_Day = True
                

            self.Calculate_Relative_Strength()

    def Calculate_Relative_Strength(self):
        if self.Sum_Gain != 0 and self.Sum_Loss != 0:
            self.Relative_Strength = self.Sum_Gain / self.Sum_Loss

            if self.Relative_Strength is not None:
                self.Current_Value = 100 - (100 / (1 + self.Relative_Strength))



        self.New_Main_Bar = False