Overall Statistics
'''
For notes, etc.

Full API (C# only): https://www.quantconnect.com/lean/docs

Python API with examples (doesn't include every method but does include most): https://www.quantconnect.com/docs/algorithm-reference/overview

Time example: https://www.quantconnect.com/forum/discussion/142/how-to-get-simulated-time-and-date

Crisis Events: https://www.quantconnect.com/blog/leans-tear-sheet-the-lean-report-creator/

Bracket Orders https://www.quantconnect.com/forum/discussion/3328/futures-quot-bracket-order-quot-example/p1

To do:
- Universe Selection
- Option intergration
- Going back certain number of periods using slices to get indicator values prior to our current period
- Trailing Stop Loss

'''

class MultipleSymbolConsolidationAlgorithm(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):
        
        
        
        #Initial investment and backtest period
        self.SetStartDate(2015, 1, 1)                                  
        self.SetEndDate(datetime.now().date() - timedelta(1))        
        self.SetCash(20000)

        
        
        
        #Brokerage Model
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage)    
        
        # This is the period of bars we'll be creating
        BarPeriod = TimeSpan.FromMinutes(20)
       
        # This is the period of our rsi indicators
        RSIPeriod = 30
        
        # This is the period of our vwap indicators
        VWAPPeriod = 10
        
        # This is the period of our volume moving average
        TEMAvolumePeriod = 8
        
        # This is the the volume of the last bar
        SMAvolumeOnePeriod = 1
        
        # This is the period of our sma indicators
        SimpleMovingAveragePeriod = 30
        
        # This is the period of our last price
        SimpleMovingAverageonePeriod = 1
       
        # This is the period of our ema indicators
        ExponentialMovingAveragePeriod = 8
       
        # This is the period of our tema indicators
        TripleExponentialMovingAveragePeriod = 8
       
        # This is the number of consolidated bars we'll hold in symbol data for reference
        RollingWindowSize = 30
        
       
        # Holds all of our data keyed by each symbol
        self.Data = {}
        
        
        
        # Contains all of our equity symbols
        EquitySymbols = ["AAPL"]
        
        # initialize our equity data
        for symbol in EquitySymbols:
            equity = self.AddEquity(symbol)
            self.Data[symbol] = SymbolData(equity.Symbol, BarPeriod, 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(SimpleMovingAveragePeriod), Resolution.Minute), SimpleMovingAveragePeriod)
            
            
            # define the indicator
            symbolData.RSI = RelativeStrengthIndex(self.CreateIndicatorName(symbol, "RSI" + str(RSIPeriod), Resolution.Minute), RSIPeriod, MovingAverageType.Simple)
            
            # define the indicator
            symbolData.SMAone = SimpleMovingAverage(self.CreateIndicatorName(symbol, "SMA" + str(SimpleMovingAverageonePeriod), Resolution.Minute), SimpleMovingAverageonePeriod)

            
            # define a consolidator to consolidate data for this symbol on the requested period
            consolidator = TradeBarConsolidator(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)


    def OnDataConsolidated(self, sender, bar):
        
        self.Data[bar.Symbol.Value].SMA.Update(bar.Time, bar.Close)
        self.Data[bar.Symbol.Value].SMAone.Update(bar.Time, bar.Close)
        self.Data[bar.Symbol.Value].RSI.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):
             
        # loop through each symbol in our structure
        for symbol in self.Data.keys():
            symbolData = self.Data[symbol]
            
            stopLossPercent =  .99
            profitTargetPercent = 1.02
            

            
            # this check proves that this symbol was JUST updated prior to this OnData function being called
            if symbolData.IsReady() and symbolData.WasJustUpdated(self.Time):
                    
                #----TIME VARIABLES----
                # Set up pre-market close time
                CloseTimeString = "15:44:00"
                CloseOutTime = datetime.strptime(CloseTimeString, "%H:%M:%S")
                CloseTime = datetime.time(CloseOutTime)
                #self.Debug(str(CloseTime) + " CLOSETIME ")
            
                # Get symbol trade time
                DataSymbolTime = data[symbol].Time
                DataTime = datetime.time(DataSymbolTime)
                #self.Debug(str(DataTime) + " DATATIME ")
                #----TIME VARIABLES----
                
                # Check to see if we are near market close
                if DataTime < CloseTime:
                    
                    #if we do not own this symbol
                    if not self.Portfolio[symbol].Invested:
                            
                           
                                        
                        #if RSI value is less than 'x'
                        if float(symbolData.RSI.Current.Value) < 35:
                            
                           
                            #Liquidate opposite symbol
                            self.Liquidate()
                            self.Debug("LIQUIDATING in loop...")
                            
                            #Cancel open ordersif there are any
                            openOrders = self.Transactions.GetOpenOrders()
                            if len(openOrders)> 0:
                                for x in openOrders:
                                     self.Transactions.CancelOrder(x.Id)
                           
                            # Set Position Size
                            posSize = self.CalculateOrderQuantity(symbol, 1)
                            
                            # Market Order to buy
                            self.MarketOrder(symbol, posSize)
                            
                            
                            # Stop Loss/Profit Taker
                            self.StopLimitOrder(symbol, -posSize, float(symbolData.SMAone.Current.Value) * stopLossPercent, float(symbolData.SMAone.Current.Value) * profitTargetPercent)
                                    
                                                       
                                                              
    # End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets).
    # Method is called 10 minutes before closing to allow user to close out position.
    def OnEndOfDay(self):
        
        
        
        #Liquidate all symbol
        self.Liquidate()
        self.Debug("LIQUIDATING at end of day...")
        
        '''
        #Cancel open ordersif there are any
        openOrders = self.Transactions.GetOpenOrders()
        if len(openOrders)> 0:
            for x in openOrders:
                 self.Transactions.CancelOrder(x.Id)
        '''
        '''
        i = 0
        for symbol in sorted(self.Data.keys()):
            symbolData = self.Data[symbol]
            # we have too many symbols to plot them all, so plot every other
            i += 1
            if symbolData.IsReady() and i%2 == 0:
                self.Plot(symbol, symbol, symbolData.SMA.Current.Value)
        '''      
    
       
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 simple moving average indicator for our symbol
        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.SMA.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