Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
-5.509
Tracking Error
0.098
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
import datetime

class SuperTrendTester(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Start Date
        self.SetEndDate(2020, 1, 12)  # End Date
        self.symbolDataBySymbol = {}
        self.SetCash(10000)  # Set Strategy Cash
        ticker = "SPY"
        
        # Profit vs Stop Loss
        self.tpPercent = 20/10000
        self.slPercent = 10/10000
        
        self.ticker = self.AddEquity(ticker, Resolution.Hour, Market.USA).Symbol
        self.superTrend = SuperTrend(self, self.ticker, 2, 14, datetime.timedelta(hours=4))
        
        # Rolling SMA window
        self.sma_high = self.SMA(ticker, 8, Resolution.Daily, Field.High)
        self.sma_low = self.SMA(ticker, 8, Resolution.Daily, Field.Low)
        
        self.window = RollingWindow[TradeBar](2)
        self.sma_high.Updated += self.SmaUpdated
        self.smaWin = RollingWindow[float](2)
        self.sma_low.Updated += self.SmaUpdated_low
        self.smaWinn = RollingWindow[float](2)
        #
        
        # create a 13 period exponential moving average
        self.fast = self.EMA(ticker, 13, Resolution.Hour);
        
        # create a 20 period simple moving average
        self.slow = self.SMA(ticker, 20, Resolution.Hour);
        
        
         # create the 4 hour data consolidator
        #fourHours = QuoteBarConsolidator(timedelta(hours=4))
        #fourHours.DataConsolidated += self.fourHoursConsolidator
        
        #self.duck1[symbol] = SimpleMovingAverage(60)
        #self.RegisterIndicator(symbol, self.duck1[symbol], fourHours)
        
        
        self.PlotIndicator("EMA", self.fast);
        self.PlotIndicator("SMA", self.slow);
        
        self.previous = None
        #
        
        
        self.trade = True

       
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                 self.TimeRules.Every(timedelta(hours=1)),
                 self.buySignals)
                 
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                 self.TimeRules.Every(timedelta(hours=1)),
                 self.sellSignals)
                 
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                 self.TimeRules.AfterMarketOpen("SPY"),
                 self.buySignals)
                 
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                 self.TimeRules.AfterMarketOpen("SPY"),
                 self.sellSignals)
#

        # if not self.Portfolio.Invested:
        #    self.SetHoldings("SPY", 1)
        
    
        
    def SmaUpdated(self, sender, updated):
        self.smaWin.Add(self.sma_high.Current.Value)
        
    def SmaUpdated_low(self, sender, updated):
        self.smaWin.Add(self.sma_low.Current.Value)    
    
    def OnData(self, data):
        self.Plot("Chart", "SPY", data[self.ticker].Close)
        if self.superTrend.Value is None: return
        self.Plot("Chart", "SuperTrend", self.superTrend.Value)
        #self.Debug(" superTrend.Value is this: " + str(self.superTrend.Value))
        
    # Rolling Window code:
        if self.IsWarmingUp: return
        self.window.Add(data["SPY"])
        
        if not (self.window.IsReady and self.smaWin.IsReady): return
    #
    
    def tradeStart(self):
        self.trade = True
        
    def tradeEnd(self):
        self.trade = False
    
    def buySignals(self):
        #self.Debug(" Post Calc superTrend.Value is this: " + str(self.superTrend.Value))
        if self.trade == False or not self.superTrend.atrUp.IsReady:
            return
        #for self.superTrend, symbolData in self.symbolDataBySymbol.items():
        #    self.Debug("Er ror here: " + str(self.ticker))
        if self.superTrend.Value == self.superTrend.atrUp[0] and self.fast.Current.Value > self.slow.Current.Value: return    
        self.SetHoldings(self.superTrend.symbol, 1, True, "Buy Signal") 
                
            
    def sellSignals(self):
        
        self.Debug(" superTrend.Value is this: " + str(self.superTrend.Value))
        for self.superTrend, symbolData in self.symbolDataBySymbol.items():
            if not self.superTrend.atrDown.IsReady or self.superTrend.Value == self.superTrend.atrDown[0]: return
            #self.Liquidate(self.ticker, "Sell Signal")
            
            ## you need to assign to self.order or else variable will remain local
            self.order = self.MarketOrder(self.symbol, 1)
                
            ## you need to define fxClose or else the orders won't be properly placed
            fxClose = data[self.symbol].Close
            
            ## you need to replace sl with self.sl, as you want these to be global variables
            ## otherwise, they will not be accessible outside of OnData
            self.sl = self.StopMarketOrder(self.symbol, -1, fxClose - self.slPercent)  
            self.tp = self.LimitOrder(self.symbol, -1, fxClose + self.tpPercent)    
            
#    close = self.Securities["SPY"].Close
#        stopPrice = close * .99 # Trigger stop limit when price falls 1%.
#        limitPrice = close * 1.02 # Sell equal or better than 1.5% > close.
#        stopLimitTicket = self.SetHoldings(self.superTrend.symbol, -1, False, "Sell Signal") #self.superTrend.symbol, 1, stopPrice, limitPrice)  #self.ticker
        
    
            
    #for symbol, symbolData in self.symbolDataBySymbol.items():
    #        if self.Portfolio[symbol].Invested and (self.Securities[symbol].Close < symbolData.sma7.Current.Value):
    #           self.Liquidate(symbol, "Sell Signal")




#class SymbolData:
#    def __init__(self, symbol, ema10, ema30, sma7, sma20, sma50, rsi, wilr):
#        self.Symbol = symbol
#        self.ema10 = ema10
#        self.ema30 = ema30
#        self.sma7 = sma7
#        self.sma20 = sma20
#        self.sma50 = sma50
#        self.rsi = rsi
#        self.wilr = wilr


class SuperTrend:

    def __init__(self, algorithm:QCAlgorithm, symbol, multiplier:float, period:int, resolution:datetime.timedelta):
        self.algorithm = algorithm
        self.symbol = symbol
        self.multiplier = multiplier
        self.period = period
        self.resolution = resolution

        self.IsReady = False
        self.Value = None


        self.atr = None
        self.registerATR()


        self.Bars = RollingWindow[IBaseDataBar](2)
        self.atrWindow = RollingWindow[float](2)
        self.atrDown = RollingWindow[float](2)
        self.atrUp = RollingWindow[float](2)
        algorithm.Consolidate(self.symbol, self.resolution, self.OnStart)

        
    
    def OnStart(self, bar):
        self.Bars.Add(bar)

        if not self.atr.IsReady:
            self.IsReady = False
            return
        else: 
            self.atrWindow.Add(self.atr.Current.Value)

        if not self.Bars.IsReady or not self.atrWindow.IsReady:
            self.IsReady = False
            return
        else: 
            self.calculateAtrUpAtrDown()

        if not self.atrUp.IsReady or not self.atrDown.IsReady:
            self.IsReady = False
            return
        else:
            self.calculateSuperTrend()
        
    
        
        self.IsReady = True


    def registerATR(self):
        self.atr = AverageTrueRange(self.period) #self.algorithm.ATR(self.symbol, self.period)
        timeDeltaConsolidator = BaseDataConsolidator(self.resolution)
        self.algorithm.SubscriptionManager.AddConsolidator(self.symbol, timeDeltaConsolidator)
        self.algorithm.RegisterIndicator(self.symbol, self.atr, timeDeltaConsolidator)

    def calculateAtrUpAtrDown(self):
        hltwo = (self.Bars[0].High + self.Bars[0].Low) / 2
        hltwoPrev = (self.Bars[1].High + self.Bars[1].Low) / 2

        downNow = hltwo - self.multiplier * self.atrWindow[0]
        downPrev = hltwoPrev - self.multiplier * self.atrWindow[1]
        atrDown = max(downPrev, downNow) if self.Bars[1].Close > downPrev else downNow
        self.atrDown.Add(atrDown)

        upNow = hltwo + self.multiplier * self.atrWindow[0]
        upPrev = hltwoPrev + self.multiplier * self.atrWindow[1]
        atrUp = min(upNow, upPrev) if self.Bars[1].Close < upPrev else upNow
        self.atrUp.Add(atrUp)
        
    def calculateSuperTrend(self):
        #self.Debug(" superTrend.Value is this: " + str(self.superTrend.Value))
        if self.Bars[0].Close > self.atrUp[1]:
            self.Value = self.atrDown[0]
        elif self.Bars[0].Close < self.atrDown[1]:
            self.Value = self.atrUp[0]
        #else:
        #    self.Debug(" superTrend.Value is this: " + str(self.superTrend.Value))
        #    pass