Overall Statistics
class QuantumSpinningAlgorithm(QCAlgorithm):
    
    
    
    # Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
    def Initialize(self):
        
        
        self.BarPeriod = timedelta(hours=1)
        self.BarPeriod2 = timedelta(days=5)
        self.BarPeriod3 = timedelta(hours=4)
        self.SetCash(100000)     
        self.tp= 30/10000
        self.sl = 20/10000
        self.StopLoss = None
        self.ProfitTarget = None
        self.last_trail_level = None
        self.SimpleMovingAveragePeriod =14
        self.RSIPeriod = 14
        self.BBPeriod = 20
        self.RSI_OB1   = 71            
        self.RSI_OB2   = 75
        self.RSI_OS   = 28            
        self.k1 = 2
        self.k2 = 4 
        self.Quantity = 10000
        # This is the number of consolidated bars we'll hold in symbol data for reference
        self.RollingWindowSize = 5
        # Holds all of our data keyed by each symbol
        self.Data = {}
        # Contains all of our equity symbols
        #EquitySymbols = ["AAPL","SPY","IBM"]
        # Contains all of our forex symbols
        ForexSymbols =["EURUSD", "USDJPY", "EURGBP", "EURCHF", "USDCAD", "USDCHF", "GBPUSD", "AUDUSD","NZDUSD"]
        

        
        self.SetStartDate(2015, 12, 1)
        self.SetEndDate(2018, 1, 1)
       
       
       
    
        
        # initialize our forex data 
        for symbol in ForexSymbols:
            forex = self.AddForex(symbol,Resolution.Hour)
            self.Data[symbol] = SymbolData(forex.Symbol, self.BarPeriod, self.RollingWindowSize)

        # loop through all our symbols and request data subscriptions and initialize indicator
        for symbol, symbolData in self.Data.items():
            # define the indicator
            #symbolData.SMA = SimpleMovingAverage(self.CreateIndicatorName(symbol, "SMA" + str(self.SimpleMovingAveragePeriod), Resolution.Hour), self.SimpleMovingAveragePeriod)
            symbolData.Bolband = self.BB(symbol, self.BBPeriod, self.k1, MovingAverageType.Simple, Resolution.Hour)
            #symbolData.Bolband_stop = self.BB(symbol, self.BBPeriod, self.k2,MovingAverageType.Simple, Resolution.Hour)
            symbolData.RSI = self.RSI(symbol,  self.RSIPeriod,Resolution.Hour)
            symbolData.RSI2 = self.RSI(symbol,  self.RSIPeriod)
            symbolData.RSI3 = self.RSI(symbol,  self.RSIPeriod, Resolution.Daily)
            symbolData.RSI4 = self.RSI(symbol,  self.RSIPeriod)
            
        
            
            
            
            # define a consolidator to consolidate data for this symbol on the requested period
            consolidator =  QuoteBarConsolidator(self.BarPeriod)
            # write up our consolidator to update the indicator
            consolidator.DataConsolidated += self.OnDataConsolidated
            # we need to add this consolidator so it gets auto updates
            self.SubscriptionManager.AddConsolidator(symbolData.Symbol, consolidator)
            self.RegisterIndicator(symbolData.Symbol, symbolData.RSI, consolidator)
            
            
            # create the fourhour data consolidator
            fourhourConsolidator = QuoteBarConsolidator(self.BarPeriod2)
            # write up our consolidator to update the indicator
            fourhourConsolidator.DataConsolidated += self.OnDataConsolidated
            
            
            self.SubscriptionManager.AddConsolidator(symbolData.Symbol, fourhourConsolidator)
            # register the weekly  consolidated bar data to automatically update the indicator
            self.RegisterIndicator(symbolData.Symbol, symbolData.RSI2, fourhourConsolidator)      
            self.RegisterIndicator(symbolData.Symbol, symbolData.Bolband, fourhourConsolidator)

            # create the weekly data consolidator
            weeklyConsolidator = QuoteBarConsolidator(self.BarPeriod2)
            # write up our consolidator to update the indicator
            weeklyConsolidator.DataConsolidated += self.OnDataConsolidated
           
            self.SubscriptionManager.AddConsolidator(symbolData.Symbol, weeklyConsolidator)
            # register the weekly  consolidated bar data to automatically update the indicator
            self.RegisterIndicator(symbolData.Symbol, symbolData.RSI4, weeklyConsolidator)      
            
            self.Schedule.On(self.DateRules.WeekStart(symbol),self.TimeRules.At( 8, 5),self.StartTrading)

    def OnDataConsolidated(self, sender, bar):
        
        self.Data[bar.Symbol.Value].RSI2.Update(bar.Time, bar.Close)
        self.Data[bar.Symbol.Value].RSI3.Update(bar.Time, bar.Close)
        self.Data[bar.Symbol.Value].RSI4.Update(bar.Time, bar.Close)
        self.Data[bar.Symbol.Value].RSI.Update(bar.Time, bar.Close)
        #self.Data[bar.Symbol.Value].SMA.Update(bar.Time, bar.Close)
        self.Data[bar.Symbol.Value].Bolband.Update(bar.Time, bar.Close)
        
        self.Data[bar.Symbol.Value].Bars.Add(bar)

    # OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
    # Argument "data": Slice object, dictionary object with your stock data 
    def OnData(self,data):
        
        pass    
    
    
    def StartTrading(self):
        
      
    
        # loop through each symbol in our structure
        for symbol in self.Data.keys():
            symbolData = self.Data[symbol]
            # this check proves that this symbol was JUST updated prior to this OnData function being called
            if  symbolData.IsReady() and symbolData.WasJustUpdated(self.Time):                 
                
                #Set Current Price 
                price = symbolData.Bars[0].Close       
            
                #Set StopLoss level
                base_sl_level = price + self.sl
                
                
                holdings = self.Portfolio[symbol].Quantity
                value = self.Portfolio.TotalPortfolioValue
                cash = self.Portfolio.Cash
                
                # Log OHLC - This can be useful for debugging to see where price is moving
                self.Log('>> {}      >> ON DATA >> >> >> >> >> >>'.format(symbol))
                self.Log('>> SL       >> Base Level:{} Last Trail Level:{}'.format(base_sl_level, self.last_trail_level))
                self.Log('>> Account  >> Cash:{}, Val:{}, Holdings:{}'.format(cash,value,holdings))
                        
          
                
                if not (self.Portfolio[symbol].Invested):
                    
                    
                        
                        
                            #Short Sell the pair 
                            CurrentOrder= self.MarketOrder(symbol, -(self.Quantity))
                        
                            #Set StopLoss order
                            self.StopLoss = self.StopMarketOrder(symbol, self.Quantity, base_sl_level)
                            self.last_trail_level = base_sl_level
                        
                            #Set Profit Target 
                            self.ProfitTarget = self.LimitOrder(symbol, self.Quantity, price-self.tp)
                        
                            
                
                            
                
                else:
                    if base_sl_level < self.last_trail_level:
                        self.Log('>> Updating Trailing Stop >>')
                    
                       
                        # Upate our stoploss order! 
                        update_order_fields = UpdateOrderFields()
                        update_order_fields.StopPrice = base_sl_level
                        self.StopLoss.Update(update_order_fields)
                        
                        # Log last sl_level
                        self.last_trail_level = base_sl_level
                
       
 
    #If the StopLoss or ProfitTarget is filled, cancel the other
    
    def OnOrderEvent(self,orderEvent):
       
        # This will check for the boolean value of whether or not the order has been filled
        if not (orderEvent.Status == 'Filled'):
           return 
        
        #python doesn't support null. Instead, check for None
       
        if (self.ProfitTarget is None) or (self.StopLoss is None): 
            return 
        
          
            
        filledOrderId = orderEvent.OrderId

        # If the ProfitTarget order was filled, close the StopLoss order
        if (self.ProfitTarget.OrderId == filledOrderId):
            
            self.StopLoss.Cancel()
            

        #If the StopLoss order was filled, close the ProfitTarget
        if (StopLoss.OrderId == filledOrderId):
            
            self.ProfitTarget.Cancel()
            
         
        
        
   
   
 
       
class SymbolData(object):
    
    def __init__(self, symbol, barPeriod, windowSize):
        self.Symbol = symbol
        # The period used when population the Bars rolling window
        self.BarPeriod = barPeriod
        # A rolling window of data, data needs to be pumped into Bars by using Bars.Update( tradeBar ) and can be accessed like:
        # mySymbolData.Bars[0] - most first recent piece of data
        # mySymbolData.Bars[5] - the sixth most recent piece of data (zero based indexing)
        self.Bars = RollingWindow[IBaseDataBar](windowSize)
        # The  indicators for our symbol
        
        self.Bolband = None
        self.Bolband_stop =None
        self.RSI4 = None
        self.RSI3 = None
        self.RSI2 = None
        self.RSI = None
        self.SMA = None
        
    # Returns true if all the data in this instance is ready (indicators, rolling windows, ect...)
    def IsReady(self):
        return self.Bars.IsReady and self.RSI.IsReady and self.Bolband.IsReady and self.RSI2.IsReady and self.RSI3.IsReady and self.RSI4.IsReady

     # Returns true if the most recent trade bar time matches the current time minus the bar's period, this
    # indicates that update was just called on this instance
    def WasJustUpdated(self, current):
        return self.Bars.Count > 0 and self.Bars[0].Time == current - self.BarPeriod