Overall Statistics
Total Trades
29
Average Win
7.00%
Average Loss
-0.62%
Compounding Annual Return
99.504%
Drawdown
15.700%
Expectancy
9.606
Net Profit
113.568%
Sharpe Ratio
3.352
Probabilistic Sharpe Ratio
95.052%
Loss Rate
14%
Win Rate
86%
Profit-Loss Ratio
11.37
Alpha
0.78
Beta
0.092
Annual Standard Deviation
0.246
Annual Variance
0.06
Information Ratio
0.944
Tracking Error
0.376
Treynor Ratio
8.911
Total Fees
$119.47
class QInOut(QCAlgorithm):

    def Initialize(self):
        
        # ------------------------------------------- Parameters ---------------------------------------
        
        # Entry minute for the Trade algo after MArket Open
        self.MinsAfterOpen = int(self.GetParameter("minsAfterOpen"))
      
        #Indicators' Days input
        self.SmaDays = int(self.GetParameter("smaDays"))
        self.MacdFastDays = int(self.GetParameter("macdFastDays"))
        self.MacdSlowDays = int(self.GetParameter("macdSlowDays"))
        self.MacdSignalDays = int(self.GetParameter("macdSignalDays"))
        self.RsiDays = int(self.GetParameter("rsiDays"))
        self.SmaLongDays = 30 # not in use ATM int(self.GetParameter("smaLongDays"))
        self.SmaShortDays = int(self.GetParameter("smaShortDays"))
        self.PpoSlowDays = int(self.GetParameter("ppoSlowDays"))
        self.PpoFastDays = int(self.GetParameter("ppoFastDays"))
       
        # Indicators gaps and factors
        self.RsiLowGap = int(self.GetParameter("rsiLow"))
        self.RsiHighGap = int(self.GetParameter("rsiHigh"))
        self.PpoGap = float(self.GetParameter("ppo"))
        self.SlopeGap = float(self.GetParameter("slope"))
        self.MompGap = 100 # not in use ATM float(self.GetParameter("momp"))
        self.MacdGap = float(self.GetParameter("macd"))
        self.MacdSignalGap = float(self.GetParameter("macdSignal"))
        
        # MACD factors
        self.MacdFactorOut = float(self.GetParameter("macdFactorOut"))
        self.MacdFactorIn = float(self.GetParameter("macdFactorIn"))
        self.MacdIn2Factor = float(self.GetParameter("macdIn2Factor"))
      
        # Trade time in minutes after market open
        self.MinDaysOut = int(self.GetParameter("daysOut"))
        
        # Debug Algo Input parameters
        #self.Debug(f"After Market Open. rsiLow:{self.RsiLowGap} rsiHigh:{self.RsiHighGap} ppo:{self.PpoGap} rsiDays:{self.RsiDays} smaLongDays:{self.SmaLongDays} smaShortDays:{self.SmaShortDays} ppoFastDays:{self.PpoFastDays} ppoSlowDays:{self.PpoSlowDays}")
        
        self.StartYear = int(self.GetParameter("startYear"))
        self.EndYear = int(self.GetParameter("endYear"))

        # For Back testing
        self.SetStartDate(self.StartYear,1,1)
        self.SetEndDate(self.EndYear,12,31)
        self.StartCash = 100000
        self.SetCash(self.StartCash)
        
        self.SetWarmUp(timedelta(days=30))
        
        # --------------------------------------- Internal variables -----------------------------------
        
        #For Plots on Equity Graph
        self.InEquityHistory = []                   # now used for QQQ
        self.OutEquityHistory = []                  # now used to TLT

        self.FirstDay = True
        self.InEquity_RSI_DAY_BEFORE = 0
        self.InEquity_PPO_DAY_BEFORE = 0 
        self.InEquity_BIG_SMA_WINDOW_DAY_BEFORE = 0
        self.InEquity_SMA_WINDOW_DAY_BEFORE = 0
        self.InEquity_SLOPE_DAY_BEFORE = 0
        self.InEquity_MOMP_DAY_BEFORE = 0
        self.InEquity_SMA_DAY_BEFORE = 0
        self.InEquity_MACD_DAY_BEFORE = 0
        self.InEquity_MACD_Signal_DAY_BEFORE = 0
       
        self.TickerTable = {}
        
        self.MyInOutIndicator = 1 # Default Enter the Market
        self.DaysOut = 0        # Cooldown days after exiting the Market
        self.TotalDays =0       # Counter for total days
        self.TotalDaysIn = 0    # Counter for days in the MArket
        
        self.Indicator_history = []
        self.IndicatorRatio = 0
        
        # ---------------------------------------- Defining Tickers and collection Indicators ---------------------------
        
        self.SetBenchmark("QQQ")
        
        self.OutEquity="TLT"                        # Out of market portfolio. Divide Cash among list (TLT VXX VIXY)
        self.InEquity ="QQQ"                        # In market asset (QQQ QQEW)
    
        self.VXX = self.AddEquity("VXX", Resolution.Daily).Symbol
        self.tickers = ["QQQ","TLT"]  # ,"FDN","SPY","ARKK","SQQQ","GLD","PSQ","SH","EMTY", "XLU","XLP","TBT","IEF", "FDN","TLH"]

        for ticker in self.tickers:
            
            # --------- Add Equity
            self.AddEquity(ticker, Resolution.Daily)
            
            # --------- Add Equity indicators
            rsi = self.RSI(ticker, self.RsiDays, Resolution.Daily)
            smaLong = self.SMA(ticker, self.SmaLongDays, Resolution.Daily)
            smaShort = self.SMA(ticker, self.SmaShortDays, Resolution.Daily)
            rcShort = self.RC(ticker,self.SmaShortDays, Resolution.Daily)
            ppo = self.PPO(ticker, self.PpoFastDays, self.PpoSlowDays, MovingAverageType.Simple, Resolution.Daily)
            momp = self.MOMP(ticker, 28, Resolution.Daily)
            sma = self.SMA(ticker, self.SmaDays, Resolution.Daily)
            ema = self.EMA(ticker, self.SmaDays, Resolution.Daily)
            macd = self.MACD(ticker,  self.MacdFastDays,self.MacdSlowDays,self.MacdSignalDays,MovingAverageType.Exponential, Resolution.Daily)
            
            symbolData = SymbolData(ticker, rsi, smaLong, smaShort, rcShort, ppo, momp, sma, ema, macd)
            
            self.TickerTable[ticker] = symbolData


        # --------------------------------------------------- Schedules --------------------------------------------
        
        self.Schedule.On(self.DateRules.EveryDay(self.InEquity),self.TimeRules.AfterMarketOpen(self.InEquity,self.MinsAfterOpen), self.Trade)


    # ------------------------------------------------- On Data -----------------------------------------------------
    
    def OnData(self, data):
        pass

    
    # ---------------------------------------------------------------------------------------------------------------
    # ---------------------------------------------- Trade Function -------------------------------------------------
    # ---------------------------------------------------------------------------------------------------------------
    
    def Trade(self):
        
        self.TotalDays +=1
        self.CollectIndicatorsAndTrends()
        self.DecideInOrOut()
        
        if self.MyInOutIndicator == 1:
            self.TotalDaysIn +=1
            if not self.Securities[self.InEquity].Invested:
                self.SetHoldings(self.InEquity, 1.00, True,f"PPO:{self.InEquity_PPO} SLOPE:{self.InEquity_SLOPE} RSI:{self.InEquity_RSI}")
                self.Notify.Sms("+972542224488", self.InEquity +" In:" + str(self.Securities[self.InEquity].Price))
        else:
             if not self.Securities[self.OutEquity].Invested:
                self.SetHoldings(self.OutEquity, 1.00, True,f"PPO:{self.InEquity_PPO} SLOPE:{self.InEquity_SLOPE} RSI:{self.InEquity_RSI}")
                self.Notify.Sms("+972542224488", self.InEquity + " Out:" + str(self.Securities[self.InEquity].Price))

        self.AfterTradeUpdate()
        self.PlotIt()
    
    # --------------------------------  Decide IN or OUT ----------------------------------------
    
    def GoldenCross(self):
        if self.InEquity_MACD > self.InEquity_MACD_Signal * self.MacdFactorIn and self.InEquity_MACD_DAY_BEFORE - self.MacdIn2Factor < self.InEquity_MACD:
            return True
        else:
            return False
    
    def DeathCross(self):
        if self.InEquity_MACD < self.InEquity_MACD_Signal * self.MacdFactorOut and self.InEquity_MACD > self.InEquity_MACD_DAY_BEFORE:
            return True
        else:
            return False
    
    
    def DecideInOrOut(self):
        
        #if self.InEquity_SLOPE < self.SlopeGap or self.InEquity_PPO <= self.PpoGap or self.InEquity_RSI < self.RsiLowGap: 

        
        #if ((self.InEquity_MACD < (self.InEquity_MACD_Signal * self.MacdFactorOut) and self.InEquity_MACD < self.InEquity_MACD_DAY_BEFORE-0.2)
        #or self.InEquity_PPO <= self.PpoGap
        #or self.InEquity_RSI < self.RsiLowGap):
        #try:
        #    temp = (self.InEquity_RSI_DAY_BEFORE - self.InEquity_RSI)/ self.InEquity_RSI_DAY_BEFORE
        #except:
        #    temp = 0
        #if self.DeathCross(): # or temp > 0.1:#self.RsiLowGap:    
        
        # Should we go OUT ?
        if self.InEquity_PPO< self.PpoGap or self.InEquity_RSI < self.RsiLowGap or self.InEquity_SLOPE < self.SlopeGap:  
            self.MyInOutIndicator = 0
            self.DaysOut = 0                                            # Zero the DaysOut counter
        
        # Should we get IN?
        elif True: #self.GoldenCross():
            if self.DaysOut >= self.MinDaysOut:
                self.MyInOutIndicator = 1
                self.DaysOut = 0
            else:
                self.DaysOut +=1                                        # ---- Unless in Market out Cooldown
        else:
            if self.MyInOutIndicator == 0:
                self.DaysOut +=1
    
    # -------------------------  Collect Indicators and trends before Trade ---------------------------------
    
    def CollectIndicatorsAndTrends(self):
        
        if not self.FirstDay:
            self.InEquity_RSI_DAY_BEFORE = self.InEquity_RSI
            self.InEquity_PPO_DAY_BEFORE = self.InEquity_PPO 
            self.InEquity_BIG_SMA_WINDOW_DAY_BEFORE = self.InEquity_BIG_SMA_WINDOW
            self.InEquity_SMA_WINDOW_DAY_BEFORE = self.InEquity_SMALL_SMA_WINDOW
            self.InEquity_SLOPE_DAY_BEFORE = self.InEquity_SLOPE
            self.InEquity_MOMP_DAY_BEFORE = self.InEquity_MOMP
            self.InEquity_SMA_DAY_BEFORE = self.InEquity_SMA
            self.InEquity_MACD_DAY_BEFORE = self.InEquity_MACD
            self.InEquity_MACD_Signal_DAY_BEFORE = self.InEquity_MACD_Signal
        
        self.InEquity_RSI = self.TickerTable[self.InEquity].Rsi.Current.Value
        self.InEquity_PPO = self.TickerTable[self.InEquity].Ppo.Current.Value
        self.InEquity_BIG_SMA_WINDOW = self.TickerTable[self.InEquity].SmaLong.Current.Value
        self.InEquity_SMALL_SMA_WINDOW = self.TickerTable[self.InEquity].SmaShort.Current.Value
        self.InEquity_SLOPE = self.TickerTable[self.InEquity].RcShort.Slope.Current.Value
        self.InEquity_MOMP = self.TickerTable[self.InEquity].Momp.Current.Value
        self.InEquity_SMA = self.TickerTable[self.InEquity].Sma.Current.Value
        self.InEquity_EMA = self.TickerTable[self.InEquity].Ema.Current.Value
        self.InEquity_MACD = self.TickerTable[self.InEquity].Macd.Current.Value
        self.InEquity_MACD_Signal = self.TickerTable[self.InEquity].Macd.Signal.Current.Value
        
        self.FirstDay = False
       
        #self.Debug(f"{self.Time} PPO:{round(self.InEquity_PPO,2)} Slope:{round(self.InEquity_SLOPE,2)} RSI:{round(self.InEquity_RSI,2)} BIG_SMA_WINDOW:{round(self.InEquity_BIG_SMA_WINDOW,2)}  SMALL_SMA_WINDOW:{round(self.InEquity_SMALL_SMA_WINDOW,2)}")
        #self.Debug(f"{self.Time} Slope:{round(self.InEquity_SLOPE,2)} RSI:{round(self.InEquity_RSI,2)}")
    
    
    # ------------------------------------  After Trade updates ---------------------------------------------

    def AfterTradeUpdate(self):
        
        self.InEquity_RSI_DAY_BEFORE = self.InEquity_RSI
        self.InEquity_PPO_DAY_BEFORE = self.InEquity_PPO 
        self.InEquity_BIG_SMA_WINDOW_DAY_BEFORE = self.InEquity_BIG_SMA_WINDOW
        self.InEquity_SMA_WINDOW_DAY_BEFORE = self.InEquity_SMALL_SMA_WINDOW
        self.InEquity_SLOPE_DAY_BEFORE = self.InEquity_SLOPE
        self.InEquity_MOMP_DAY_BEFORE = self.InEquity_MOMP
        self.InEquity_SMA_DAY_BEFORE = self.InEquity_SMA
        self.InEquity_MACD_DAY_BEFORE = self.InEquity_MACD
        self.InEquity_MACD_Signal_DAY_BEFORE = self.InEquity_MACD_Signal
        
        self.Indicator_history.append(self.MyInOutIndicator)
        self.Indicator_history_changes = [x1 - x2 for x1, x2 in zip(self.Indicator_history[1:], self.Indicator_history)][-15:]
        try:
            self.IndicatorRatio = 1.0000 * (len([x for x in self.Indicator_history_changes if x != 0])/ len(self.Indicator_history_changes))
            #if self.IndicatorRatio > 0:
            #    self.Debug(str(self.Time) + str(self.IndicatorRatio))
        except:
            self.Debug("START !!")
    
    # -------------------------------------------- Plot Function ------------------------------------------------
    
    def PlotIt(self):    
        
        self.Plot("In/Out Indicator","InOut",self.MyInOutIndicator)
        self.Plot("RSI","RSI",self.InEquity_RSI)
        self.Plot("PPO","PPO",self.InEquity_PPO)
        self.Plot("Slope","SLOPE",self.InEquity_SLOPE)
        #self.Plot("Momp","MOMP", self.InEquity_MOMP)
        self.Plot("MACD","Value",self.InEquity_MACD)        
        self.Plot("MACD","Signal",self.InEquity_MACD_Signal)   
        
        try:
            self.Plot("VXX","TLT",self.Securities[self.VXX.Value].Price)
        except:
            pass
        
        # Benchmark Ploting
        hist = self.History([self.InEquity], 2, Resolution.Daily)['close'].unstack(level= 0).dropna() 
        self.InEquityHistory.append(hist[self.InEquity].iloc[-1])
        perf = self.InEquityHistory[-1] / self.InEquityHistory[0] * self.StartCash
        self.Plot("Strategy Equity", self.InEquity, perf)
        
        hist = self.History([self.OutEquity], 2, Resolution.Daily)['close'].unstack(level= 0).dropna() 
        self.OutEquityHistory.append(hist[self.OutEquity].iloc[-1])
        perf = self.OutEquityHistory[-1] / self.OutEquityHistory[0] * self.StartCash
        self.Plot("Strategy Equity", self.OutEquity, perf)

# ----------------------------------------------- End of Algo ---------------------------------------------------

    def OnEndOfAlgorithm(self):
        self.Liquidate()
        if self.TotalDays>0:
            self.Debug(f"TPV:{round(self.Portfolio.TotalPortfolioValue,2)} Total Days:{self.TotalDays}  Total Days In:{self.TotalDaysIn} {round(self.TotalDaysIn/self.TotalDays*100,2)}%")
    

# ---------------------------------------------- SymbolData --------------------------------------------------
         
class SymbolData:
    def __init__(self, symbol, rsi, smaLong, smaShort, rcShort, ppo, momp, sma, ema, macd):
        self.Symbol = symbol
        self.Rsi = rsi
        self.SmaLong = smaLong
        self.SmaShort = smaShort
        self.RcShort = rcShort
        self.Ppo = ppo
        self.Momp = momp
        self.Sma = sma
        self.Ema = ema
        self.Macd = macd