Overall Statistics
Total Trades
449
Average Win
11.49%
Average Loss
-0.15%
Compounding Annual Return
36.528%
Drawdown
48.000%
Expectancy
14.095
Net Profit
2836.220%
Sharpe Ratio
1.221
Probabilistic Sharpe Ratio
57.257%
Loss Rate
80%
Win Rate
20%
Profit-Loss Ratio
74.14
Alpha
0.365
Beta
-0.173
Annual Standard Deviation
0.282
Annual Variance
0.079
Information Ratio
0.66
Tracking Error
0.336
Treynor Ratio
-1.993
Total Fees
$1186.03
import pandas as pd
#https://www.quantconnect.com/forum/discussion/7867/tim-sykes-and-penny-stocks/p1
class CalibratedUncoupledCoreWave(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 5, 1)  # Set Start Date
        #self.SetEndDate(2020, 3, 11)  # Set End Date
        self.SetCash(100000)          # Set Strategy Cash
        
        # Setup universe
        self.UniverseSettings.Resolution = Resolution.Minute
        self.AddUniverse(self.SelectCoarse,self.SelectFine)
        self.AddEquity("SPY", Resolution.Minute)
        
        # Liquidate all positions before the market close each day
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 30), self.ClosePositions)
        
        self.coarseclose={}    # Store yesterday's close in a dictionary for reference
        self.volumeprior = {}  # Last x days' average dollar volume
        self.stddev={}         # Standard Deviation
        self.minmax={}         # Ratio of Hi Lo of last x days' close price    
        self.cumvol={}         # Cumulative volume throughout trading day    
        self.traded={}         # Ensure only 1 trade per day per stock
        self.targetentry=1.05  # Only enter a trade if today's price doubles yesterday's close
        self.stops = {}        # Keep track of stop loss orders so we can update them
        
        #self.coarsefilter = 50 # return the top x stocks sorted by [momentum] etc
        self.histlength = 60 # lngth of history to call to ensure sufficient data


    def SelectCoarse(self, coarse):
        # Penny Stock filter
        myuniverse = [x for x in coarse if x.HasFundamentalData and \
                                           float(x.Volume) > 2000000 and \
                                           300 >= float(x.Price) >= 20]
        # rank the stocks by dollar volume and choose the top 150
        myuniverse = sorted(myuniverse, key=lambda x: x.DollarVolume, reverse=True)[:150]

        self.coarseclose.clear()  # Clear the dictionary each day before re-populating it
        self.volumeprior.clear()
        self.stddev.clear()
        self.minmax.clear()
        stocks = {x.Symbol: x for x in myuniverse} 
        histStocks=list(stocks.keys())
        history = self.History(histStocks, self.histlength, Resolution.Daily)

        scam={}
        for stock in histStocks:
            if stock in history.index:
                df = pd.DataFrame()
                if not history.loc[stock].empty:
                    df = history.loc[stock].dropna()
                if df.empty or len(df)<self.histlength:
                    continue
                # Some alternative filters
                self.volumeprior[stock] = df['volume'][-5:].mean()
                self.stddev[stock]=((df["close"][-5:].pct_change()).std())*15.87*100
                self.minmax[stock]=((df["close"][-10:].max()/df["close"][-10:].min())-1)*100
                if self.minmax[stock] < 10.00  and self.volumeprior[stock]< 50000 :
                    scam[stock]= self.minmax[stock]
                
        #scammed=[key for (key, value) in sorted(scam.items(),reverse=False)] 
        scammed=[key for (key, value) in scam.items()]

        
        # Save yesterday's close
        for c in myuniverse:
            self.coarseclose[c.Symbol] = c.AdjustedPrice
        
        return scammed[:] # Return filtered stocks for further filtering by the SelectFine
        
    def SelectFine(self,fine):
        ''' 
        This function takes the stock of the CoarceFundamental function and narrow the list adding specific fundamental filters
        Largely to ensure that only common stock is traded and not EG Preference Shares or ETFs
        '''
        # Primary share, common stock, not limited partnership, and not ADR
        fine_filter = [x.Symbol for x in fine if x.SecurityReference.IsPrimaryShare == 1 and \
                                                 x.SecurityReference.SecurityType == 'ST00000001' and \
                                                 x.CompanyReference.IsLimitedPartnership == 0 and \
                                                 x.SecurityReference.IsDepositaryReceipt == 0 ]
        self.traded.clear()
        self.traded = {k: 0 for k in fine_filter}
        self.cumvol.clear()
        self.cumvol = {k: 0 for k in fine_filter}
        return fine_filter

    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        Arguments:
            data: Slice object keyed by symbol containing the stock data
        '''
        for kvp in data.Bars:
            symbol = kvp.Key
            close = kvp.Value.Close
            if symbol in self.cumvol.keys():
                 self.cumvol[symbol]=self.cumvol[symbol]+(kvp.Value.Close*kvp.Value.Volume)
            
            # Entry conditions:
            #  - We have no position in this stock
            #  - We haven't traded this symbol today
            #  - Bar closed above our target
            #  - Before 10:30am
            #  - Cumulative Volume for the day exceeds average total dollar volume for past x days
            if (self.Portfolio[symbol].Quantity == 0.0 and
                symbol in self.traded.keys() and
                self.traded[symbol] == 0 and              
                close >= self.coarseclose[symbol]*self.targetentry and 
                self.Time.hour <= 10 and self.Time.minute <=30 and   
                self.cumvol[symbol] >= self.volumeprior[symbol]): 
                
                # Signal today's entry
                self.traded[symbol] = 1

                # Determine position size
                quantity = int(self.Portfolio.TotalPortfolioValue / 100 / data[symbol].Close) #self.CalculateOrderQuantity(symbol, 0.01) // 2
                if quantity < 4:
                    continue
                
                # Enter with market order
                enter_ticket = self.MarketOrder(symbol, quantity)
                
                # Set profit targets 
                quarter = int(quantity / 4)
                final = quantity - 3 * quarter
                for i in range(3):
                    order = self.LimitOrder(symbol, -quarter, enter_ticket.AverageFillPrice * (1 + (i+1)*0.05))
                    updateSettings = UpdateOrderFields()
                    updateSettings.Tag = "pt"
                    order.Update(updateSettings)
                order = self.LimitOrder(symbol, -final, enter_ticket.AverageFillPrice * 1.20)
                order.Update(updateSettings)
            
                # Set stop loss
                self.stops[symbol] = self.StopMarketOrder(symbol, -quantity, enter_ticket.AverageFillPrice * 0.50)
                updateSettings.Tag = "sl"
                self.stops[symbol].Update(updateSettings)

    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Filled: 
            order = self.Transactions.GetOrderById(orderEvent.OrderId)
            if order.Tag == 'pt':  # If hit profit target, update stop order quantity
                updateSettings = UpdateOrderFields()
                updateSettings.Quantity = self.stops[orderEvent.Symbol].Quantity - orderEvent.Quantity
                self.stops[orderEvent.Symbol].Update(updateSettings)

            elif order.Tag == 'sl': # If hit stop loss, cancel profit target orders
                self.Transactions.CancelOpenOrders(orderEvent.Symbol, "Hit stop price")

    def ClosePositions(self):        
        if self.Portfolio.Invested:
            self.Transactions.CancelOpenOrders()
            self.Liquidate()
import pandas as pd
import numpy as np

class VixFix:
    def __init__(self, data, ticker, *args, **kwargs):
        super(VixFix, self).__init__()
        self.data = data
        self.ticker = ticker
        self.length = 22
        self.bbl = 20
        self.mult = 2.0
        self.lb = 50
        self.ph = 0.85
        self.pl = 1.01
        
    def sma(self):
        cumsum = np.cumsum(np.insert(self.wvf, 0, 0))
        return (cumsum[-self.bbl:] - cumsum[:self.bbl])/float(self.bbl)
    
    def run(self):
        self.prices = self.data.loc[str(self.ticker)]['close']
        
        def wvf(x):
            low = x[-1]
            return ((max(x) - low)/max(x)) * 100
        
        rolling_wvf = self.prices.rolling(self.length).apply(wvf)
        
        rolling_wvf_sDev = self.mult * rolling_wvf.rolling(self.bbl).std()
        
        midline = rolling_wvf.rolling(self.bbl).mean().tolist()
        
        lowerBand = midline - rolling_wvf_sDev
        upperBand = midline + rolling_wvf_sDev
        
        rangeHigh = max(self.prices.rolling(self.lb).apply(wvf)) * self.ph
        rangeLow = max(self.prices.rolling(self.lb).apply(wvf)) * self.pl
        
        # Test market bottom
        previous_wvf, current_wvf = rolling_wvf.drop(rolling_wvf.tail(1).index), rolling_wvf.tail(1).values[0]
        if (current_wvf >= max(upperBand)): # or (current_wvf >= max(rangeHigh)):
            if current_wvf > previous_wvf.drop(previous_wvf.tail(1).index):
                return 'Yes'
            else:
                return 'No'
import pandas as pd
import numpy as np

class VixFix:
    def __init__(self, data, ticker, *args, **kwargs):
        super(VixFix, self).__init__()
        self.data = data
        self.ticker = ticker
        self.length = 22
        self.bbl = 20
        self.mult = 2.0
        self.lb = 50
        self.ph = 0.85
        self.pl = 1.01
        
    def sma(self):
        cumsum = np.cumsum(np.insert(self.wvf, 0, 0))
        return (cumsum[-self.bbl:] - cumsum[:self.bbl])/float(self.bbl)
    
    def run(self):
        self.prices = self.data.loc[str(self.ticker)]['close']
        
        def wvf(x):
            low = x[-1]
            return ((max(x) - low)/max(x)) * 100
        
        rolling_wvf = self.prices.rolling(self.length).apply(wvf)
        
        rolling_wvf_sDev = self.mult * rolling_wvf.rolling(self.bbl).std()
        
        midline = rolling_wvf.rolling(self.bbl).mean().tolist()
        
        lowerBand = midline - rolling_wvf_sDev
        upperBand = midline + rolling_wvf_sDev
        
        rangeHigh = max(self.prices.rolling(self.lb).apply(wvf)) * self.ph
        rangeLow = max(self.prices.rolling(self.lb).apply(wvf)) * self.pl
        
        # Test market bottom
        previous_wvf, current_wvf = rolling_wvf.drop(rolling_wvf.tail(1).index), rolling_wvf.tail(1).values[0]
        if (current_wvf >= max(upperBand)): # or (current_wvf >= max(rangeHigh)):
            if current_wvf > previous_wvf.drop(previous_wvf.tail(1).index):
                return 'Yes'
            else:
                return 'No'
from QuantConnect.Data.UniverseSelection import *
import pandas as pd
import numpy as np
import DeltaModel as DeltaModel


class EnhancedShortTermMeanReversionAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2016, 1, 1)  #Set Start Date
        self.SetEndDate(2020, 9, 24)   #Set Start Date       
        self.SetCash(50000)            #Set Strategy Cash
        
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        self.AddEquity("SPY", Resolution.Daily)
        # rebalance the universe selection once a month
        self.rebalence_flag = 0
        # make sure to run the universe selection at the start of the algorithm even it's not the month start
        self.first_month_trade_flag = 1
        self.trade_flag = 0  
        # Number of quantiles for sorting returns for mean reversion
        self.nq = 5
        # Number of quantiles for sorting volatility over five-day mean reversion period
        self.nq_vol = 3
        # the symbol list after the coarse and fine universe selection
        self.universe = None
        
        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.At(0, 0), Action(self.monthly_rebalance))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 304), Action(self.get_prices))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 303), Action(self.daily_rebalance))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 302), Action(self.calc_avg_delta))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 301), Action(self.short))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 300), Action(self.long))
    
    def monthly_rebalance(self):
        # rebalance the universe every month
        self.rebalence_flag = 1
 
    def CoarseSelectionFunction(self, coarse):
        
        if self.rebalence_flag or self.first_month_trade_flag:
            # drop stocks which have no fundamental data or have too low prices
            selected = [x for x in coarse if (x.HasFundamentalData) and (float(x.Price) > 15) and (float(x.Volume) >= 1000000)]
            # rank the stocks by dollar volume and choose the top 50
            filtered = sorted(selected, key=lambda x: x.DollarVolume, reverse=True) 

            return [x.Symbol for x in filtered[:20]]
        else:
            return self.universe

    def FineSelectionFunction(self, fine):

        if self.rebalence_flag or self.first_month_trade_flag:
            # filter the stocks which have positive EV To EBITDA
            filtered_fine = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0]
            self.universe = [x.Symbol for x in filtered_fine]
            
            self.rebalence_flag = 0
            self.first_month_trade_flag = 0
            self.trade_flag = 1
            
        return self.universe

    def OnData(self, data):
        pass
    
    def short(self):
        if self.universe is None: return
        SPY_Velocity = 0
        self.long_leverage = 0
        self.short_leverage = 0
        # request the history of benchmark
        pri = self.History(["SPY"], 200, Resolution.Daily)
        pos_one = (pri.loc["SPY"]['close'][-1])
        pos_six = (pri.loc["SPY"]['close'][-75:].mean())
        # calculate velocity of the benchmark 
        velocity_stop = (pos_one - pos_six)/100.0
        SPY_Velocity = velocity_stop
        if SPY_Velocity > 0.0:
            self.long_leverage = 1.8
            self.short_leverage = -0.0
        else:
            self.long_leverage = 1.1
            self.short_leverage = -0.7
        for symbol in self.shorts:
            if len(self.shorts) + self.existing_shorts == 0: return
            self.AddEquity(symbol, Resolution.Daily)
            self.SetHoldings(symbol, self.short_leverage/(len(self.shorts) + self.existing_shorts))                                
 
    def long(self):
        if self.universe is None: return
        for symbol in self.longs:
            if len(self.longs) + self.existing_longs == 0: return
            self.AddEquity(symbol, Resolution.Daily)
            self.SetHoldings(symbol, self.long_leverage/(len(self.longs) + self.existing_longs))                                
       
    def get_prices(self):
        if self.universe is None: return
        # Get the last 15 days of prices for every stock in our universe
        prices = {}
        hist = self.History(self.universe, 15, Resolution.Daily)
        for i in self.universe:
            if str(i) in hist.index.levels[0]:
                prices[i.Value] = hist.loc[str(i)]['close']
        df_prices = pd.DataFrame(prices, columns = prices.keys()) 
        # calculate the daily log return
        daily_rets = np.log(df_prices/df_prices.shift(1))
        # calculate the latest return but skip the most recent price
        rets = (df_prices.iloc[-2] - df_prices.iloc[0]) / df_prices.iloc[0]
        # standard deviation of the daily return
        stdevs = daily_rets.std(axis = 0)
        self.ret_qt = pd.qcut(rets, 5, labels=False) + 1
        self.stdev_qt = pd.qcut(stdevs, 3, labels=False) + 1
        self.longs = list((self.ret_qt[self.ret_qt == 1].index) & (self.stdev_qt[self.stdev_qt < 3].index))
        self.shorts = list((self.ret_qt[self.ret_qt == self.nq].index) & (self.stdev_qt[self.stdev_qt < 3].index))
    
    def calc_avg_delta(self):
        gains = list()
        delta_percent_ten = list()
        delta_avg_percent = 0.0
        
        prices = self.History([str(self.symbol)], 20, Resolution.Daily)['close'].values.tolist()
        
        prices = list(reversed(prices))
        
        for i in range(0, len(prices)-1):
            current = prices[i]
            previous = prices[i+1]
            gains_percent = ((current - previous)/previous) * 100.0
            gains.append(gains_percent)
        
        for i in range(0, len(gains)-1):
            current_gain = gains[i]
            last_ten_gain = gains[i+9]
            delta_percent = ((current_gain - last_ten_gain)/last_ten_gain) * 100.0
            if len(delta_percent_ten) < 10:
                delta_percent_ten.append(delta_percent)
            elif len(delta_percent_ten) == 10:
                delta_avg_percent = float(sum(delta_percent_ten)/len(delta_percent_ten))
        
        return delta_avg_percent
 
    def daily_rebalance(self):
        # rebalance the position in portfolio every day           
        if self.universe is None: return
        self.existing_longs = 0
        self.existing_shorts = 0
       
        for symbol in self.Portfolio.Keys:
            if (symbol.Value != 'SPY') and (symbol.Value in self.ret_qt.index):
                current_quantile = self.ret_qt.loc[symbol.Value]
                
                avg_delta = self.calc_avg_delta(symbol)
                
                if self.Portfolio[symbol].Quantity > 0 and avg_delta > -5.5:
                    if (current_quantile == 1) and (symbol not in self.longs):
                        self.existing_longs += 2
                    elif (current_quantile > 1) and (symbol not in self.shorts): 
                        self.SetHoldings(symbol, 0)
                elif self.Portfolio[symbol].Quantity < 0 and avg_delta > -5.5:
                    if (current_quantile == self.nq) and (symbol not in self.shorts):
                        self.existing_shorts += 1
                    elif (current_quantile < self.nq) and (symbol not in self.longs): 
                        self.SetHoldings(symbol, 0)
                        
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Invalid:
            self.Log(str(orderEvent))
            
            
            # multi-task, multi-level learning
import pandas as pd
import numpy as np

class DeltaModel:
    """
    This class continues to buy an equity until the average delta over the last 10 periods exceeds -5.5%
    """
    def __init__(self, data, ticker, *args, **kwargs):
        super(DeltaModel, self).__init__()
        self.data = data
        self.ticker = ticker
        self.prices = list()
        self.gains = list()
        self.delta_percent_ten = list()
        self.delta_avg_percent = 0.0
        
    def run(self):
        self.prices = list(reversed(self.data.loc[str(self.ticker)]['close'].tolist()))
        
        if len(self.prices) >= 2:
            current = self.prices[-1]
            previous = self.prices[-2]
            gains_percent = ((current - previous)/previous) * 100.0
            if len(self.gains) < 15:
                self.gains.append(gains_percent)
            else:
                del self.gains[0]
                self.gains.append(gains_percent)
        
        if len(self.delta_percent_ten) >= 10:
            smallest_gain = min(self.gains[-10:])
            largest_gain = max(self.gains[-10:])
            delta_percent = ((smallest_gain - largest_gain)/largest_gain) * 100.0
            if len(self.delta_percent_ten) < 10:
                self.delta_percent_ten.append(delta_percent)
            else:
                del self.delta_percent_ten[0]
                self.delta_percent_ten.append(delta_percent)
            
            self.delta_avg_percent = sum(self.delta_percent_ten)/len(self.delta_percent_ten)  
        
        return self.delta_avg_percent
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel, NullPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Risk import MaximumDrawdownPercentPortfolio, MaximumUnrealizedProfitPercentPerSecurity, MaximumDrawdownPercentPerSecurity
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

from datetime import datetime, timedelta
import pandas as pd
import numpy as np
import re
import scipy as sp
from collections import deque
from math import ceil
from itertools import chain
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

from DeltaModel import DeltaModel
from VixFix import VixFix
from UniverseSelectionHelperFunctions import SelectionData, SymbolData
from CompositeTradeSignals import CompositeTradeSignals
from SequoiaAlphaModel import SequoiaAlphaModel
from IchimokuCloudCrossOverAlphaModel import IchimokuCloudCrossOverAlphaModel

from trading_algorithm import TradingAlgorithm_main

class EnhancedShortTermMeanReversionAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2010, 1, 1)  #Set Start Date
        self.SetCash(10000)            #Set Strategy Cash
        self.SetWarmUp(timedelta(minutes=1))   # Set Algorithm to 21 days
        
        #self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        # rebalance the universe selection once a month
        self.rebalance_flag = 0
        # make sure to run the universe selection at the start of the algorithm even it's not the month start
        self.first_month_trade_flag = 1
        self.trade_flag = 0  
        # Number of quantiles for sorting returns for mean reversion
        self.nq = 5
        # Number of quantiles for sorting volatility over five-day mean reversion period
        self.nq_vol = 3
        # the symbol list after the coarse and fine universe selection
        self.universe = None
        self.NumberOfSymbolsFine = 500
        self.NumberOfSymbolsCoarse = 150
        self.dollarVolumeBySymbol = {}
        
        # setup state storage in initialize method    
        self.dataDict = {}
        
        # Benchmark
        self.AddEquity("SPY", Resolution.Daily)
        self.SetBenchmark("SPY")
        
        # weighting stuffs
        self.lookback = 20*6
        self.portfolios = deque(maxlen=6)
        
        # SPY HIGH
        self.correction_flag = 0
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
    
    def monthly_rebalance(self):
        # rebalance the universe every month
        self.rebalance_flag = 1
 
    def CoarseSelectionFunction(self, coarse):
        if self.rebalance_flag or self.first_month_trade_flag:
            # drop stocks which have no fundamental data or have too low prices
            coarse_filtered = [x for x in coarse if (x.HasFundamentalData) and (20 <= float(x.Price) <= 300) and (float(x.Volume) >= 2000000)]
            # We are going to use a dictionary to refer the object that will keep the moving averages
            for c in coarse_filtered:
                if c.Symbol not in self.stateData:
                    self.stateData[c.Symbol] = SelectionData(c.Symbol, 10)
                
                # Updates the SymbolData object with current EOD price
                avg = self.stateData[c.Symbol]
                avg.update(c.EndTime, c.Price, c.Volume, c.DollarVolume)
            
            # filter the values of selectionData(sd) above SMA
            values = [sd for sd in self.stateData.values() if (sd.Volume > (sd.Sma.Current.Value * 1.25)) and (sd.Volume_Ratio > 2) 
                        and (sd.Fast_Vol_Ratio > 2) and (sd.Med_Vol_Ratio > 2)]
            
            # sort sd by the largest % jump in volume.
            values.sort(key=lambda sd: sd.Volume_Ratio, reverse=True)
            
            self.dollarVolumeBySymbol = {i.Symbol: i.DollarVolume for i in values[:self.NumberOfSymbolsCoarse]}
            
            return [x.Symbol for x in values[:self.NumberOfSymbolsCoarse]]
        else:
            return self.universe

    def FineSelectionFunction(self, fine):
        def upper_groups(x):
            x = np.asarray(x, dtype=np.float32)
            x = x[x >= 0]
            cutoff = np.mean(x, dtype=np.float64) #+ (np.std(x, dtype=np.float64) * 2)
            return cutoff
            
        if self.rebalance_flag or self.first_month_trade_flag:
            """
            Need to do a better job with filter system with multiple parameters
                - currently takes the top 50% in each category and checks if stock is top 50% in each category
            """
            # filter the stocks which have positive EV To EBITDA
            # filtered_fine = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
            #                     and x.ValuationRatios.PriceChange1M > 0   
            #                     and x.CompanyReference.CountryId == "USA"
            #                     and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
            #                     and x.CompanyReference.IndustryTemplateCode == "N"
            #                     and x.ValuationRatios.PERatio > 20
            #                     and x.ValuationRatios.FirstYearEstimatedEPSGrowth > 0.2
            #                     and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
            #                     and (x.Time - x.SecurityReference.IPODate).days > 180
            #                     and x.ValuationRatios.PEGRatio > 2
            #                     and x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > 10]
                                
            # if len(filtered_fine) <= 0:
            initial_filter = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
                                and x.ValuationRatios.PriceChange1M > 0
                                and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
                                and (x.Time - x.SecurityReference.IPODate).days > 180 and x.CompanyReference.CountryId == "USA"
                                and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
                                and x.CompanyReference.IndustryTemplateCode == "N"
                                and x.AssetClassification.MorningstarSectorCode in [MorningstarSectorCode.FinancialServices,
                                MorningstarSectorCode.Technology, MorningstarSectorCode.Industrials, MorningstarSectorCode.CommunicationServices,
                                MorningstarSectorCode.ConsumerCyclical, MorningstarSectorCode.ConsumerDefensive, MorningstarSectorCode.Healthcare,
                                MorningstarSectorCode.Utilities]]
                    
            PERatio_mean = upper_groups([float(x.ValuationRatios.PERatio) for x in initial_filter if x.ValuationRatios.PERatio > 0])
            PEGRatio_mean = upper_groups([float(x.ValuationRatios.PEGRatio) for x in initial_filter if x.ValuationRatios.PEGRatio >= 0])
            #SustainGrowthRate_mean = upper_groups([float(x.ValuationRatios.SustainableGrowthRate) for x in initial_filter if x.ValuationRatios.SustainableGrowthRate > 0])
            #GrossMargin_mean = upper_groups([float(x.OperationRatios.GrossMargin.ThreeMonths) for x in initial_filter if x.OperationRatios.GrossMargin.ThreeMonths > 0])
            #NetProfitMargin_mean = upper_groups([float(x.OperationRatios.NormalizedNetProfitMargin.ThreeMonths) for x in initial_filter if x.OperationRatios.NormalizedNetProfitMargin.ThreeMonths > 0])
            FreeCashFlow_mean = upper_groups([float(x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths) for x in initial_filter if x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > 0])
            FirstYREPSGrowth_mean = upper_groups([float(x.ValuationRatios.FirstYearEstimatedEPSGrowth) for x in initial_filter if x.ValuationRatios.FirstYearEstimatedEPSGrowth > 0])                    
            
            second_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PERatio > PERatio_mean, reverse = True)
            third_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PEGRatio > PEGRatio_mean, reverse = True)
            #fourth_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.SustainableGrowthRate > SustainGrowthRate_mean, reverse = True)
            #fifth_filter = sorted(initial_filter, key = lambda x: x.OperationRatios.GrossMargin.ThreeMonths > NetProfitMargin_mean, reverse = True)
            #six_filter = sorted(initial_filter, key = lambda x: x.OperationRatios.NormalizedNetProfitMargin.ThreeMonths > NetProfitMargin_mean, reverse = True)
            seventh_filter = sorted(initial_filter, key = lambda x: x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > FreeCashFlow_mean, reverse = True)
            eigth_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.FirstYearEstimatedEPSGrowth > FirstYREPSGrowth_mean, reverse = True)

            filtered_fine = list(set.intersection(*map(set, [initial_filter, second_filter, third_filter, 
                                                            # fourth_filter, fifth_filter, six_filter, 
                                                            seventh_filter, eigth_filter])))   
            
            count = len(filtered_fine)
            if count == 0: return []
            
            myDict = dict()
            percent = float(self.NumberOfSymbolsFine / count)
            
            # select stocks with top dollar volume in every single sector
            for key in ["N"]:
                value = [x for x in filtered_fine if x.CompanyReference.IndustryTemplateCode == key]
                value = sorted(value, key=lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True)
                myDict[key] = value[:ceil(len(value) * percent)]
                
            topFine = list(chain.from_iterable(myDict.values()))[:self.NumberOfSymbolsFine]
            self.universe = [f.Symbol for f in topFine[:int(len(topFine) * 0.5)]] # [:int(len(topFine) * 0.33)]
            
            self.rebalance_flag = 0
            self.first_month_trade_flag = 0
            self.trade_flag = 1
            
        return self.universe

    def OnData(self, data):
        pass
            
    def short(self):
        if self.universe is None: return
        SPY_Velocity = 0
        self.long_leverage = 0
        self.short_leverage = 0
        # request the history of benchmark
        pri = self.History(["SPY"], 75, Resolution.Daily)
        pos_one = (pri.loc["SPY"]['close'][-1])
        pos_six = (pri.loc["SPY"]['close'][-75:].mean())
        # calculate velocity of the benchmark 
        velocity_stop = (pos_one - pos_six)/100.0
        SPY_Velocity = velocity_stop
        if SPY_Velocity > 0.0:
            self.long_leverage = 1.8     
            self.short_leverage = -0.0
        else:
            self.long_leverage = 1.1     
            self.short_leverage = -0.7
        if (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'No'): return
        for symbol in self.shorts:
            if len(self.shorts) + self.existing_shorts == 0: return
            self.AddEquity(symbol, Resolution.Daily)
            self.SetHoldings(symbol, 0.8*(self.short_leverage/(len(self.shorts) + self.existing_shorts)))                                
 
    def long(self):
        if self.universe is None: return
        if (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'No'): return
        for symbol in self.longs:
            if len(self.longs) + self.existing_longs == 0: return
            self.AddEquity(symbol, Resolution.Daily)
            self.SetHoldings(symbol, 1*(self.long_leverage/(len(self.longs) + self.existing_longs)))
       
    def get_prices(self):
        if self.universe is None: return
        # Get the last 30 days of prices for every stock in our universe
        prices = {}
        hist = self.History(self.universe, 30, Resolution.Daily)
        for i in self.universe:
            try:
                if str(i) in hist.index.levels[0]:
                    if self.technical_setup(i):
                        prices[i.Value] = hist.loc[str(i)]['close']
            except:
                pass
        
        if len(prices.keys()) <= 0: return
        df_prices = pd.DataFrame(prices, columns = prices.keys())
        # calculate the daily log return
        daily_rets = np.log(df_prices/df_prices.shift(1))
        # calculate the latest return but skip the most recent price
        rets = (df_prices.iloc[-2] - df_prices.iloc[0]) / df_prices.iloc[0]
        # standard deviation of the daily return
        stdevs = daily_rets.std(axis = 0)
        try:
            self.ret_qt = pd.qcut(rets, 5, labels=False) + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False) + 1
        except:
            self.ret_qt = pd.qcut(rets, 5, labels=False, duplicates='drop') + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False, duplicates='drop') + 1
        self.longs = list((self.ret_qt[self.ret_qt == 1].index) & (self.stdev_qt[self.stdev_qt < 3].index))
        self.shorts = list((self.ret_qt[self.ret_qt == self.nq].index) & (self.stdev_qt[self.stdev_qt < 3].index))
 
    def daily_rebalance(self):
        # rebalance the position in portfolio every day           
        if self.universe is None: return
        if self.longs is None: return
        if self.shorts is None: return
        self.existing_longs = 0
        self.existing_shorts = 0
        
        if (self.SPY_avg_delta <= - 5.5 and self.SPY_vix_data == 'No') or (self.SPY_mom < 0.0):
            for symbol in self.Portfolio.Invested:
                self.Liquidate(symbol)
            
        elif (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes'):
            self.monthly_rebalance
            self.daily_rebalance

        elif (self.SPY_avg_delta > -5.5) or (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes') or (self.SPY_mom >= 0.25):
            
            for symbol in self.Portfolio.Keys:
                    
                if (symbol.Value != 'SPY') and (symbol.Value in self.ret_qt.index) and (self.Portfolio[symbol].IsLong):
                    current_quantile = self.ret_qt.loc[symbol.Value]
                    
                    avg_delta = DeltaModel(self.History(symbol, 25, Resolution.Daily), symbol).run()
                    vix_data = VixFix(self.History(symbol, 50, Resolution.Daily), symbol).run()
                    
                    if avg_delta > -5.5 or (avg_delta <= -5.5 and vix_data == 'Yes'):

                        # create a 20 day exponential moving average
                        self.fast = self.EMA(symbol, 20, Resolution.Daily).Current.Value
                        # create a 50 day simple moving average
                        self.slow = self.EMA(symbol, 50, Resolution.Daily).Current.Value
                        # create a 200 day simple moving average
                        self.baseline = self.SMA(symbol, 200, Resolution.Daily).Current.Value
                        
                        if (self.fast >= self.slow > self.baseline):
                            if self.ttm_squeeze(symbol) or (self.ema_squeeze(symbol) >= 4) or (self.go_time_indicators(symbol) >= 3):
                                self.TradeOptions(symbol)
                                self.MarketOrder(symbol, 100)
                                self.update_ticket(symbol)
                            elif self.ttm_squeeze(symbol) or (self.ema_squeeze(symbol) >= 3) or (self.go_time_indicators(symbol) >= 2):
                                if self.Portfolio[symbol].Quantity > 0:
                                    if (current_quantile == 1) and (symbol not in self.longs):
                                        self.existing_longs += 2
                                    elif (current_quantile > 1) and (symbol not in self.shorts):
                                        self.Liquidate(symbol)
                                        self.longs.remove(symbol)
                                        self.shorts.append(symbol)
                                elif self.Portfolio[symbol].Quantity < 0:
                                    if (current_quantile == self.nq) and (symbol not in self.shorts):
                                        self.existing_shorts += 1
                                    elif (current_quantile < self.nq) and (symbol not in self.longs):
                                        self.Liquidate(symbol)
                    
                    elif avg_delta <= -5.5:
                        try:
                            self.Liquidate(symbol)
                            self.universe.remove(symbol)
                            self.longs.remove(symbol)
                            self.shorts.remove(symbol)
                        except:
                            pass
                        
        self.AddEquity('SPY', Resolution.Daily)
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        self.take_profit()
    
    def technical_setup(self, i):
        x = re.sub('[(){}<>| ]', '', str(i))
        self.AddEquity(x, Resolution.Daily)
        self.History(self.Symbol(x), 200, Resolution.Daily)
        if self.EMA(x, 50, Resolution.Daily).Current.Value >= self.SMA(x, 200, Resolution.Daily).Current.Value:
            if self.RSI(x, 14, Resolution.Daily).Current.Value < 30:
                return x
    
    def ttm_squeeze(self, symbol):
        self.AddEquity(symbol, Resolution.Daily)
        #TTM Squeeze
        sma_twenty = self.SMA(symbol, 20, Resolution.Daily).Current.Value
        std = self.STD(symbol, 20, Resolution.Daily).Current.Value
        lower_band = sma_twenty - 2*std
        upper_band = sma_twenty + 2*std
        atr = self.ATR(symbol, 20, Resolution.Daily).Current.Value
        lower_keltner = sma_twenty - 2*atr
        upper_keltner = sma_twenty + 2*atr
        return lower_band > lower_keltner and upper_band < upper_keltner
    
    def ema_squeeze(self, symbol):
        self.AddEquity(symbol, Resolution.Daily)
        # create a 8 day exponential moving average
        fastest = self.EMA(symbol, 8, Resolution.Daily).Current.Value
        # create a 14 day exponential moving average
        faster = self.EMA(symbol, 14, Resolution.Daily).Current.Value   
        # create a 21 day exponential moving average
        fast = self.EMA(symbol, 21, Resolution.Daily).Current.Value
        # create a 34 day exponential moving average
        slow = self.EMA(symbol, 34, Resolution.Daily).Current.Value
        # create a 50 day exponential moving average
        slower = self.EMA(symbol, 55, Resolution.Daily).Current.Value
        # creat a 200 day simple moving average
        slowest = self.SMA(symbol, 200, Resolution.Daily).Current.Value
        # define a small tolerance on our checks to avoid bouncing
        tolerance = 0.025
        
        condition_one = ((fastest * (1-tolerance)) >= (faster * (1+tolerance)))
        condition_two = ((faster * (1-tolerance)) >= (fast * (1+tolerance)))
        condition_three = ((fast * (1-tolerance)) >= (slow * (1+tolerance)))
        condition_four = ((slow * (1-tolerance)) >= (slower * (1+tolerance)))
        condition_five = (slower > slowest)
        conditions = [condition_one, condition_two, condition_three, condition_four, condition_five]
        
        count = 0
        for condition in conditions:
            if condition is True:
                count += 1
        return count
    
    def go_time_indicators(self, symbol):
        self.AddEquity(symbol, Resolution.Daily)
        # Momentum & Volume & Trend
        # RSI <= 30 = buy
        rsi = self.RSI(symbol, 14, MovingAverageType.Simple, Resolution.Daily).Current.Value
        # William's %R <= -20 = buy
        wilr = self.WILR(symbol, 14, Resolution.Daily).Current.Value
        # MACD current < signal = buy
        macd = self.MACD(symbol, 12, 26, 9, Resolution.Daily)
        macd_current = macd.Current.Value
        macd_signal = macd.Signal.Current.Value
        macd_fast = macd.Fast.Current.Value
        macd_signal_delta = (macd_current - macd_signal)/(macd_fast)
        tolerance = 0.0025
        
        condition_one = (rsi <= 30)
        condition_two = (wilr <= -20)
        condition_three = (macd_signal_delta > tolerance)
        conditions = [condition_one, condition_two, condition_three]
        count = 0
        for condition in conditions:
            if condition is True:
                count += 1
        return count
                
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Invalid:
            self.Log(str(orderEvent))
            
        if orderEvent.Status == OrderStatus.Filled: 
            order = self.Transactions.GetOrderById(orderEvent.OrderId)
            if order.Tag == 'pt':  # If hit profit target, update stop order quantity
                updateSettings = UpdateOrderFields()
                updateSettings.Quantity = self.stops[orderEvent.Symbol].Quantity - orderEvent.Quantity
                self.stops[orderEvent.Symbol].Update(updateSettings)
    
            elif order.Tag == 'sl': # If hit stop loss, cancel profit target orders
                self.Transactions.CancelOpenOrders(orderEvent.Symbol, "Hit stop price")
    
    def take_profit(self):
        if self.Portfolio.TotalUnrealizedProfit > (0.2 * self.Portfolio.TotalPortfolioValue):
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            stocks_invested_by_profit = sorted(stocks_invested, key=lambda x: self.Portfolio[x].UnrealizedProfit, reverse=True)
            for stock in stocks_invested_by_profit:
                holding = self.Portfolio[stock].Quantity
                avg_price = self.Portfolio[stock].AveragePrice
                holdings_profit = self.Portfolio[stock].UnrealizedProfit
                holdings_cost = avg_price * holding
                if stock in self.shorts:
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -holding)
                elif stock in self.longs:
                    half_holding = int(holding/2.0)
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -half_holding)
        elif self.SPY_mom <= 0.0:
            for stock in self.Portfolio:
                try:
                    if stock.Value.Invested:
                        self.Liquidate(stock)
                except:
                    pass
        try:
            if self.longs and self.shorts:
                stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
                # liquidate stocks not in the trading list
                for stock in stocks_invested:
                    holding = self.Portfolio[stock].Quantity
                    avg_price = self.Portfolio[stock].AveragePrice
                    holdings_profit = self.Portfolio[stock].UnrealizedProfit
                    holdings_cost = avg_price * holding
                    if holdings_profit > holdings_cost * 1.5:
                        self.Liquidate(stock)
        except:
            pass
    
    def update_ticket(self, stock):
        """
        Uses mean reversion to update stop loss and limit orders.
        """
        self.mean = self.EMA(stock, 8, Resolution.Daily)
        self.atr = self.ATR(stock, 8, Resolution.Daily)
        # # Mean reversion when price is too low
        if self.Securities[stock].Price > (self.Portfolio[stock].AveragePrice * 0.95):
            limitTicket = self.LimitOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price + (0.5 * self.atr.Current.Value))
            stopTicket = self.StopMarketOrder(stock, -self.Portfolio[stock].Quantity, (self.Portfolio[stock].AveragePrice * 0.90))
    
        # Mean reversion when price is too high
        if self.Securities[stock].Close > self.mean.Current.Value + (1.5 * self.atr.Current.Value):
            limitTicket = self.LimitOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price + (self.atr.Current.Value))
            stopTicket = self.StopMarketOrder(stock, -self.Portfolio[stock].Quantity, (self.Securities[stock].Price * 0.95))
            
    def TradeOptions(self, symbol):
        equity = self.AddEquity(symbol, Resolution.Minute)
        option = self.AddOption(symbol, Resolution.Minute)
        self.symbol = option.Symbol
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        option.SetFilter(-3, +3, timedelta(0), timedelta(60))
        # use the underlying equity as the benchmark
        self.SetBenchmark(equity.Symbol)
        self.call = symbol # Initialize the call contract
        
        if slice.OptionChains.Count == 0: return   
        for i in slice.OptionChains:
            if i.Key != self.symbol: continue
            chain = i.Value
            call = [x for x in chain if x.Right == 0] # filter the call options contracts
            # sorted the contracts according to their expiration dates and choose the ATM options
            contracts = sorted(sorted(call, key = lambda x: x.Expiry, reverse=True), 
                                            key = lambda x: abs(chain.Underlying.Price - x.Strike))
    
            if len(contracts) == 0: return    
            contract = contracts[0] 
            self.call = contract.Symbol
            
            if self.Securities[self.call].Price < (0.01 * self.Portfolio.TotalPortfolioValue):
                num_contracts = int((self.Portfolio.TotalPortfolioValue * 0.01)/self.Securities[self.call].Price)
                
            #if num_contracts > 0:
            self.Sell(symbol, num_contracts) # short the call options
            if self.Portfolio[symbol].Quantity == 0:
                self.Buy(symbol, 100)     # buy 100 the underlying stock
                self.Log("The stock price at time 0 S(0): {}".format(self.Securities[symbol].Price)) 
                
    def MarketOpen(self):
        return self.Time.hour != 0 and self.Time.minute == 1
from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Data.UniverseSelection import *
import math
import numpy as np
import pandas as pd
import scipy as sp
from collections import deque
from datetime import timedelta
from clr import AddReference

class SelectionData(object):
    def __init__(self, symbol, period):
        self.Symbol = symbol
        self.Volume = 0
        self.Volume_Ratio = 0
        self.DollarVolume = 0
        self.Fast_Vol_Ratio = 0
        self.Med_Vol_Ratio = 0
        self.Slow_Vol_Ratio = 0
        self.Sma = SimpleMovingAverage(period)
        self.Slow = SimpleMovingAverage(100)
        self.Med = SimpleMovingAverage(50)
        self.Fast = SimpleMovingAverage(20)

    def update(self, time, Price, Volume, DollarVolume):
        self.Volume = Volume
        self.DollarVolume = DollarVolume
        self.Price = Price
        if self.Sma.Update(time,Volume):
            # get ratio of this volume bar vs previous 10 before it.
            self.Volume_Ratio = Volume / self.Sma.Current.Value
        if self.Fast.Update(time,Volume):
            self.Fast_Vol_Ratio = Volume / self.Fast.Current.Value
        if self.Med.Update(time,Volume):
            self.Med_Vol_Ratio = Volume / self.Med.Current.Value
        if self.Slow.Update(time,Volume):
            self.Slow_Vol_Ratio = Volume / self.Slow.Current.Value
            
class SymbolData:
  def __init__(self, symbol, lookback):
      self.Symbol = symbol
      self.ROC = RateOfChange(lookback)
      self.Volume = None
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel, NullPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Risk import MaximumDrawdownPercentPortfolio, MaximumUnrealizedProfitPercentPerSecurity, MaximumDrawdownPercentPerSecurity
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

from datetime import datetime, timedelta
import pandas as pd
import numpy as np
import re
from math import ceil
from itertools import chain
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

from DeltaModel import DeltaModel
from VixFix import VixFix
from MyAlphaModel import MyAlphaModel, SymbolData
from UniverseSelectionHelperFunctions import SelectionData
from CompositeTradeSignals import CompositeTradeSignals
from SequoiaAlphaModel import SequoiaAlphaModel
from IchimokuCloudCrossOverAlphaModel import IchimokuCloudCrossOverAlphaModel

from trading_algorithm import TradingAlgorithm_main

class EnhancedShortTermMeanReversionAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2010, 1, 1)  #Set Start Date
        self.SetEndDate(2020, 10, 15)   #Set End Date       
        self.SetCash(10000)            #Set Strategy Cash
        self.SetWarmUp(timedelta(minutes=1))   # Set Algorithm to 21 days
        
        #self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        # rebalance the universe selection once a month
        self.rebalance_flag = 0
        # make sure to run the universe selection at the start of the algorithm even it's not the month start
        self.first_month_trade_flag = 1
        self.trade_flag = 0  
        # Number of quantiles for sorting returns for mean reversion
        self.nq = 5
        # Number of quantiles for sorting volatility over five-day mean reversion period
        self.nq_vol = 3
        # the symbol list after the coarse and fine universe selection
        self.universe = None
        self.NumberOfSymbolsFine = 500
        self.NumberOfSymbolsCoarse = 150
        self.dollarVolumeBySymbol = {}
        
         # setup state storage in initialize method
        self.stateData = { }
        
        # Benchmark
        self.AddEquity("SPY", Resolution.Daily)
        self.SetBenchmark("SPY")
        
        # SPY HIGH
        self.correction_flag = 0
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.At(0, 0), Action(self.monthly_rebalance))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 303), Action(self.get_prices))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 302), Action(self.daily_rebalance))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 301), Action(self.short))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 300), Action(self.long))
    
    def monthly_rebalance(self):
        # rebalance the universe every month
        self.rebalance_flag = 1
 
    def CoarseSelectionFunction(self, coarse):
        if self.rebalance_flag or self.first_month_trade_flag:
            # drop stocks which have no fundamental data or have too low prices
            selected = [x for x in coarse if (x.HasFundamentalData) and (20 <= float(x.Price) <= 300) and (float(x.Volume) >= 2000000)]
            # rank the stocks by dollar volume and choose the top 150
            filtered = sorted(selected, key=lambda x: x.DollarVolume > 4e7, reverse=True)[:self.NumberOfSymbolsCoarse]
            
            self.dollarVolumeBySymbol = { i.Symbol: i.DollarVolume for i in filtered}

            return [x.Symbol for x in filtered] # [:self.NumberOfSymbolsCoarse]
        else:
            return self.universe

    def FineSelectionFunction(self, fine):

        if self.rebalance_flag or self.first_month_trade_flag:
            # filter the stocks which have positive EV To EBITDA
            filtered_fine = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
                                    and x.ValuationRatios.PriceChange1M > 0   
                                    and x.CompanyReference.CountryId == "USA"
                                    and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
                                    and x.CompanyReference.IndustryTemplateCode == "N"
                                    and x.ValuationRatios.PERatio > 20
                                    and x.ValuationRatios.FirstYearEstimatedEPSGrowth > 0.2
                                    and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
                                    and (x.Time - x.SecurityReference.IPODate).days > 180
                                    and x.ValuationRatios.PEGRatio > 2
                                    and x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > 10]
                                    
            if len(filtered_fine) <= 0:
                initial_filter = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
                                    and x.ValuationRatios.PriceChange1M > 0
                                    and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
                                    and (x.Time - x.SecurityReference.IPODate).days > 180 and x.CompanyReference.CountryId == "USA"
                                    and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
                                    and x.CompanyReference.IndustryTemplateCode == "N"
                                    and x.AssetClassification.MorningstarSectorCode in [MorningstarSectorCode.FinancialServices,
                                    MorningstarSectorCode.Technology, MorningstarSectorCode.Industrials, MorningstarSectorCode.CommunicationServices,
                                    MorningstarSectorCode.ConsumerCyclical, MorningstarSectorCode.ConsumerDefensive, MorningstarSectorCode.Healthcare,
                                    MorningstarSectorCode.Utilities]]
                                    
                                    
                second_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PERatio > 5, reverse = True)[:int(len(initial_filter)/3)]
                third_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PEGRatio > 0.5, reverse = True)[:int(len(initial_filter)/2.5)]
                fourth_filter = sorted(initial_filter, key = lambda x: x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > 5, reverse = True)[:int(len(initial_filter)/2.5)]
                fifth_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.FirstYearEstimatedEPSGrowth > 0.1, reverse = True)[:int(len(initial_filter)/2.5)]
                
                filtered_fine = list()
                for symbol in initial_filter:
                    if symbol in second_filter:
                        if symbol in third_filter:
                            if symbol in fourth_filter:
                                if symbol in fifth_filter:
                                    filtered_fine.append(symbol)
                
            count = len(filtered_fine)
            if count == 0: return []
            
            myDict = dict()
            percent = float(self.NumberOfSymbolsFine / count)
            
            # select stocks with top dollar volume in every single sector
            for key in ["N"]:
                value = [x for x in filtered_fine if x.CompanyReference.IndustryTemplateCode == key]
                value = sorted(value, key=lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True)
                myDict[key] = value[:ceil(len(value) * percent)]
                
            topFine = list(chain.from_iterable(myDict.values()))[:self.NumberOfSymbolsFine]
            self.universe = [f.Symbol for f in topFine]
            
            self.rebalance_flag = 0
            self.first_month_trade_flag = 0
            self.trade_flag = 1
            
        return self.universe

    def OnData(self, data):
        pass
    
    def short(self):
        if self.universe is None: return
        SPY_Velocity = 0
        self.long_leverage = 0
        self.short_leverage = 0
        # request the history of benchmark
        pri = self.History(["SPY"], 75, Resolution.Daily)
        pos_one = (pri.loc["SPY"]['close'][-1])
        pos_six = (pri.loc["SPY"]['close'][-75:].mean())
        # calculate velocity of the benchmark 
        velocity_stop = (pos_one - pos_six)/100.0
        SPY_Velocity = velocity_stop
        if SPY_Velocity > 0.0:
            self.long_leverage = 1.8     
            self.short_leverage = -0.0
        else:
            self.long_leverage = 1.1     
            self.short_leverage = -0.7    
        for symbol in self.shorts:
            if len(self.shorts) + self.existing_shorts == 0: return
            self.AddEquity(symbol, Resolution.Daily)
            self.SetHoldings(symbol, 0.8*(self.short_leverage/(len(self.shorts) + self.existing_shorts)))                                
 
    def long(self):
        if self.universe is None: return
        for symbol in self.longs:
            if len(self.longs) + self.existing_longs == 0: return
            self.AddEquity(symbol, Resolution.Daily)
            self.SetHoldings(symbol, (self.long_leverage/(len(self.longs) + self.existing_longs)))
       
    def get_prices(self):
        if self.universe is None: return
        # Get the last 25 days of prices for every stock in our universe
        prices = {}
        hist = self.History(self.universe, 25, Resolution.Daily)
        for i in self.universe:
            if str(i) in hist.index.levels[0]:
                if self.technical_setup(i):
                    prices[i.Value] = hist.loc[str(i)]['close']
        df_prices = pd.DataFrame(prices, columns = prices.keys())
        # calculate the daily log return
        daily_rets = np.log(df_prices/df_prices.shift(1))
        # calculate the latest return but skip the most recent price
        rets = (df_prices.iloc[-2] - df_prices.iloc[0]) / df_prices.iloc[0]
        # standard deviation of the daily return
        stdevs = daily_rets.std(axis = 0)
        try:
            self.ret_qt = pd.qcut(rets, 5, labels=False) + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False) + 1
        except:
            self.ret_qt = pd.qcut(rets, 5, labels=False, duplicates='drop') + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False, duplicates='drop') + 1
        self.longs = list((self.ret_qt[self.ret_qt == 1].index) & (self.stdev_qt[self.stdev_qt < 3].index))
        self.shorts = list((self.ret_qt[self.ret_qt == self.nq].index) & (self.stdev_qt[self.stdev_qt < 3].index))
 
    def daily_rebalance(self):
        # rebalance the position in portfolio every day           
        if self.universe is None: return
        if self.longs is None: return
        if self.shorts is None: return
        self.existing_longs = 0
        self.existing_shorts = 0
        
        if (self.SPY_avg_delta <= - 5.5 and self.SPY_vix_data == 'No') or (self.SPY_mom < 0.0):
            if self.correction_flag == 0:
                for symbol in self.Portfolio.Invested:
                    self.Liquidate(symbol)
                self.correction_flag = 1
            elif self.correction_flag == 1:
                return
            
        elif (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes'):
            if self.correction_flag == 1:
                self.monthly_rebalance
                self.daily_rebalance
                self.correction_flag = 0
                return
            elif self.correction_flag == 0:
                pass

        elif (self.SPY_avg_delta > -5.5) or (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes') or (self.SPY_mom >= 0.0):
            
            for symbol in self.Portfolio.Keys:
                    
                if (symbol.Value != 'SPY') and (symbol.Value in self.ret_qt.index) and (self.Portfolio[symbol].IsLong):
                    current_quantile = self.ret_qt.loc[symbol.Value]
                    
                    avg_delta = DeltaModel(self.History(symbol, 25, Resolution.Daily), symbol).run()
                    vix_data = VixFix(self.History(symbol, 50, Resolution.Daily), symbol).run()
                    
                    if avg_delta > -5.5 or (avg_delta <= -5.5 and vix_data == 'Yes'):
                        
                        def ttm_squeeze(symbol):
                            #TTM Squeeze
                            sma_twenty = self.SMA(symbol, 20, Resolution.Daily).Current.Value
                            std = self.STD(symbol, 20, Resolution.Daily).Current.Value
                            lower_band = sma_twenty - 2*std
                            upper_band = sma_twenty + 2*std
                            atr = self.ATR(symbol, 20, Resolution.Daily).Current.Value
                            lower_keltner = sma_twenty - 2*atr
                            upper_keltner = sma_twenty + 2*atr
                            return lower_band > lower_keltner and upper_band < upper_keltner
                        
                        def ema_squeeze(symbol):
                            # create a 8 day exponential moving average
                            fastest = self.EMA(symbol, 8, Resolution.Daily).Current.Value
                            # create a 14 day exponential moving average
                            faster = self.EMA(symbol, 14, Resolution.Daily).Current.Value   
                            # create a 21 day exponential moving average
                            fast = self.EMA(symbol, 21, Resolution.Daily).Current.Value
                            # create a 34 day exponential moving average
                            slow = self.EMA(symbol, 34, Resolution.Daily).Current.Value
                            # create a 50 day exponential moving average
                            slower = self.EMA(symbol, 55, Resolution.Daily).Current.Value
                            # creat a 200 day simple moving average
                            slowest = self.SMA(symbol, 200, Resolution.Daily).Current.Value
                            # define a small tolerance on our checks to avoid bouncing
                            tolerance = 0.025
                            
                            condition_one = ((fastest * (1-tolerance)) >= (faster * (1+tolerance)))
                            condition_two = ((faster * (1-tolerance)) >= (fast * (1+tolerance)))
                            condition_three = ((fast * (1-tolerance)) >= (slow * (1+tolerance)))
                            condition_four = ((slow * (1-tolerance)) >= (slower * (1+tolerance)))
                            condition_five = (slower > slowest)
                            conditions = [condition_one, condition_two, condition_three, condition_four]
                            
                            count = 0
                            for condition in conditions:
                                if condition is True:
                                    count += 1
                            if condition_five is True:
                                return count
                            
                        # create a 50 day exponential moving average
                        self.slow = self.EMA(symbol, 21, Resolution.Daily).Current.Value
                        # creat a 200 day simple moving average
                        self.slower = self.SMA(symbol, 55, Resolution.Daily).Current.Value
                        
                        if (self.slow > self.slower):
                            if ttm_squeeze(symbol) or (ema_squeeze(symbol) >= 3):
                                if self.Portfolio[symbol].Quantity > 0:
                                    if (current_quantile == 1) and (symbol not in self.longs):
                                        self.existing_longs += 2
                                        self.update_ticket(symbol)
                                    elif (current_quantile > 1) and (symbol not in self.shorts):
                                        #self.Liquidate(symbol)
                                        self.longs.remove(symbol)
                                        self.shorts.append(symbol)
                                elif self.Portfolio[symbol].Quantity < 0:
                                    if (current_quantile == self.nq) and (symbol not in self.shorts):
                                        self.existing_shorts += 1
                                        self.update_ticket(symbol)
                                    elif (current_quantile < self.nq) and (symbol not in self.longs):
                                        self.Liquidate(symbol)
                    
                    elif avg_delta <= -5.5:
                        try:
                            self.Liquidate(symbol)
                            self.universe.remove(symbol)
                            self.longs.remove(symbol)
                            self.shorts.remove(symbol)
                        except:
                            pass
                        
        self.AddEquity('SPY', Resolution.Daily)
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        self.take_profit()
                        
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Invalid:
            self.Log(str(orderEvent))
            
        if orderEvent.Status == OrderStatus.Filled: 
            order = self.Transactions.GetOrderById(orderEvent.OrderId)
            if order.Tag == 'pt':  # If hit profit target, update stop order quantity
                updateSettings = UpdateOrderFields()
                updateSettings.Quantity = self.stops[orderEvent.Symbol].Quantity - orderEvent.Quantity
                self.stops[orderEvent.Symbol].Update(updateSettings)
    
            elif order.Tag == 'sl': # If hit stop loss, cancel profit target orders
                self.Transactions.CancelOpenOrders(orderEvent.Symbol, "Hit stop price")
    
    def technical_setup(self, i):
        x = re.sub('[(){}<>| ]', '', str(i))
        self.AddEquity(x, Resolution.Daily)
        self.History(self.Symbol(x), 200, Resolution.Daily)
        if self.EMA(x, 50, Resolution.Daily).Current.Value >= self.EMA(x, 200, Resolution.Daily).Current.Value:
            if self.RSI(x, 14, Resolution.Daily).Current.Value < 30:
                return x
    
    def take_profit(self):
        if self.Portfolio.TotalUnrealizedProfit > (0.2 * self.Portfolio.TotalPortfolioValue):
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            stocks_invested_by_profit = sorted(stocks_invested, key=lambda x: self.Portfolio[x].UnrealizedProfit, reverse=True)
            for stock in stocks_invested_by_profit:
                holding = self.Portfolio[stock].Quantity
                avg_price = self.Portfolio[stock].AveragePrice
                holdings_profit = self.Portfolio[stock].UnrealizedProfit
                holdings_cost = avg_price * holding
                if stock in self.shorts:
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -holding)
                elif stock in self.longs:
                    half_holding = int(holding/2.0)
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -half_holding)
        elif self.longs and self.shorts:
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            # liquidate stocks not in the trading list
            for stock in stocks_invested:
                holding = self.Portfolio[stock].Quantity
                avg_price = self.Portfolio[stock].AveragePrice
                holdings_profit = self.Portfolio[stock].UnrealizedProfit
                holdings_cost = avg_price * holding
                if holdings_profit > holdings_cost * 1.5:
                        self.Liquidate(stock)
        elif self.SPY_mom <= 0.0:
            for stock in self.Portfolio:
                try:
                    if stock.Value.Invested:
                        self.Liquidate(stock)
                except:
                    pass
    
    def update_ticket(self, stock):
        """
        Uses mean reversion to update stop loss and limit orders.
        """
        self.mean = self.EMA(stock, 20, Resolution.Daily)
        self.atr = self.ATR(stock, 20, Resolution.Daily)
        # Mean reversion when price is too low
        if self.Securities[stock].Price < self.mean.Current.Value - 2.0 * self.atr.Current.Value:
            holding = self.Portfolio[stock].Quantity
            marketTicket = self.MarketOrder(stock, quantity)
            limitTicket = self.LimitOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            stopTicket = self.StopMarketOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price - self.atr.Current.Value)
    
        # Mean reversion when price is too high
        if self.Securities[stock].Price > self.mean.Current.Value + 2.0 * self.atr.Current.Value:
            holding = self.Portfolio[stock].Quantity
            marketTicket = self.MarketOrder(stock, -holding)
            limitTicket = self.LimitOrder(stock, self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            stopTicket = self.StopMarketOrder(stock, self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            
            
    def TradeOptions(self, symbol):
        equity = self.AddEquity(symbol, Resolution.Minute)
        option = self.AddOption(symbol, Resolution.Minute)
        self.symbol = option.Symbol
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        option.SetFilter(-3, +3, timedelta(0), timedelta(60))
        # use the underlying equity as the benchmark
        self.SetBenchmark(equity.Symbol)
        self.call = symbol # Initialize the call contract
        
        if slice.OptionChains.Count == 0: return   
        for i in slice.OptionChains:
            if i.Key != self.symbol: continue
            chain = i.Value
            call = [x for x in chain if x.Right == 0] # filter the call options contracts
            # sorted the contracts according to their expiration dates and choose the ATM options
            contracts = sorted(sorted(call, key = lambda x: x.Expiry, reverse=True), 
                                            key = lambda x: abs(chain.Underlying.Price - x.Strike))
    
            if len(contracts) == 0: return    
            contract = contracts[0] 
            self.call = contract.Symbol
            self.Sell(symbol, 1) # short the call options
            if self.Portfolio[symbol].Quantity == 0:
                self.Buy(symbol, 100)     # buy 100 the underlying stock
                self.Log("The stock price at time 0 S(0): {}".format(self.Securities[symbol].Price)) 
                
    def MarketOpen(self):
        return self.Time.hour != 0 and self.Time.minute == 1
import pandas as pd
import numpy as np
from System import *
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from System.Collections.Generic import List

class CompositeTradeSignals:
    """
    Bullish Count > 7. Max 14
    Bearish Count < -10. Max -21
    """
    def __init__(self, symbol, trade, *args, **kwargs):
        super(CompositeTradeSignals, self).__init__()
        self.symbol = symbol
        self.trade = trade
        self.count = 0
        
        def StochRSI(self, period):
            RSI = self.RSI(self.symbol, period, Resolution.Daily).Current.Value
            HH_RSI = IndicatorExtensions.MAX(RSI, period).Current.Value
            LL_RSI = IndicatorExtensions.MIN(RSI, period).Current.Value
            
            StochRSI = (RSI - LL_RSI) / (HH_RSI - LL_RSI).Current.Value
            StochRSI_Avg = IndicatorExtensions.SMA(StochRSI, period).Current.Value
            
            return StochRSI, StochRSI_Avg
      
    
        if trade == 'Buy':
            # EMA Cross
            fastest = self.EMA(self.symbol, 8, Resolution.Daily).Current.Value
            fast = self.EMA(self.symbol, 14, Resolution.Daily).Current.Value
            slow = self.EMA(self.symbol, 20, Resolution.Daily).Current.Value
            if fast > slow:
                self.count += 1
            if fastest > fast:
                self.count += 1
            
            # StochRSI and RSI Crossover
            StochRSI, StochRSI_Avg = StochRSI(self.symbol, period = 14)
            if (StochRSI < 30) and (StochRSI_Avg < 30) and (StochRSI > StochRSI_Avg):
                self.count += 5
            else:
                if StochRSI < 30:
                    self.count += 1
                if StochRSI_Avg < 30:
                    self.count += 1
                if StochRSI > StochRSI_Avg:
                    self.count += 1
            
                
            # Momentum
            mom = self.MOM(self.symbol, 10, Resolution.Daily).Current.Value
            if mom > 0.0:
                self.count += 1
            
            # Ultimate Oscillator
            ultosc = self.ULTOSC(self.symbol, 7, 14, 28, Resolution.Daily).Current.Value
            if ultosc > 50:
                self.count += 1
            
            # CandlestickPatterns
            if self.CandlestickPatterns.MatHold(self.symbol) == 1:
                self.count += 1
            if self.CandlestickPatterns.UpsideGapTwoCrows(self.symbol) == 1:
                self.count += 1
                
        elif trade == 'Sell':
            # EMA Cross
            fastest = self.EMA(self.symbol, 8, Resolution.Daily).Current.Value
            fast = self.EMA(self.symbol, 14, Resolution.Daily).Current.Value
            slow = self.EMA(self.symbol, 20, Resolution.Daily).Current.Value
            if fast < slow:
                self.count -= 1
            if fastest < fast:
                self.count -= 1
            
            # RSI and RSI Crossover
            for period in [14, 21]:
                StochRSI, StochRSI_Avg = StochRSI(self.symbol, period)
                if (StochRSI > 70) and (StochRSI_Avg > 70) and (StochRSI < StochRSI_Avg):
                    self.count -= 5
                else:
                    if StochRSI > 70:
                        self.count -= 1
                    if StochRSI_Avg > 70:
                        self.count -= 1
                    if StochRSI < StochRSI_Avg:
                        self.count -= 1
            
            # Momentum
            mom = self.MOM(self.symbol, 10, Resolution.Daily).Current.Value
            if mom <= 0.0:
                self.count -= 1
            
            # Ultimate Oscillator
            ultosc = self.ULTOSC(self.symbol, 7, 14, 28, Resolution.Daily).Current.Value
            if ultosc < 50:
                self.count -= 1
            
            # CandlestickPatterns
            if self.CandlestickPatterns.TwoCrows(self.symbol)  == -1:
                self.count -= 1
            
        return self.count


class StochRSI:
    """
    Bullish Count > 4. Max 6
    Bearish Count < -5. Max -10
    """
    def __init__(self, symbol, period, *args, **kwargs):
        super(StochRSI, self).__init__()
        self.symbol = symbol

        RSI = self.RSI(self.symbol, period, Resolution.Daily).Current.Value
        HH_RSI = IndicatorExtensions.MAX(RSI, period).Current.Value
        LL_RSI = IndicatorExtensions.MIN(RSI, period).Current.Value
        
        StochRSI = (RSI - LL_RSI) / (HH_RSI - LL_RSI).Current.Value
        StochRSI_Avg = IndicatorExtensions.SMA(StochRSI, period).Current.Value
        
        return StochRSI, StochRSI_Avg
# Your New Python File
from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *
from datetime import timedelta

class MyAlphaModel(AlphaModel):
    def __init__(self):
        self.symbolData = {}
    
    def Update(self, algorithm, data):
        insights = []
        for symbol in self.symbolData:
            if symbol in data.Bars:
                self.symbolData[symbol].update(data.Time, data[symbol].Close)
                if self.symbolData[symbol].RSIcross:
                    insights.append(Insight(symbol, timedelta(1), InsightType.Price, InsightDirection.Up))
        return Insight.Group(insights)
    
    def OnSecuritiesChanged(self, algorithm, changes):
        added_symbols = [s.Symbol for s in changes.AddedSecurities]
        history = algorithm.History(added_symbols, 14, Resolution.Daily)
        for s in changes.AddedSecurities:
            self.symbolData[s.Symbol] = SymbolData(s.Symbol, history.loc[s.Symbol])
    
        for s in changes.RemovedSecurities:
            self.symbolData.pop(s.Symbol, None)
    
    
class SymbolData:
    def __init__(self, symbol, history, period):
        self.RSIcross = False
        for idx, row in history.iterrows():
            self.update(idx, row.close)
        
    def update(self, time, price):
        self.rsi.Update(time, price)
        if not self.rsi.IsReady:
            return 
        
        self.rollingRSI.Add(self.rsi.Current.Value)
        
        if not self.rollingRSI.IsReady:
            return
        
        self.RSIcross = self.rollingRSI[1] < 30 and self.rollingRSI[0] > 30
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *

class SequoiaAlphaModel(AlphaModel):
    """
    This class takes a comprehensive approach to assess whether an intrument is bullish or bearish.
    Hull_Moving_Average: Price = Close, Length = 20, Displace = 0
    Ichimoku: Tekan = 9, Kijun = 26
    Simple_Moving_Average: Length = 200, Length = 50
    Shared_Floor_Pivots: Time_Frame = Month
    RSI: Length = 10, Average_Type = Wilders
    MACDHistogram: Fast_Length = 12, Slow_Length = 26, MACD_Length = 9, Average_Type = Exponential
    
    This class emits insights to hold a long (short) position after the chikou line of a
    security's Ichimoku Cloud crosses over (under) the top (bottom) of the cloud.
    """
    symbol_data_by_symbol = {}
    
    def Update(self, algorithm, data):
        """
        Called each time our alpha model receives a new data slice.
        
        Input:
         - algorithm
            Algorithm instance running the backtest
         - data
            A data structure for all of an algorithm's data at a single time step
        
        Returns a list of Insights to the portfolio construction model.
        """
        insights = []

        for symbol, symbol_data in self.symbol_data_by_symbol.items():
            if not data.ContainsKey(symbol) or data[symbol] is None:
                continue
            
            # Update indicator with the latest TradeBar
            symbol_data.ichimoku.Update(data[symbol])
            symbol_data.hma.Update(data[symbol])
            symbol_data.twohundred_sma.Update(data[symbol])
            symbol_data.fifty_sma.Update(data[symbol])
            symbol_data.macd.Update(data[symbol])
            symbol_data.rsi.Update(data[symbol])
            
            
            # Determine insight direction
            current_location = symbol_data.get_location()
            if symbol_data.previous_location is not None: # Indicator is ready
                if symbol_data.previous_location != 1 and current_location == 1:
                    symbol_data.direction = InsightDirection.Up
                if symbol_data.previous_location != -1 and current_location == -1:
                    symbol_data.direction = InsightDirection.Down
            
            symbol_data.previous_location = current_location
            
            # Emit insight
            if symbol_data.direction:
                insight = Insight.Price(symbol, timedelta(days=1), symbol_data.direction)
                insights.append(insight)
        
        return insights

    
    def OnSecuritiesChanged(self, algorithm, changes):
        """
        Called each time our universe has changed.
        
        Input:
         - algorithm
            Algorithm instance running the backtest
         - changes
            The additions and subtractions to the algorithm's security subscriptions
        """
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            self.symbol_data_by_symbol[symbol] = SymbolData(symbol, algorithm)
        
        for security in changes.RemovedSecurities:
            self.symbol_data_by_symbol.pop(security.Symbol, None)   
        

class SymbolData:
    """
    This class is used to store information on each security in the universe. It is
    responsible for initializing and warming up the Ichimoku indicator and determining
    the position of the chikou line in respect to the cloud.
    """
    previous_location = None
    direction = None
    
    def __init__(self, symbol, algorithm):
        """
        Input:
         - symbol
            Symbol of the security
         - algorithm
            Algorithm instance running the backtest
        """
        # Create Ichimoku Indicator
        self.ichimoku = IchimokuKinkoHyo()
        # Warm up indicator
        history = algorithm.History(symbol, self.ichimoku.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.ichimoku.IsReady:
                self.previous_location = self.get_location()
            
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.ichimoku.Update(tradebar)
            
        # Create Hull Moving Average Indicator
        self.hma = self.HMA(symbol, 20, Resolution.Daily)
        # Warm up indicator
        history = algorithm.History(symbol, self.hma.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.hma.IsReady:
                self.signal = 1 if self.hma.Current.Value > row.close else 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.hma.Update(tradebar)
        
        # Create Exponential Moving Average Indicator (200 Length)
        self.twohundred_ema = self.EMA(symbol, 200, Resolution.Daily)
        # Warm up Indicator
        history = algorithm.History(symbol, self.twohundred_sma.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.twohundred_ema.IsReady:
                self.signal = 1 if self.twohundred_ema.Current.Value > row.close else 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.twohundred_ema.Update(tradebar)
            
        # Create Exponential Moving Average Indicator (50 Length)
        self.fifty_ema = self.EMA(symbol, 50, Resolution.Daily)
        # Warm up Indicator
        history = algorithm.History(symbol, self.fifty_ema.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.fifty_ema.IsReady:
                self.signal = 1 if self.fifty_ema.Current.Value > row.close else 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.fifty_ema.Update(tradebar)
        
        # Create MACD Fast_Length = 12, Slow_Length = 26, MACD_Length = 9, Average_Type = Exponential
        self.macd = self.MACD(symbol, 12, 26, 9, MovingAverageType.Exponential, Resolution.Daily)
        # Warm up Indicator
        history = algorithm.History(symbol, self.macd.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.macd.IsReady:
                tolerance = 0.0025
                signalDeltaPercent = (self.macd.Current.Value - self.macd.Signal.Current.Value)/self.macd.Fast.Current.Value
                if signalDeltaPercent > tolerance:
                    self.signal = 1 
                elif signalDeltaPercent < -tolerance:
                    self.signal = 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.macd.Update(tradebar)
            
        # Create RSI
        self.rsi = self.RSI(symbol, 14, MovingAverageType.Wilders, Resolution.Daily)
        # Warm up Indicator
        history = algorithm.History(symbol, self.rsi.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.rsi.IsReady:
                tolerance = 0.0025

                if self.Current.Value * (1 + tolerance) < 30:
                    self.signal = 1 
                elif self.Current.Value * (1 + tolerance) > 70:
                    self.signal = 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.rsi.Update(tradebar)
        
        
    def get_location(self):
        """
        Determines the location of the chikou line in respect to the cloud.
        
        Returns an integer in the interval [-1, 1], representing the location. 
        1 => Above cloud; 0 => Inside cloud; -1 => Below cloud
        """
        chikou = self.ichimoku.Chikou.Current.Value
        
        senkou_span_a = self.ichimoku.SenkouA.Current.Value
        senkou_span_b = self.ichimoku.SenkouB.Current.Value
        cloud_top = max(senkou_span_a, senkou_span_b)
        cloud_bottom = min(senkou_span_a, senkou_span_b)
        
        if chikou > cloud_top:
            return 1    # Above cloud
        if chikou < cloud_bottom:
            return -1   # Below cloud
            
        return 0        # Inside cloud
# Imports
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Jupyter")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm")

from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Data import *
from QuantConnect.Data.Custom import *
from QuantConnect.Data.Market import TradeBar, QuoteBar
from QuantConnect.Data.Consolidators import *
from QuantConnect.Jupyter import *
from QuantConnect.Indicators import *
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np


class BasicTemplateAlgorithm(QCAlgorithm):
    
    def Initialize(self):
        self.symbol = "SPY"
        self.highprice = None
        self.lowprice = None
        self.tidetrend = None
        self.wavetrend = None
        
        self.closeWindow = RollingWindow[float](4)
        
        self.SetStartDate(2018,9,1) #Set Start Date
        self.SetEndDate(datetime.now()) #Set End Date to Now
        self.SetCash(1122) #Set Strategy Cash
        
        self.AddEquity(self.symbol, Resolution.Minute).SetLeverage(50.0)
        
        # Create the rolling windows
        # Creates MACDOH indicator and add to a rolling window when it is updated
        self.macd1 = self.MACD(self.symbol, 12, 26, 9, MovingAverageType.Exponential)
        self.macd1.Updated += self.MACDOHUpdated
        self.macdoh = RollingWindow[IndicatorDataPoint](5)
        
        # Creates MACDTM indicator and add to a rolling window when it is updated
        self.macd2 = self.MACD(self.symbol, 12, 26, 9, MovingAverageType.Exponential)
        self.macd2.Updated += self.MACDTMUpdated
        self.macdtm = RollingWindow[IndicatorDataPoint](5)
        
        # Creates BB indicator and add to a rolling window when it is updated
        self.boll = self.BB(self.symbol, 20, 1, MovingAverageType.Exponential, Resolution.Minute)
        self.boll.Updated += self.BBUpdated
        self.bb = RollingWindow[IndicatorDataPoint](5)
        
        # Creates RSI indicator and add to a rolling window when it is updated
        self.strength = self.RSI(self.symbol, 14, MovingAverageType.Simple, Resolution.Minute)
        self.strength.Updated += self.RSIUpdated
        self.rsi = RollingWindow[IndicatorDataPoint](5)
        
        oneHourConsolidator = QuoteBarConsolidator(timedelta(minutes=60))
        oneHourConsolidator.DataConsolidated += self.OneHourBarHandler
        self.RegisterIndicator(self.symbol, self.macd1, oneHourConsolidator)
        self.SubscriptionManager.AddConsolidator(self.symbol, oneHourConsolidator)
        
        tenMinuteConsolidator = QuoteBarConsolidator(timedelta(minutes=10))
        tenMinuteConsolidator.DataConsolidated += self.TenMinuteBarHandler
        self.RegisterIndicator(self.symbol, self.macd2, tenMinuteConsolidator)
        self.RegisterIndicator(self.symbol, self.boll, tenMinuteConsolidator)
        self.RegisterIndicator(self.symbol, self.strength, tenMinuteConsolidator)
        self.SubscriptionManager.AddConsolidator(self.symbol, tenMinuteConsolidator)
        
#        twoMinuteConsolidator = QuoteBarConsolidator(timedelta(minutes=2))
#        twoMinuteConsolidator.DataConsolidated += self.TwoMinuteBarHandler
#        self.SubscriptionManager.AddConsolidator(self.symbol, twoMinuteConsolidator)
        
        self.SetWarmUp(120, Resolution.Minute)
    
    #Pass (cause this is only for minute data)
    def OnData(self, data):
        pass
    
    # Adds updated values to MACDOH rolling window
    def MACDOHUpdated(self, sender, updated):
        self.macdoh.Add(updated)
        
    # Adds updated values to MACDTM rolling window
    def MACDTMUpdated(self, sender, updated):
        self.macdtm.Add(updated)
    
    # Adds updated values to BB rolling window
    def BBUpdated(self, sender, updated):
        self.bb.Add(updated)
    
    # Adds updated values to RSI rolling window
    def RSIUpdated(self, sender, updated):
        self.rsi.Add(updated)
    
    def OneHourBarHandler(self, sender, consolidated):
        if not (self.macdoh.IsReady): return
        macd_hist_0 = self.macdoh[0].Current.Value - self.macdoh[0].Signal.Current.Value
        macd_hist_1 = self.macdoh[1].Current.Value - self.macdoh[1].Signal.Current.Value
        macd_hist_2 = self.macdoh[2].Current.Value - self.macdoh[2].Signal.Current.Value
        macd_hist_3 = self.macdoh[3].Current.Value - self.macdoh[3].Signal.Current.Value
        
    def TenMinuteBarHandler(self, sender, consolidated):
        self.closeWindow.Add(self.Securities[self.symbol].Close)
        
        if not (self.closeWindow.IsReady and self.macdoh.IsReady and self.macdtm.IsReady and self.bb.IsReady and self.rsi.IsReady): return
    
        price_0 = self.closeWindow[0]
        price_1 = self.closeWindow[1]
        price_2 = self.closeWindow[2]
        
        self.highprice = max(price_0, price_1, price_2)
        self.lowprice = min(price_0, price_1, price_2)
        
        currrsi = self.rsi[0].Current.Value
        currbbub = self.bb[0].UpperBand.Current.Value
        currbblb = self.bb[0].LowerBand.Current.Value
        
        macd_hist_0 = self.macdtm[0].Current.Value - self.macdtm[0].Signal.Current.Value
        macd_hist_1 = self.macdtm[1].Current.Value - self.macdtm[1].Signal.Current.Value
        macd_hist_2 = self.macdtm[2].Current.Value - self.macdtm[2].Signal.Current.Value
        macd_hist_3 = self.macdtm[3].Current.Value - self.macdtm[3].Signal.Current.Value
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
from datetime import timedelta

class BasicTemplateOptionsAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  #Set Start Date
        self.SetEndDate(2018, 10, 15)   #Set Start Date       
        self.SetCash(100000)            #Set Strategy Cash
        equity = self.AddEquity("IBM", Resolution.Minute)
        option = self.AddOption("IBM", Resolution.Minute)
        self.symbol = option.Symbol
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        # set our strike/expiry filter for this option chain
        option.SetFilter(-3, +3, timedelta(0), timedelta(30))
        # use the underlying equity as the benchmark
        self.SetBenchmark(equity.Symbol)
        self.call = "IBM" # Initialize the call contract
        
    def OnData(self,slice):
        if not self.Portfolio[self.call].Invested and self.MarketOpen():
            self.TradeOptions(slice) # sell the call option
        
        # if the option contract expires, print out the price and position information      
        if slice.Delistings.Count > 0:
            if [x.Key == self.call for x in slice.Delistings]:
                self.Log("stock IBM quantity: {0}".format(self.Portfolio["IBM"].Quantity))
                self.Log("{0} quantity: {1}".format(self.call.Value, self.Portfolio[self.call].Quantity))
                self.Log("The stock price at Expiry S(T): {}".format(self.Securities["IBM"].Price))

    def TradeOptions(self,slice):
        if slice.OptionChains.Count == 0: return   
        for i in slice.OptionChains:
            if i.Key != self.symbol: continue
            chain = i.Value
            call = [x for x in chain if x.Right == 0] # filter the call options contracts
            # sorted the contracts according to their expiration dates and choose the ATM options
            contracts = sorted(sorted(call, key = lambda x: x.Expiry, reverse=True), 
                                            key = lambda x: abs(chain.Underlying.Price - x.Strike))
    
            if len(contracts) == 0: return    
            contract = contracts[0] 
            self.call = contract.Symbol
            self.Sell(self.call, 1) # short the call options
            if self.Portfolio["IBM"].Quantity == 0:
                self.Buy("IBM",100)     # buy 100 the underlying stock
                self.Log("The stock price at time 0 S(0): {}".format(self.Securities["IBM"].Price))  
                
    def MarketOpen(self):
        return self.Time.hour != 0 and self.Time.minute == 1
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel, NullPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Risk import MaximumDrawdownPercentPortfolio, MaximumUnrealizedProfitPercentPerSecurity, MaximumDrawdownPercentPerSecurity
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

from datetime import datetime, timedelta
import pandas as pd
import numpy as np
import re
from math import ceil
from itertools import chain
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

from DeltaModel import DeltaModel
from VixFix import VixFix
from MyAlphaModel import MyAlphaModel, SymbolData
from UniverseSelectionHelperFunctions import SelectionData
from CompositeTradeSignals import CompositeTradeSignals
from SequoiaAlphaModel import SequoiaAlphaModel
from IchimokuCloudCrossOverAlphaModel import IchimokuCloudCrossOverAlphaModel

from trading_algorithm import TradingAlgorithm_main

class EnhancedShortTermMeanReversionAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2010, 1, 1)  #Set Start Date
        self.SetCash(10000)            #Set Strategy Cash
        self.SetWarmUp(timedelta(minutes=1))   # Set Algorithm to 21 days
        
        #self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        # rebalance the universe selection once a month
        self.rebalance_flag = 0
        # make sure to run the universe selection at the start of the algorithm even it's not the month start
        self.first_month_trade_flag = 1
        self.trade_flag = 0  
        # Number of quantiles for sorting returns for mean reversion
        self.nq = 5
        # Number of quantiles for sorting volatility over five-day mean reversion period
        self.nq_vol = 3
        # the symbol list after the coarse and fine universe selection
        self.universe = None
        self.NumberOfSymbolsFine = 500
        self.NumberOfSymbolsCoarse = 150
        self.dollarVolumeBySymbol = {}
        
         # setup state storage in initialize method
        self.stateData = { };
        
        # Benchmark
        self.AddEquity("SPY", Resolution.Daily)
        self.SetBenchmark("SPY")
        
        # SPY HIGH
        self.correction_flag = 0
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        try:
            self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.At(0, 0), Action(self.monthly_rebalance))
            self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.At(9, 0), Action(self.get_prices))
            self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 0), Action(self.take_profit))
            self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 1), Action(self.daily_rebalance))
            self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 1), Action(self.short))
            self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 1), Action(self.long))
            self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 10), Action(self.take_profit))
        except:
            self.Liquidate()
            return
            
    def monthly_rebalance(self):
        # rebalance the universe every month
        self.rebalance_flag = 1
 
    def CoarseSelectionFunction(self, coarse):
        if self.rebalance_flag or self.first_month_trade_flag:
            # drop stocks which have no fundamental data or have too low prices
            coarse_filtered = [x for x in coarse if (x.HasFundamentalData) and (20 <= float(x.Price) <= 300) and (float(x.Volume) >= 2000000)]
            if (self.SPY_avg_delta > -5.5) or (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes') and (self.SPY_mom >= 0.025):
                # We are going to use a dictionary to refer the object that will keep the moving averages
                for c in coarse_filtered:
                    if c.Symbol not in self.stateData:
                        self.stateData[c.Symbol] = SelectionData(c.Symbol, 10)
                    
                    # Updates the SymbolData object with current EOD price
                    avg = self.stateData[c.Symbol]
                    avg.update(c.EndTime, c.Price, c.Volume, c.DollarVolume)
                
                # filter the values of selectionData(sd) above SMA
                values = [sd for sd in self.stateData.values() if (sd.Volume > (sd.Sma.Current.Value * 1.25)) and (sd.Volume_Ratio > 2) 
                            and (sd.Fast_Vol_Ratio > 2) and (sd.Med_Vol_Ratio > 2)]
                
                # sort sd by the largest % jump in volume.
                values.sort(key=lambda sd: sd.Volume_Ratio, reverse=True)
                
                self.dollarVolumeBySymbol = {i.Symbol: (i.DollarVolume, i.Volume_Ratio) for i in values[:self.NumberOfSymbolsCoarse]}
                
                return [x.Symbol for x in values[:self.NumberOfSymbolsCoarse]]
            elif (self.SPY_avg_delta <= - 5.5 and self.SPY_vix_data == 'No') or (self.SPY_mom < 0.0):
                # rank the stocks by dollar volume and choose the top 150
                filtered = sorted(coarse_filtered, key=lambda x: x.DollarVolume, reverse=True)[:self.NumberOfSymbolsCoarse]
                
                self.dollarVolumeBySymbol = { i.Symbol: i.DollarVolume for i in filtered}
    
                return [x.Symbol for x in filtered]
        else:
            return self.universe
        
    def FineSelectionFunction(self, fine):
        def upper_groups(x):
            x = np.asarray(x, dtype=np.float32)
            x = x[x >= 0]
            cutoff = np.mean(x, dtype=np.float64) #+ (np.std(x, dtype=np.float64) * 2)
            return cutoff
        if self.rebalance_flag or self.first_month_trade_flag:
            """
            Need to do a better job with filter system with multiple parameters
                - currently takes the top 50% in each category and checks if stock is top 50% in each category
            """
            initial_filter = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
                                and x.ValuationRatios.PriceChange1M > 0
                                and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
                                and (x.Time - x.SecurityReference.IPODate).days > 180 and x.CompanyReference.CountryId == "USA"
                                and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
                                and x.CompanyReference.IndustryTemplateCode == "N"
                                and x.AssetClassification.MorningstarSectorCode in [MorningstarSectorCode.FinancialServices,
                                MorningstarSectorCode.Technology, MorningstarSectorCode.Industrials, MorningstarSectorCode.CommunicationServices,
                                MorningstarSectorCode.ConsumerCyclical, MorningstarSectorCode.ConsumerDefensive, MorningstarSectorCode.Healthcare,
                                MorningstarSectorCode.Utilities]]
                
            PERatio_mean = upper_groups([float(x.ValuationRatios.PERatio) for x in initial_filter if x.ValuationRatios.PERatio > 0])
            PEGRatio_mean = upper_groups([float(x.ValuationRatios.PEGRatio) for x in initial_filter if x.ValuationRatios.PEGRatio >= 0])
            FreeCashFlow_mean = upper_groups([float(x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths) for x in initial_filter if x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > 0])
            FirstYREPSGrowth_mean = upper_groups([float(x.ValuationRatios.FirstYearEstimatedEPSGrowth) for x in initial_filter if x.ValuationRatios.FirstYearEstimatedEPSGrowth > 0.05])                    
            
            second_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PERatio > PERatio_mean, reverse = True)
            third_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PEGRatio > PEGRatio_mean, reverse = True)
            fourth_filter = sorted(initial_filter, key = lambda x: x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > FreeCashFlow_mean, reverse = True)
            fifth_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.FirstYearEstimatedEPSGrowth > FirstYREPSGrowth_mean, reverse = True)
            
            filtered_fine = list(set.intersection(*map(set, [initial_filter, second_filter, third_filter, fourth_filter, fifth_filter])))   
                
            count = len(filtered_fine)
            if count == 0: return []
            
            myDict = dict()
            percent = float(self.NumberOfSymbolsFine / count)
            
            # select stocks with top dollar volume in every single sector
            for key in ["N"]:
                value = [x for x in filtered_fine if x.CompanyReference.IndustryTemplateCode == key]
                value = sorted(value, key=lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True)
                myDict[key] = value[:ceil(len(value) * percent)]
                
            topFine = list(chain.from_iterable(myDict.values()))#[:self.NumberOfSymbolsFine]
            self.universe = [f.Symbol for f in topFine] # [:self.NumberOfSymbolsFine]
            
            self.rebalance_flag = 0
            self.first_month_trade_flag = 0
            self.trade_flag = 1
            
        return self.universe

    def OnData(self, data):
        pass
    
    def short(self):
        if self.universe is None: return
        SPY_Velocity = 0
        self.long_leverage = 0
        self.short_leverage = 0
        # request the history of benchmark
        pri = self.History(["SPY"], 75, Resolution.Daily)
        pos_one = (pri.loc["SPY"]['close'][-1])
        pos_six = (pri.loc["SPY"]['close'][-75:].mean())
        # calculate velocity of the benchmark 
        velocity_stop = (pos_one - pos_six)/100.0
        SPY_Velocity = velocity_stop
        if SPY_Velocity > 0.0:
            self.long_leverage = 1.8     
            self.short_leverage = -0.0
        else:
            self.long_leverage = 1.1     
            self.short_leverage = -0.7
        if (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'No'): return
        elif (self.SPY_avg_delta > -5.5):
            for symbol in self.shorts:
                if len(self.shorts) + self.existing_shorts == 0: return
                self.AddEquity(symbol, Resolution.Daily)
                self.SetHoldings(symbol, 0.8*(self.short_leverage/(len(self.shorts) + self.existing_shorts)))
 
    def long(self):
        if self.universe is None: return
        if (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'No'): return
        elif (self.SPY_avg_delta > -5.5):
            for symbol in self.longs:
                if len(self.longs) + self.existing_longs == 0: return
                self.AddEquity(symbol, Resolution.Daily)
                self.SetHoldings(symbol, 1*(self.long_leverage/(len(self.longs) + self.existing_longs)))
       
    def get_prices(self):
        if self.universe is None: return
        # Get the last 30 days of prices for every stock in our universe
        prices = {}
        hist = self.History(self.universe, 30, Resolution.Daily)
        for i in self.universe:
            try:
                if str(i) in hist.index.levels[0]:
                    if self.technical_setup(i):
                        prices[i.Value] = hist.loc[str(i)]['close']
            except:
                pass
        
        if len(prices.keys()) <= 0: return
        df_prices = pd.DataFrame(prices, columns = prices.keys())
        # calculate the daily log return
        daily_rets = np.log(df_prices/df_prices.shift(1))
        # calculate the latest return but skip the most recent price
        rets = (df_prices.iloc[-2] - df_prices.iloc[0]) / df_prices.iloc[0]
        # standard deviation of the daily return
        stdevs = daily_rets.std(axis = 0)
        try:
            self.ret_qt = pd.qcut(rets, 5, labels=False) + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False) + 1
        except:
            self.ret_qt = pd.qcut(rets, 5, labels=False, duplicates='drop') + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False, duplicates='drop') + 1
        self.longs = list((self.ret_qt[self.ret_qt == 1].index) & (self.stdev_qt[self.stdev_qt < 3].index))
        self.shorts = list((self.ret_qt[self.ret_qt == self.nq].index) & (self.stdev_qt[self.stdev_qt < 3].index))
 
    def daily_rebalance(self):
        # rebalance the position in portfolio every day           
        if self.universe is None: return
        if self.longs is None: return
        if self.shorts is None: return
        self.existing_longs = 0
        self.existing_shorts = 0
        
        if (self.SPY_avg_delta <= - 5.5 and self.SPY_vix_data == 'No') or (self.SPY_mom < 0.0):
            for symbol in self.Portfolio.Invested:
                self.Liquidate(symbol)
            
        elif (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes'):
            self.monthly_rebalance
            self.get_prices

        elif (self.SPY_avg_delta > -5.5) or (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes') and (self.SPY_mom >= 0.025):
            
            for symbol in self.Portfolio.Keys:
                    
                if (symbol.Value != 'SPY') and (symbol.Value in self.ret_qt.index) and (self.Portfolio[symbol].IsLong):
                    current_quantile = self.ret_qt.loc[symbol.Value]
                    
                    avg_delta = DeltaModel(self.History(symbol, 25, Resolution.Daily), symbol).run()
                    vix_data = VixFix(self.History(symbol, 50, Resolution.Daily), symbol).run()
                    
                    if avg_delta > -5.5 or (avg_delta <= -5.5 and vix_data == 'Yes'):
                            
                        # create a 50 day exponential moving average
                        self.fast = self.EMA(symbol, 20, Resolution.Daily).Current.Value
                        # creat a 200 day simple moving average
                        self.slow = self.SMA(symbol, 55, Resolution.Daily).Current.Value
                        # create a 200 day simple moving average
                        self.baseline = self.SMA(symbol, 200, Resolution.Daily).Current.Value
                        
                        if (self.fast > self.slow):
                            if self.ttm_squeeze(symbol) or (self.ema_squeeze(symbol) >= 4) or (self.go_time_indicators(symbol) >= 3):
                                #self.TradeOptions(symbol)
                                self.MarketOrder(symbol, 100)
                                self.update_ticket(symbol)
                            elif self.ttm_squeeze(symbol) or (self.ema_squeeze(symbol) >= 3) or (self.go_time_indicators(symbol) >= 2):
                                if self.Portfolio[symbol].Quantity > 0:
                                    if (current_quantile == 1) and (symbol not in self.longs):
                                        self.existing_longs += 2
                                    elif (current_quantile > 1) and (symbol not in self.shorts):
                                        self.Liquidate(symbol)
                                        self.longs.remove(symbol)
                                        self.shorts.append(symbol)
                                elif self.Portfolio[symbol].Quantity < 0:
                                    if (current_quantile == self.nq) and (symbol not in self.shorts):
                                        self.existing_shorts += 1
                                    elif (current_quantile < self.nq) and (symbol not in self.longs):
                                        self.Liquidate(symbol)
                    
                    elif avg_delta <= -5.5:
                        try:
                            self.Liquidate(symbol)
                            self.universe.remove(symbol)
                            self.longs.remove(symbol)
                            self.shorts.remove(symbol)
                        except:
                            pass
                        
        self.AddEquity('SPY', Resolution.Daily)
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        self.take_profit()
    
    def technical_setup(self, i):
        x = re.sub('[(){}<>| ]', '', str(i))
        self.AddEquity(x, Resolution.Daily)
        self.History(self.Symbol(x), 200, Resolution.Daily)
        if self.EMA(x, 50, Resolution.Daily).Current.Value >= self.SMA(x, 200, Resolution.Daily).Current.Value:
            if self.RSI(x, 14, Resolution.Daily).Current.Value < 30:
                return x
    
    def ttm_squeeze(self, symbol):
        self.AddEquity(symbol, Resolution.Daily)
        #TTM Squeeze
        sma_twenty = self.SMA(symbol, 20, Resolution.Daily).Current.Value
        std = self.STD(symbol, 20, Resolution.Daily).Current.Value
        lower_band = sma_twenty - 2*std
        upper_band = sma_twenty + 2*std
        atr = self.ATR(symbol, 20, Resolution.Daily).Current.Value
        lower_keltner = sma_twenty - 2*atr
        upper_keltner = sma_twenty + 2*atr
        return lower_band > lower_keltner and upper_band < upper_keltner
    
    def ema_squeeze(self, symbol):
        self.AddEquity(symbol, Resolution.Daily)
        # create a 8 day exponential moving average
        fastest = self.EMA(symbol, 8, Resolution.Daily).Current.Value
        # create a 14 day exponential moving average
        faster = self.EMA(symbol, 14, Resolution.Daily).Current.Value   
        # create a 21 day exponential moving average
        fast = self.EMA(symbol, 21, Resolution.Daily).Current.Value
        # create a 34 day exponential moving average
        slow = self.EMA(symbol, 34, Resolution.Daily).Current.Value
        # create a 50 day exponential moving average
        slower = self.EMA(symbol, 55, Resolution.Daily).Current.Value
        # creat a 200 day simple moving average
        slowest = self.SMA(symbol, 200, Resolution.Daily).Current.Value
        # define a small tolerance on our checks to avoid bouncing
        tolerance = 0.025
        
        condition_one = ((fastest * (1-tolerance)) >= (faster * (1+tolerance)))
        condition_two = ((faster * (1-tolerance)) >= (fast * (1+tolerance)))
        condition_three = ((fast * (1-tolerance)) >= (slow * (1+tolerance)))
        condition_four = ((slow * (1-tolerance)) >= (slower * (1+tolerance)))
        condition_five = (slower > slowest)
        conditions = [condition_one, condition_two, condition_three, condition_four, condition_five]
        
        count = 0
        for condition in conditions:
            if condition is True:
                count += 1
        return count
    
    def go_time_indicators(self, symbol):
        self.AddEquity(symbol, Resolution.Daily)
        # Momentum & Volume & Trend
        # RSI <= 30 = buy
        rsi = self.RSI(symbol, 14, MovingAverageType.Simple, Resolution.Daily).Current.Value
        # William's %R <= -20 = buy
        wilr = self.WILR(symbol, 14, Resolution.Daily).Current.Value
        # MACD current < signal = buy
        macd = self.MACD(symbol, 12, 26, 9, Resolution.Daily)
        macd_current = macd.Current.Value
        macd_signal = macd.Signal.Current.Value
        macd_fast = macd.Fast.Current.Value
        macd_signal_delta = (macd_current - macd_signal)/(macd_fast)
        tolerance = 0.0025
        
        condition_one = (rsi <= 30)
        condition_two = (wilr <= -20)
        condition_three = (macd_signal_delta > tolerance)
        conditions = [condition_one, condition_two, condition_three]
        count = 0
        for condition in conditions:
            if condition is True:
                count += 1
        return count
                
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Invalid:
            self.Log(str(orderEvent))
            
        if orderEvent.Status == OrderStatus.Filled: 
            order = self.Transactions.GetOrderById(orderEvent.OrderId)
            if order.Tag == 'pt':  # If hit profit target, update stop order quantity
                updateSettings = UpdateOrderFields()
                updateSettings.Quantity = self.stops[orderEvent.Symbol].Quantity - orderEvent.Quantity
                self.stops[orderEvent.Symbol].Update(updateSettings)
    
            elif order.Tag == 'sl': # If hit stop loss, cancel profit target orders
                self.Transactions.CancelOpenOrders(orderEvent.Symbol, "Hit stop price")
    
    def take_profit(self):
        if self.Portfolio.TotalUnrealizedProfit > (0.2 * self.Portfolio.TotalPortfolioValue):
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            stocks_invested_by_profit = sorted(stocks_invested, key=lambda x: self.Portfolio[x].UnrealizedProfit, reverse=True)
            for stock in stocks_invested_by_profit:
                holding = self.Portfolio[stock].Quantity
                avg_price = self.Portfolio[stock].AveragePrice
                holdings_profit = self.Portfolio[stock].UnrealizedProfit
                holdings_cost = avg_price * holding
                if stock in self.shorts:
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -holding)
                elif stock in self.longs:
                    half_holding = int(holding/2.0)
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -holding)
        elif self.SPY_mom <= 0.0:
            for stock in self.Portfolio:
                try:
                    if stock.Value.Invested:
                        self.Liquidate(stock)
                except:
                    pass
        try:
            if self.longs and self.shorts:
                stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
                # liquidate stocks not in the trading list
                for stock in stocks_invested:
                    holding = self.Portfolio[stock].Quantity
                    avg_price = self.Portfolio[stock].AveragePrice
                    holdings_profit = self.Portfolio[stock].UnrealizedProfit
                    holdings_cost = avg_price * holding
                    if holdings_profit > holdings_cost * 1.5:
                        self.Liquidate(stock)
        except:
            pass
    
    def update_ticket(self, stock):
        """
        Uses mean reversion to update stop loss and limit orders.
        """
        self.mean = self.EMA(stock, 8, Resolution.Daily)
        self.atr = self.ATR(stock, 8, Resolution.Daily)
        # # Mean reversion when price is too low
        if self.Securities[stock].Price > (self.Portfolio[stock].AveragePrice * 0.95):
            limitTicket = self.LimitOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price + (0.5 * self.atr.Current.Value))
            stopTicket = self.StopMarketOrder(stock, -self.Portfolio[stock].Quantity, (self.Portfolio[stock].AveragePrice * 0.90))
    
        # Mean reversion when price is too high
        if self.Securities[stock].Close > self.mean.Current.Value + (1.5 * self.atr.Current.Value):
            limitTicket = self.LimitOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price + (self.atr.Current.Value))
            stopTicket = self.StopMarketOrder(stock, -self.Portfolio[stock].Quantity, (self.Securities[stock].Price * 0.95))
            
    def TradeOptions(self, symbol):
        equity = self.AddEquity(symbol, Resolution.Minute)
        option = self.AddOption(symbol, Resolution.Minute)
        self.symbol = option.Symbol
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        option.SetFilter(-3, +3, timedelta(0), timedelta(60))
        # use the underlying equity as the benchmark
        self.SetBenchmark(equity.Symbol)
        self.call = symbol # Initialize the call contract
        
        if slice.OptionChains.Count == 0: return   
        for i in slice.OptionChains:
            if i.Key != self.symbol: continue
            chain = i.Value
            call = [x for x in chain if x.Right == 0] # filter the call options contracts
            # sorted the contracts according to their expiration dates and choose the ATM options
            contracts = sorted(sorted(call, key = lambda x: x.Expiry, reverse=True), 
                                            key = lambda x: abs(chain.Underlying.Price - x.Strike))
    
            if len(contracts) == 0: return    
            contract = contracts[0] 
            self.call = contract.Symbol
            
            if self.Securities[self.call].Price < (0.01 * self.Portfolio.TotalPortfolioValue):
                num_contracts = int((self.Portfolio.TotalPortfolioValue * 0.01)/self.Securities[self.call].Price)
                
            num_conracts = max([5, num_contracts])
                
            #if num_contracts > 0:
            self.Sell(symbol, num_contracts) # short the call options
            if self.Portfolio[symbol].Quantity == 0:
                self.Buy(symbol, 100)     # buy 100 the underlying stock
                self.Log("The stock price at time 0 S(0): {}".format(self.Securities[symbol].Price)) 
                
    def MarketOpen(self):
        return self.Time.hour != 0 and self.Time.minute == 1
from QuantConnect.Indicators import IchimokuKinkoHyo

class IchimokuCloudCrossOverAlphaModel(AlphaModel):
    """
    This class emits insights to hold a long (short) position after the chikou line of a
    security's Ichimoku Cloud crosses over (under) the top (bottom) of the cloud.
    """
    symbol_data_by_symbol = {}
    
    def Update(self, algorithm, data):
        """
        Called each time our alpha model receives a new data slice.
        
        Input:
         - algorithm
            Algorithm instance running the backtest
         - data
            A data structure for all of an algorithm's data at a single time step
        
        Returns a list of Insights to the portfolio construction model.
        """
        insights = []

        for symbol, symbol_data in self.symbol_data_by_symbol.items():
            if not data.ContainsKey(symbol) or data[symbol] is None:
                continue
            
            # Update indicator with the latest TradeBar
            symbol_data.ichimoku.Update(data[symbol])
            
            # Determine insight direction
            current_location = symbol_data.get_location()
            if symbol_data.previous_location is not None: # Indicator is ready
                if symbol_data.previous_location != 1 and current_location == 1:
                    symbol_data.direction = InsightDirection.Up
                if symbol_data.previous_location != -1 and current_location == -1:
                    symbol_data.direction = InsightDirection.Down
            
            symbol_data.previous_location = current_location
            
            # Emit insight
            if symbol_data.direction:
                insight = Insight.Price(symbol, timedelta(days=1), symbol_data.direction)
                insights.append(insight)
        
        return insights
        
    def OnSecuritiesChanged(self, algorithm, changes):
        """
        Called each time our universe has changed.
        
        Input:
         - algorithm
            Algorithm instance running the backtest
         - changes
            The additions and subtractions to the algorithm's security subscriptions
        """
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            self.symbol_data_by_symbol[symbol] = SymbolData(symbol, algorithm)
        
        for security in changes.RemovedSecurities:
            self.symbol_data_by_symbol.pop(security.Symbol, None)


class SymbolData:
    """
    This class is used to store information on each security in the universe. It is
    responsible for initializing and warming up the Ichimoku indicator and determining
    the position of the chikou line in respect to the cloud.
    """
    previous_location = None
    direction = None
    
    def __init__(self, symbol, algorithm):
        """
        Input:
         - symbol
            Symbol of the security
         - algorithm
            Algorithm instance running the backtest
        """
        # Create Ichimoku indicator
        self.ichimoku = IchimokuKinkoHyo()

        # Warm up indicator
        history = algorithm.History(symbol, self.ichimoku.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.ichimoku.IsReady:
                self.previous_location = self.get_location()
            
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.ichimoku.Update(tradebar)
        
    def get_location(self):
        """
        Determines the location of the chikou line in respect to the cloud.
        
        Returns an integer in the interval [-1, 1], representing the location. 
        1 => Above cloud; 0 => Inside cloud; -1 => Below cloud
        """
        chikou = self.ichimoku.Chikou.Current.Value
        
        senkou_span_a = self.ichimoku.SenkouA.Current.Value
        senkou_span_b = self.ichimoku.SenkouB.Current.Value
        cloud_top = max(senkou_span_a, senkou_span_b)
        cloud_bottom = min(senkou_span_a, senkou_span_b)
        
        if chikou > cloud_top:
            return 1    # Above cloud
        if chikou < cloud_bottom:
            return -1   # Below cloud
            
        return 0        # Inside cloud
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *

class SequoiaAlphaModel(AlphaModel):
    """
    This class takes a comprehensive approach to assess whether an intrument is bullish or bearish.
    Hull_Moving_Average: Price = Close, Length = 20, Displace = 0
    Ichimoku: Tekan = 9, Kijun = 26
    Simple_Moving_Average: Length = 200, Length = 50
    Shared_Floor_Pivots: Time_Frame = Month
    RSI: Length = 10, Average_Type = Wilders
    MACDHistogram: Fast_Length = 12, Slow_Length = 26, MACD_Length = 9, Average_Type = Exponential
    
    This class emits insights to hold a long (short) position after the chikou line of a
    security's Ichimoku Cloud crosses over (under) the top (bottom) of the cloud.
    """
    symbol_data_by_symbol = {}
    
    def Update(self, algorithm, data):
        """
        Called each time our alpha model receives a new data slice.
        
        Input:
         - algorithm
            Algorithm instance running the backtest
         - data
            A data structure for all of an algorithm's data at a single time step
        
        Returns a list of Insights to the portfolio construction model.
        """
        insights = []

        for symbol, symbol_data in self.symbol_data_by_symbol.items():
            if not data.ContainsKey(symbol) or data[symbol] is None:
                continue
            
            # Update indicator with the latest TradeBar
            symbol_data.ichimoku.Update(data[symbol])
            symbol_data.hma.Update(data[symbol])
            symbol_data.twohundred_sma.Update(data[symbol])
            symbol_data.fifty_sma.Update(data[symbol])
            symbol_data.macd.Update(data[symbol])
            symbol_data.rsi.Update(data[symbol])
            
            
            # Determine insight direction
            current_location = symbol_data.get_location()
            if symbol_data.previous_location is not None: # Indicator is ready
                if symbol_data.previous_location != 1 and current_location == 1:
                    symbol_data.direction = InsightDirection.Up
                if symbol_data.previous_location != -1 and current_location == -1:
                    symbol_data.direction = InsightDirection.Down
            
            symbol_data.previous_location = current_location
            
            # Emit insight
            if symbol_data.direction:
                insight = Insight.Price(symbol, timedelta(days=1), symbol_data.direction)
                insights.append(insight)
        
        return insights

    
    def OnSecuritiesChanged(self, algorithm, changes):
        """
        Called each time our universe has changed.
        
        Input:
         - algorithm
            Algorithm instance running the backtest
         - changes
            The additions and subtractions to the algorithm's security subscriptions
        """
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            self.symbol_data_by_symbol[symbol] = SymbolData(symbol, algorithm)
        
        for security in changes.RemovedSecurities:
            self.symbol_data_by_symbol.pop(security.Symbol, None)   
        

class SymbolData:
    """
    This class is used to store information on each security in the universe. It is
    responsible for initializing and warming up the Ichimoku indicator and determining
    the position of the chikou line in respect to the cloud.
    """
    previous_location = None
    direction = None
    
    def __init__(self, symbol, algorithm):
        """
        Input:
         - symbol
            Symbol of the security
         - algorithm
            Algorithm instance running the backtest
        """
        # Create Ichimoku Indicator
        self.ichimoku = IchimokuKinkoHyo()
        # Warm up indicator
        history = algorithm.History(symbol, self.ichimoku.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.ichimoku.IsReady:
                self.previous_location = self.get_location()
            
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.ichimoku.Update(tradebar)
            
        # Create Hull Moving Average Indicator
        self.hma = self.HMA(symbol, 20, Resolution.Daily)
        # Warm up indicator
        history = algorithm.History(symbol, self.hma.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.hma.IsReady:
                self.signal = 1 if self.hma.Current.Value > row.close else 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.hma.Update(tradebar)
        
        # Create Exponential Moving Average Indicator (200 Length)
        self.twohundred_ema = self.EMA(symbol, 200, Resolution.Daily)
        # Warm up Indicator
        history = algorithm.History(symbol, self.twohundred_sma.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.twohundred_ema.IsReady:
                self.signal = 1 if self.twohundred_ema.Current.Value > row.close else 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.twohundred_ema.Update(tradebar)
            
        # Create Exponential Moving Average Indicator (50 Length)
        self.fifty_ema = self.EMA(symbol, 50, Resolution.Daily)
        # Warm up Indicator
        history = algorithm.History(symbol, self.fifty_ema.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.fifty_ema.IsReady:
                self.signal = 1 if self.fifty_ema.Current.Value > row.close else 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.fifty_ema.Update(tradebar)
        
        # Create MACD Fast_Length = 12, Slow_Length = 26, MACD_Length = 9, Average_Type = Exponential
        self.macd = self.MACD(symbol, 12, 26, 9, MovingAverageType.Exponential, Resolution.Daily)
        # Warm up Indicator
        history = algorithm.History(symbol, self.macd.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.macd.IsReady:
                tolerance = 0.0025
                signalDeltaPercent = (self.macd.Current.Value - self.macd.Signal.Current.Value)/self.macd.Fast.Current.Value
                if signalDeltaPercent > tolerance:
                    self.signal = 1 
                elif signalDeltaPercent < -tolerance:
                    self.signal = 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.macd.Update(tradebar)
            
        # Create RSI
        self.rsi = self.RSI(symbol, 14, MovingAverageType.Wilders, Resolution.Daily)
        # Warm up Indicator
        history = algorithm.History(symbol, self.rsi.WarmUpPeriod + 1, Resolution.Daily).loc[symbol]
        for idx, row in history.iterrows():
            if self.rsi.IsReady:
                tolerance = 0.0025

                if self.Current.Value * (1 + tolerance) < 30:
                    self.signal = 1 
                elif self.Current.Value * (1 + tolerance) > 70:
                    self.signal = 0
                
            tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume)
            self.rsi.Update(tradebar)
        
        
    def get_location(self):
        """
        Determines the location of the chikou line in respect to the cloud.
        
        Returns an integer in the interval [-1, 1], representing the location. 
        1 => Above cloud; 0 => Inside cloud; -1 => Below cloud
        """
        chikou = self.ichimoku.Chikou.Current.Value
        
        senkou_span_a = self.ichimoku.SenkouA.Current.Value
        senkou_span_b = self.ichimoku.SenkouB.Current.Value
        cloud_top = max(senkou_span_a, senkou_span_b)
        cloud_bottom = min(senkou_span_a, senkou_span_b)
        
        if chikou > cloud_top:
            return 1    # Above cloud
        if chikou < cloud_bottom:
            return -1   # Below cloud
            
        return 0        # Inside cloud
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
# Your New Python File
import os, sys, copy
import numpy as np

class TradingAlgorithm_main:
    """
    This function deploys and employs various trading strategies to arrive at the best
    decision to buy/sell/hold a stock.
    """
    def __init__(self, data, *args, **kwargs):
        """
        :param data:
        :param args:
        :param kwargs:
        """
        super(LongTermAlgos, self).__init__()
        self.data = data
        self.algos = {}

        # import libraries
        from MeanReversion.main import MeanReversion
        from StatisticalArbitrage.main import StatsArbitrage
        from CrowdSourcing.main import CrowdSource
        from MachineLearning.main import MachineLearning
        from Momentum.main import Momentum
        from TrendFollowing.main import TrendFollowing
        from MarketMaking.main import MarketMaking
        from SentimentAnalysis.main import Sentiment

        self.algos['MeanReversion'] = MeanReversion
        self.algos['StatsticalArbitrage'] = StatsticalArbitrage
        self.algos['CrowdSourcing'] = CrowdSourcing
        self.algos['MachineLearning'] = MachineLearning
        self.algos['Momentum'] = Momentum
        self.algos['TrendFollowing'] = TrendFollowing
        self.algos['MarketMaking'] = MarketMaking
        self.algos['SentimentAnalysis'] = SentimentAnalysis


    def run(self):
        """
        :return:
        """
        for algo in self.algos.keys():
            trading_strategy = self.algos[algo](data = self.data)
            results = trading_strategy.run()

# Your New Python File
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel, NullPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Risk import MaximumDrawdownPercentPortfolio, MaximumUnrealizedProfitPercentPerSecurity, MaximumDrawdownPercentPerSecurity
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

from datetime import datetime, timedelta
import pandas as pd
import numpy as np
import re
from math import ceil
from itertools import chain
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

from DeltaModel import DeltaModel
from VixFix import VixFix
from MyAlphaModel import MyAlphaModel, SymbolData
from UniverseSelectionHelperFunctions import SelectionData
from CompositeTradeSignals import CompositeTradeSignals
from SequoiaAlphaModel import SequoiaAlphaModel
from IchimokuCloudCrossOverAlphaModel import IchimokuCloudCrossOverAlphaModel

from trading_algorithm import TradingAlgorithm_main

class EnhancedShortTermMeanReversionAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2010, 1, 1)  #Set Start Date
        self.SetEndDate(datetime.now())   #Set End Date       
        self.SetCash(10000)            #Set Strategy Cash
        self.SetWarmUp(timedelta(minutes=1))   # Set Algorithm to 21 days
        
        #self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        # rebalance the universe selection once a month
        self.rebalance_flag = 0
        # make sure to run the universe selection at the start of the algorithm even it's not the month start
        self.first_month_trade_flag = 1
        self.trade_flag = 0  
        # Number of quantiles for sorting returns for mean reversion
        self.nq = 5
        # Number of quantiles for sorting volatility over five-day mean reversion period
        self.nq_vol = 3
        # the symbol list after the coarse and fine universe selection
        self.universe = None
        self.NumberOfSymbolsFine = 500
        self.NumberOfSymbolsCoarse = 150
        self.dollarVolumeBySymbol = {}
        
         # setup state storage in initialize method
        self.stateData = { };
        
        # Benchmark
        self.AddEquity("SPY", Resolution.Daily)
        self.SetBenchmark("SPY")
        
        # SPY HIGH
        self.correction_flag = 0
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.At(0, 0), Action(self.monthly_rebalance))
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", 305), Action(self.weekly_rebalance))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 304), Action(self.get_prices))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 303), Action(self.daily_rebalance))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 302), Action(self.short))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 301), Action(self.long))
            
    def monthly_rebalance(self):
        # rebalance the universe every month
        self.rebalance_flag = 1
                
        # symbols = {}
        # assets = []
        # for i in self.universe:
        #     assets.append(i)
        
        # for i in range(len(assets)):
        #     symbols[assets[i]] = self.AddEquity(assets[i], Resolution.Minute).Symbol
            
        # regressor = RandomForestRegressor(n_estimators=100, min_samples_split=5, random_state = 1990)
            
        # df = self.History(self.universe, 50, Resolution.Hour)
        
        # X = df.unstack(level=1).transpose().pct_change().dropna()
        # y = np.random.normal(100000, 5, X.shape[0])
        # X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 1990)
        # # Fit Regressor
        # regressor.fit(X_train, y_train)
        # # Get long-only predictions
        # weights = regressor.feature_importances_
        # symbols = X.columns[np.where(weights)]
        # self.selected = zip(symbols, weights)
    
    def weekly_rebalance(self):
        # rebalance coarse universe
        self.rebalance_flag = 1
 
    def CoarseSelectionFunction(self, coarse):
        if self.rebalance_flag or self.first_month_trade_flag:
            # drop stocks which have no fundamental data or have too low prices
            coarse_filtered = [x for x in coarse if (x.HasFundamentalData) and (20 <= float(x.Price) <= 300) and (float(x.Volume) >= 2000000)]
            # We are going to use a dictionary to refer the object that will keep the moving averages
            for c in coarse_filtered:
                if c.Symbol not in self.stateData:
                    self.stateData[c.Symbol] = SelectionData(c.Symbol, 10)
                
                # Updates the SymbolData object with current EOD price
                avg = self.stateData[c.Symbol]
                avg.update(c.EndTime, c.Price, c.Volume, c.DollarVolume)
            
            # filter the values of selectionData(sd) above SMA
            values = [sd for sd in self.stateData.values() if (sd.Volume > (sd.Sma.Current.Value * 1.25)) and (sd.Volume_Ratio > 2) 
                        and (sd.Fast_Vol_Ratio > 2) and (sd.Med_Vol_Ratio > 2)]
            
            # sort sd by the largest % jump in volume.
            values.sort(key=lambda sd: sd.Volume_Ratio, reverse=True)
            
            self.dollarVolumeBySymbol = {i.Symbol: i.DollarVolume for i in values[:self.NumberOfSymbolsCoarse]}
            
            return [x.Symbol for x in values[:self.NumberOfSymbolsCoarse]]
        else:
            return self.universe
        
    def FineSelectionFunction(self, fine):
        if self.rebalance_flag or self.first_month_trade_flag:
            """
            Need to do a better job with filter system with multiple parameters
                - currently takes the top 50% in each category and checks if stock is top 50% in each category
            """
            # filter the stocks which have positive EV To EBITDA
            # filtered_fine = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
            #                     and x.ValuationRatios.PriceChange1M > 0   
            #                     and x.CompanyReference.CountryId == "USA"
            #                     and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
            #                     and x.CompanyReference.IndustryTemplateCode == "N"
            #                     and x.ValuationRatios.PERatio > 20 #20
            #                     and x.ValuationRatios.FirstYearEstimatedEPSGrowth > 0.2
            #                     and x.ValuationRatios.BookValueYield < 0.0
            #                     and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
            #                     and (x.Time - x.SecurityReference.IPODate).days > 180
            #                     and x.ValuationRatios.PEGRatio > 2
            #                     and x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > 10]
            initial_filter = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
                                and x.ValuationRatios.PriceChange1M > 0
                                and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
                                and (x.Time - x.SecurityReference.IPODate).days > 180 and x.CompanyReference.CountryId == "USA"
                                and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
                                and x.CompanyReference.IndustryTemplateCode == "N"
                                and x.AssetClassification.MorningstarSectorCode in [MorningstarSectorCode.FinancialServices,
                                MorningstarSectorCode.Technology, MorningstarSectorCode.Industrials, MorningstarSectorCode.CommunicationServices,
                                MorningstarSectorCode.ConsumerCyclical, MorningstarSectorCode.ConsumerDefensive, MorningstarSectorCode.Healthcare,
                                MorningstarSectorCode.Utilities]]
                
            second_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PERatio > 5, reverse = True)[:int(len(initial_filter)/3)]
            third_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PEGRatio > 0.5, reverse = True)[:int(len(initial_filter)/2.5)]
            fourth_filter = sorted(initial_filter, key = lambda x: x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > 5, reverse = True)[:int(len(initial_filter)/2.5)]
            fifth_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.FirstYearEstimatedEPSGrowth > 0.1, reverse = True)[:int(len(initial_filter)/2.5)]
            
            filtered_fine = list()
            for symbol in initial_filter:
                if symbol in second_filter:
                    if symbol in third_filter:
                        if symbol in fourth_filter:
                            if symbol in fifth_filter:
                                filtered_fine.append(symbol)
                
            count = len(filtered_fine)
            if count == 0: return []
            
            myDict = dict()
            percent = float(self.NumberOfSymbolsFine / count)
            
            # select stocks with top dollar volume in every single sector
            for key in ["N"]:
                value = [x for x in filtered_fine if x.CompanyReference.IndustryTemplateCode == key]
                value = sorted(value, key=lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True)
                myDict[key] = value[:ceil(len(value) * percent)]
                
            topFine = list(chain.from_iterable(myDict.values()))[:self.NumberOfSymbolsFine]
            self.universe = [f.Symbol for f in topFine[:int(self.NumberOfSymbolsFine)]] # [:self.NumberOfSymbolsFine]
            
            self.rebalance_flag = 0
            self.first_month_trade_flag = 0
            self.trade_flag = 1
            
        return self.universe

    def OnData(self, data):
        pass
    
    def short(self):
        if self.universe is None: return
        SPY_Velocity = 0
        self.long_leverage = 0
        self.short_leverage = 0
        # request the history of benchmark
        pri = self.History(["SPY"], 75, Resolution.Daily)
        pos_one = (pri.loc["SPY"]['close'][-1])
        pos_six = (pri.loc["SPY"]['close'][-75:].mean())
        # calculate velocity of the benchmark 
        velocity_stop = (pos_one - pos_six)/100.0
        SPY_Velocity = velocity_stop
        if SPY_Velocity > 0.0:
            self.long_leverage = 1.8     
            self.short_leverage = -0.0
        else:
            self.long_leverage = 1.1     
            self.short_leverage = -0.7    
        for symbol in self.shorts:
            if len(self.shorts) + self.existing_shorts == 0: return
            self.AddEquity(symbol, Resolution.Daily)
            self.SetHoldings(symbol, 0.8*(self.short_leverage/(len(self.shorts) + self.existing_shorts)))                                
 
    def long(self):
        if self.universe is None: return
        for symbol in self.longs:
            if len(self.longs) + self.existing_longs == 0: return
            self.AddEquity(symbol, Resolution.Daily)
            self.SetHoldings(symbol, 1*(self.long_leverage/(len(self.longs) + self.existing_longs)))
       
    def get_prices(self):
        def technical_setup(i):
            x = re.sub('[(){}<>| ]', '', str(i))
            self.AddEquity(x, Resolution.Daily)
            self.History(self.Symbol(x), 200, Resolution.Daily)
            if self.EMA(x, 50, Resolution.Daily).Current.Value >= self.EMA(x, 200, Resolution.Daily).Current.Value:
                RSI = self.RSI(x, 14, Resolution.Daily).Current.Value
                if RSI <= 30:
                    return x
        
        if self.universe is None: return
        # Get the last 30 days of prices for every stock in our universe
        prices = {}
        hist = self.History(self.universe, 30, Resolution.Daily)
        for i in self.universe:
            try:
                if str(i) in hist.index.levels[0]:
                    if technical_setup(i):
                        prices[i.Value] = hist.loc[str(i)]['close']
            except:
                pass
        
        if len(prices.keys()) <= 0: return
        df_prices = pd.DataFrame(prices, columns = prices.keys())
        # calculate the daily log return
        daily_rets = np.log(df_prices/df_prices.shift(1))
        # calculate the latest return but skip the most recent price
        rets = (df_prices.iloc[-2] - df_prices.iloc[0]) / df_prices.iloc[0]
        # standard deviation of the daily return
        stdevs = daily_rets.std(axis = 0)
        try:
            self.ret_qt = pd.qcut(rets, 5, labels=False) + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False) + 1
        except:
            self.ret_qt = pd.qcut(rets, 5, labels=False, duplicates='drop') + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False, duplicates='drop') + 1
        self.longs = list((self.ret_qt[self.ret_qt == 1].index) & (self.stdev_qt[self.stdev_qt < 3].index))
        self.shorts = list((self.ret_qt[self.ret_qt == self.nq].index) & (self.stdev_qt[self.stdev_qt < 3].index))
 
    def daily_rebalance(self):
        # rebalance the position in portfolio every day           
        if self.universe is None: return
        if self.longs is None: return
        if self.shorts is None: return
        self.existing_longs = 0
        self.existing_shorts = 0
        
        if (self.SPY_avg_delta <= - 5.5 and self.SPY_vix_data == 'No') or (self.SPY_mom < 0.0):
            if self.correction_flag == 0:
                for symbol in self.Portfolio.Invested:
                    self.Liquidate(symbol)
                self.correction_flag = 1
            elif self.correction_flag == 1:
                return
            
        elif (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes'):
            if self.correction_flag == 1:
                self.monthly_rebalance
                self.weekly_rebalance
                self.get_prices
                self.daily_rebalance
                self.short
                self.long
                self.correction_flag = 0
                return
            elif self.correction_flag == 0:
                pass

        elif (self.SPY_avg_delta > -5.5) or (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes') or (self.SPY_mom >= 0.0):
            
            for symbol in self.Portfolio.Keys:
                    
                if (symbol.Value != 'SPY') and (symbol.Value in self.ret_qt.index) and (self.Portfolio[symbol].IsLong):
                    current_quantile = self.ret_qt.loc[symbol.Value]
                    
                    avg_delta = DeltaModel(self.History(symbol, 25, Resolution.Daily), symbol).run()
                    vix_data = VixFix(self.History(symbol, 50, Resolution.Daily), symbol).run()
                    
                    if avg_delta > -5.5 or (avg_delta <= -5.5 and vix_data == 'Yes'):
                        
                        def ttm_squeeze(symbol):
                            #TTM Squeeze
                            sma_twenty = self.SMA(symbol, 20, Resolution.Daily).Current.Value
                            std = self.STD(symbol, 20, Resolution.Daily).Current.Value
                            lower_band = sma_twenty - 2*std
                            upper_band = sma_twenty + 2*std
                            atr = self.ATR(symbol, 20, Resolution.Daily).Current.Value
                            lower_keltner = sma_twenty - 2*atr
                            upper_keltner = sma_twenty + 2*atr
                            return lower_band > lower_keltner and upper_band < upper_keltner
                        
                        def ema_squeeze(symbol):
                            # create a 8 day exponential moving average
                            fastest = self.EMA(symbol, 8, Resolution.Daily).Current.Value
                            # create a 14 day exponential moving average
                            faster = self.EMA(symbol, 14, Resolution.Daily).Current.Value   
                            # create a 21 day exponential moving average
                            fast = self.EMA(symbol, 21, Resolution.Daily).Current.Value
                            # create a 34 day exponential moving average
                            slow = self.EMA(symbol, 34, Resolution.Daily).Current.Value
                            # create a 50 day exponential moving average
                            slower = self.EMA(symbol, 55, Resolution.Daily).Current.Value
                            # creat a 200 day simple moving average
                            slowest = self.SMA(symbol, 200, Resolution.Daily).Current.Value
                            # define a small tolerance on our checks to avoid bouncing
                            tolerance = 0.025
                            
                            condition_one = ((fastest * (1-tolerance)) >= (faster * (1+tolerance)))
                            condition_two = ((faster * (1-tolerance)) >= (fast * (1+tolerance)))
                            condition_three = ((fast * (1-tolerance)) >= (slow * (1+tolerance)))
                            condition_four = ((slow * (1-tolerance)) >= (slower * (1+tolerance)))
                            condition_five = (slower > slowest)
                            conditions = [condition_one, condition_two, condition_three, condition_four]
                            
                            count = 0
                            for condition in conditions:
                                if condition is True:
                                    count += 1
                            if condition_five is True:
                                return count
                            
                        # create a 50 day exponential moving average
                        self.slow = self.EMA(symbol, 21, Resolution.Daily).Current.Value
                        # creat a 200 day simple moving average
                        self.slower = self.SMA(symbol, 55, Resolution.Daily).Current.Value
                        
                        if (self.slow > self.slower):
                            if ttm_squeeze(symbol) or (ema_squeeze(symbol) >= 3):
                                if self.Portfolio[symbol].Quantity > 0:
                                    if (current_quantile == 1) and (symbol not in self.longs):
                                        self.existing_longs += 2
                                        self.update_ticket(symbol)
                                    elif (current_quantile > 1) and (symbol not in self.shorts):
                                        self.Liquidate(symbol)
                                        self.longs.remove(symbol)
                                        self.shorts.append(symbol)
                                elif self.Portfolio[symbol].Quantity < 0:
                                    if (current_quantile == self.nq) and (symbol not in self.shorts):
                                        self.existing_shorts += 1
                                        self.update_ticket(symbol)
                                    elif (current_quantile < self.nq) and (symbol not in self.longs):
                                        self.Liquidate(symbol)
                    
                    elif avg_delta <= -5.5:
                        try:
                            self.Liquidate(symbol)
                            self.universe.remove(symbol)
                            self.longs.remove(symbol)
                            self.shorts.remove(symbol)
                        except:
                            pass
                        
        self.AddEquity('SPY', Resolution.Daily)
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        self.take_profit()
                        
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Invalid:
            self.Log(str(orderEvent))
            
        if orderEvent.Status == OrderStatus.Filled: 
            order = self.Transactions.GetOrderById(orderEvent.OrderId)
            if order.Tag == 'pt':  # If hit profit target, update stop order quantity
                updateSettings = UpdateOrderFields()
                updateSettings.Quantity = self.stops[orderEvent.Symbol].Quantity - orderEvent.Quantity
                self.stops[orderEvent.Symbol].Update(updateSettings)
    
            elif order.Tag == 'sl': # If hit stop loss, cancel profit target orders
                self.Transactions.CancelOpenOrders(orderEvent.Symbol, "Hit stop price")
    
    def take_profit(self):
        if self.Portfolio.TotalUnrealizedProfit > (0.2 * self.Portfolio.TotalPortfolioValue):
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            stocks_invested_by_profit = sorted(stocks_invested, key=lambda x: self.Portfolio[x].UnrealizedProfit, reverse=True)
            for stock in stocks_invested_by_profit:
                holding = self.Portfolio[stock].Quantity
                avg_price = self.Portfolio[stock].AveragePrice
                holdings_profit = self.Portfolio[stock].UnrealizedProfit
                holdings_cost = avg_price * holding
                if stock in self.shorts:
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -holding)
                elif stock in self.longs:
                    half_holding = int(holding/2.0)
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -half_holding)
        elif self.longs and self.shorts:
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            # liquidate stocks not in the trading list
            for stock in stocks_invested:
                holding = self.Portfolio[stock].Quantity
                avg_price = self.Portfolio[stock].AveragePrice
                holdings_profit = self.Portfolio[stock].UnrealizedProfit
                holdings_cost = avg_price * holding
                if holdings_profit > holdings_cost * 1.5:
                    self.Liquidate(stock)
        elif self.SPY_mom <= 0.0:
            for stock in self.Portfolio:
                try:
                    if stock.Value.Invested:
                        self.Liquidate(stock)
                except:
                    pass
    
    def update_ticket(self, stock):
        """
        Uses mean reversion to update stop loss and limit orders.
        """
        self.mean = self.EMA(stock, 20, Resolution.Daily)
        self.atr = self.ATR(stock, 20, Resolution.Daily)
        # Mean reversion when price is too low
        if self.Securities[stock].Price < self.mean.Current.Value - 2.0 * self.atr.Current.Value:
            holding = self.Portfolio[stock].Quantity
            #marketTicket = self.MarketOrder(stock, holding)
            limitTicket = self.LimitOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            stopTicket = self.StopMarketOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price - self.atr.Current.Value)
    
        # Mean reversion when price is too high
        if self.Securities[stock].Price > self.mean.Current.Value + 2.0 * self.atr.Current.Value:
            holding = self.Portfolio[stock].Quantity
            #marketTicket = self.MarketOrder(stock, -holding)
            limitTicket = self.LimitOrder(stock, self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            stopTicket = self.StopMarketOrder(stock, self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            
            
    def TradeOptions(self, symbol):
        equity = self.AddEquity(symbol, Resolution.Minute)
        option = self.AddOption(symbol, Resolution.Minute)
        self.symbol = option.Symbol
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        option.SetFilter(-3, +3, timedelta(0), timedelta(60))
        # use the underlying equity as the benchmark
        self.SetBenchmark(equity.Symbol)
        self.call = symbol # Initialize the call contract
        
        if slice.OptionChains.Count == 0: return   
        for i in slice.OptionChains:
            if i.Key != self.symbol: continue
            chain = i.Value
            call = [x for x in chain if x.Right == 0] # filter the call options contracts
            # sorted the contracts according to their expiration dates and choose the ATM options
            contracts = sorted(sorted(call, key = lambda x: x.Expiry, reverse=True), 
                                            key = lambda x: abs(chain.Underlying.Price - x.Strike))
    
            if len(contracts) == 0: return    
            contract = contracts[0] 
            self.call = contract.Symbol
            self.Sell(symbol, 1) # short the call options
            if self.Portfolio[symbol].Quantity == 0:
                self.Buy(symbol, 100)     # buy 100 the underlying stock
                self.Log("The stock price at time 0 S(0): {}".format(self.Securities[symbol].Price)) 
                
    def MarketOpen(self):
        return self.Time.hour != 0 and self.Time.minute == 1
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Orders.Fees import ConstantFeeModel
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import EqualWeightingPortfolioConstructionModel, NullPortfolioConstructionModel
from QuantConnect.Algorithm.Framework.Risk import MaximumDrawdownPercentPortfolio, MaximumUnrealizedProfitPercentPerSecurity, MaximumDrawdownPercentPerSecurity
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

from datetime import datetime, timedelta
import pandas as pd
import numpy as np
from scipy.stats import hmean, gmean
import re
from math import ceil
from itertools import chain
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

from DeltaModel import DeltaModel
from VixFix import VixFix
from UniverseSelectionHelperFunctions import SelectionData
from CompositeTradeSignals import CompositeTradeSignals
from SequoiaAlphaModel import SequoiaAlphaModel
from IchimokuCloudCrossOverAlphaModel import IchimokuCloudCrossOverAlphaModel

from trading_algorithm import TradingAlgorithm_main

class EnhancedShortTermMeanReversionAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2010, 1, 1)  #Set Start Date
        #self.SetEndDate(2016, 1, 1)  #Set Start Date
        self.SetCash(10000)            #Set Strategy Cash
        self.SetWarmUp(timedelta(minutes=1))   # Set Algorithm to 21 days
        
        #self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        #self.AddUniverse("Weekly", lambda dt: self.weekly_adds if dt.day % 7 == 0 else [])
        # rebalance the universe selection once a month
        self.rebalance_flag = 0
        # make sure to run the universe selection at the start of the algorithm even it's not the month start
        self.first_month_trade_flag = 1
        self.trade_flag = 0  
        # Number of quantiles for sorting returns for mean reversion
        self.nq = 5
        # Number of quantiles for sorting volatility over five-day mean reversion period
        self.nq_vol = 3
        # the symbol list after the coarse and fine universe selection
        self.universe = None
        self.NumberOfSymbolsFine = 500
        self.NumberOfSymbolsCoarse = 150
        self.dollarVolumeBySymbol = {}
        
         # setup state storage in initialize method
        self.stateData = { };
        
        # Benchmark
        self.AddEquity("SPY", Resolution.Daily)
        self.SetBenchmark("SPY")
        
        # SPY HIGH
        self.correction_flag = 0
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.At(0, 0), Action(self.monthly_rebalance))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 304), Action(self.get_prices))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 302), Action(self.daily_rebalance))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 301), Action(self.short))
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 300), Action(self.long))
    
    def monthly_rebalance(self):
        # rebalance the universe every month
        self.rebalance_flag = 1
 
    def CoarseSelectionFunction(self, coarse):
        def aggregate_mean(x):
            x = np.asarray(x, dtype=np.float32)
            x = x[x >= 0]
            cutoff = np.mean(x, dtype=np.float64)
            return cutoff
        if self.rebalance_flag or self.first_month_trade_flag:
            # drop stocks which have no fundamental data or have too low prices
            selected = [x for x in coarse if (x.HasFundamentalData) and (20 <= float(x.Price) <= 300) and (float(x.Volume) >= 2000000)]
            # rank the stocks by dollar volume and choose the top 150 # <= 300
            avg_dollar_volume = aggregate_mean([x.DollarVolume for x in coarse])
            
            filtered = sorted(selected, key=lambda x: x.DollarVolume > avg_dollar_volume, reverse=True)[:self.NumberOfSymbolsCoarse]
            
            self.dollarVolumeBySymbol = {i.Symbol: i.DollarVolume for i in filtered}
            
            return [x.Symbol for x in filtered]
        else:
            return self.universe

    def FineSelectionFunction(self, fine):
        def aggregate_mean(x):
            x = np.asarray(x, dtype=np.float32)
            x = x[x >= 0]
            cutoff = np.mean(x, dtype=np.float64)
            return cutoff
        def upper_groups(x):
            x = np.asarray(x, dtype=np.float32)
            x = x[x >= 0]
            cutoff = np.mean(x, dtype=np.float64) + (np.std(x, dtype=np.float64) *2)
            return cutoff

        if self.rebalance_flag or self.first_month_trade_flag:
            # filter the stocks which have positive EV To EBITDA
            filtered_fine = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
                                and x.ValuationRatios.PriceChange1M > 0   
                                and x.CompanyReference.CountryId == "USA"
                                and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
                                and x.CompanyReference.IndustryTemplateCode == "N"
                                and x.ValuationRatios.PERatio > 20
                                and x.ValuationRatios.FirstYearEstimatedEPSGrowth > 0.2
                                and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
                                and (x.Time - x.SecurityReference.IPODate).days > 180
                                and x.ValuationRatios.PEGRatio > 2
                                and x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths > 10]
                                
            if len(filtered_fine) <= 0:
                symbol_marketcap = [x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio for x in fine]
                marketcap_mean = upper_groups([x for x in symbol_marketcap])
                
                initial_filter = [x for x in fine if x.ValuationRatios.EVToEBITDA > 0
                                    and x.ValuationRatios.PriceChange1M > 0
                                    and x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > marketcap_mean
                                    and (x.Time - x.SecurityReference.IPODate).days > 180 and x.CompanyReference.CountryId == "USA"
                                    and (x.CompanyReference.PrimaryExchangeID == "NYS" or x.CompanyReference.PrimaryExchangeID == "NAS")
                                    and x.CompanyReference.IndustryTemplateCode == "N"]
                            
                PERatio_mean = upper_groups([float(x.ValuationRatios.PERatio) for x in initial_filter])
                PEGRatio_mean = upper_groups([float(x.ValuationRatios.PEGRatio) for x in initial_filter])
                FreeCashFlow_mean = upper_groups([float(x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths) for x in initial_filter])
                FirstYREPSGrowth_mean = upper_groups([float(x.ValuationRatios.FirstYearEstimatedEPSGrowth) for x in initial_filter])
                
                second_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PERatio > PERatio_mean, reverse = True)#[:int(len(initial_filter)/2)]
                third_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.PEGRatio >= PEGRatio_mean, reverse = True)#[:int(len(initial_filter)/1.5)]
                fourth_filter = sorted(initial_filter, key = lambda x: x.FinancialStatements.CashFlowStatement.FreeCashFlow.ThreeMonths >= FreeCashFlow_mean, reverse = True)#[:int(len(initial_filter)/1.5)]
                fifth_filter = sorted(initial_filter, key = lambda x: x.ValuationRatios.FirstYearEstimatedEPSGrowth >= FirstYREPSGrowth_mean, reverse = True)#[:int(len(initial_filter)/1.5)]

                filtered_fine = list(set.intersection(*map(set, [initial_filter, second_filter, third_filter, fourth_filter, fifth_filter])))


            count = len(filtered_fine)
            if count == 0: return []
            
            myDict = dict()
            percent = float(self.NumberOfSymbolsFine / count)
            
            # select stocks with top dollar volume in every single sector
            for key in ["N"]:
                value = [x for x in filtered_fine if x.CompanyReference.IndustryTemplateCode == key]
                value = sorted(value, key=lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True)
                myDict[key] = value[:ceil(len(value) * percent)]
                
            topFine = list(chain.from_iterable(myDict.values()))[:self.NumberOfSymbolsFine]
            self.universe = [f.Symbol for f in topFine]
            
            self.rebalance_flag = 0
            self.first_month_trade_flag = 0
            self.trade_flag = 1
            
        return self.universe

    def OnData(self, data):
        pass
    
    def short(self):
        if self.universe is None: return
        if (self.SPY_avg_delta > -5.5):
            SPY_Velocity = 0
            self.long_leverage = 0
            self.short_leverage = 0
            # request the history of benchmark
            pri = self.History(["SPY"], 75, Resolution.Daily)
            pos_one = (pri.loc["SPY"]['close'][-1])
            pos_six = (pri.loc["SPY"]['close'][-75:].mean())
            # calculate velocity of the benchmark 
            velocity_stop = (pos_one - pos_six)/100.0
            SPY_Velocity = velocity_stop
            if SPY_Velocity > 0.0:
                self.long_leverage = 1.8     
                self.short_leverage = -0.0
            else:
                self.long_leverage = 1.1     
                self.short_leverage = -0.7
            for symbol in self.shorts:
                if len(self.shorts) + self.existing_shorts == 0: return
                self.AddEquity(symbol, Resolution.Daily)
                self.SetHoldings(symbol, 0.8*(self.short_leverage/(len(self.shorts) + self.existing_shorts)))
 
    def long(self):
        if self.universe is None: return
        if (self.SPY_avg_delta > -5.5):
            for symbol in self.longs:
                if len(self.longs) + self.existing_longs == 0: return
                self.AddEquity(symbol, Resolution.Daily)
                self.SetHoldings(symbol, (self.long_leverage/(len(self.longs) + self.existing_longs)))
       
    def get_prices(self):
        if self.universe is None: return
        # Get the last 25 days of prices for every stock in our universe
        prices = {}
        hist = self.History(self.universe, 25, Resolution.Daily)
        for i in self.universe:
            if str(i) in hist.index.levels[0]:
                if self.technical_setup(i):
                    prices[i.Value] = hist.loc[str(i)]['close']
        df_prices = pd.DataFrame(prices, columns = prices.keys())
        # calculate the daily log return
        daily_rets = np.log(df_prices/df_prices.shift(1))
        # calculate the latest return but skip the most recent price
        rets = (df_prices.iloc[-2] - df_prices.iloc[0]) / df_prices.iloc[0]
        # standard deviation of the daily return
        stdevs = daily_rets.std(axis = 0)
        try:
            self.ret_qt = pd.qcut(rets, 5, labels=False) + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False) + 1
        except:
            self.ret_qt = pd.qcut(rets, 5, labels=False, duplicates='drop') + 1
            self.stdev_qt = pd.qcut(stdevs, 3, labels=False, duplicates='drop') + 1
        self.longs = list((self.ret_qt[self.ret_qt == 1].index) & (self.stdev_qt[self.stdev_qt < 3].index))
        self.shorts = list((self.ret_qt[self.ret_qt == self.nq].index) & (self.stdev_qt[self.stdev_qt < 3].index))
 
    def daily_rebalance(self):
        # rebalance the position in portfolio every day           
        if self.universe is None: return
        if self.longs is None: return
        if self.shorts is None: return
        self.existing_longs = 0
        self.existing_shorts = 0
        
        if (self.SPY_avg_delta <= - 5.5 and self.SPY_vix_data == 'No') or (self.SPY_mom < 0.0):
            if self.correction_flag == 0:
                for symbol in self.Portfolio.Invested:
                    self.Liquidate(symbol)
                self.correction_flag = 1
            elif self.correction_flag == 1:
                return
            
        elif (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes'):
            if self.correction_flag == 1:
                self.monthly_rebalance
                self.daily_rebalance
                self.correction_flag = 0
                return
            elif self.correction_flag == 0:
                pass

        elif (self.SPY_avg_delta > -5.5) or (self.SPY_avg_delta <= -5.5 and self.SPY_vix_data == 'Yes') or (self.SPY_mom >= 0.5):
            
            for symbol in self.Portfolio.Keys:
                    
                if (symbol.Value != 'SPY') and (symbol.Value in self.ret_qt.index) and (self.Portfolio[symbol].IsLong):
                    current_quantile = self.ret_qt.loc[symbol.Value]
                    
                    avg_delta = DeltaModel(self.History(symbol, 25, Resolution.Daily), symbol).run()
                    vix_data = VixFix(self.History(symbol, 50, Resolution.Daily), symbol).run()
                    
                    if avg_delta > -5.5 or (avg_delta <= -5.5 and vix_data == 'Yes'):
                        
                        def ttm_squeeze(symbol):
                            #TTM Squeeze
                            sma_twenty = self.SMA(symbol, 20, Resolution.Daily).Current.Value
                            std = self.STD(symbol, 20, Resolution.Daily).Current.Value
                            lower_band = sma_twenty - 2*std
                            upper_band = sma_twenty + 2*std
                            atr = self.ATR(symbol, 20, Resolution.Daily).Current.Value
                            lower_keltner = sma_twenty - 2*atr
                            upper_keltner = sma_twenty + 2*atr
                            return (lower_band > lower_keltner) and (upper_band < upper_keltner)
                        
                        def ema_squeeze(symbol):
                            # create a 8 day exponential moving average
                            fastest = self.EMA(symbol, 8, Resolution.Daily).Current.Value
                            # create a 14 day exponential moving average
                            faster = self.EMA(symbol, 14, Resolution.Daily).Current.Value   
                            # create a 21 day exponential moving average
                            fast = self.EMA(symbol, 21, Resolution.Daily).Current.Value
                            # create a 34 day exponential moving average
                            slow = self.EMA(symbol, 34, Resolution.Daily).Current.Value
                            # create a 50 day exponential moving average
                            slower = self.EMA(symbol, 55, Resolution.Daily).Current.Value
                            # creat a 200 day simple moving average
                            slowest = self.SMA(symbol, 200, Resolution.Daily).Current.Value
                            # define a small tolerance on our checks to avoid bouncing
                            tolerance = 0.025
                            
                            condition_one = ((fastest * (1-tolerance)) >= (faster * (1+tolerance)))
                            condition_two = ((faster * (1-tolerance)) >= (fast * (1+tolerance)))
                            condition_three = ((fast * (1-tolerance)) >= (slow * (1+tolerance)))
                            condition_four = ((slow * (1-tolerance)) >= (slower * (1+tolerance)))
                            condition_five = (slower > slowest)
                            conditions = [condition_one, condition_two, condition_three, condition_four, condition_five]
                            
                            count = 0
                            for condition in conditions:
                                if condition is True:
                                    count += 1
                                return count
                        
                        def go_time_indicators(symbol):
                            # Momentum & Volume & Trend
                            # RSI <= 30 = buy
                            rsi = self.RSI(symbol, 14, MovingAverageType.Simple, Resolution.Daily).Current.Value
                            # William's %R <= -20 = buy
                            wilr = self.WILR(symbol, 14, Resolution.Daily).Current.Value
                            # MACD current < signal = buy
                            macd = self.MACD(symbol, 12, 26, 9, Resolution.Daily)
                            macd_current = macd.Current.Value
                            macd_signal = macd.Signal.Current.Value
                            macd_fast = macd.Fast.Current.Value
                            macd_signal_delta = (macd_current - macd_signal)/(macd_fast)
                            tolerance = 0.0025
                            
                            condition_one = (rsi < 30)
                            condition_two = (wilr < -20)
                            condition_three = (macd_signal_delta > tolerance)
                            
                            return condition_one or condition_two or condition_three
                        
                        # create a 21 day exponential moving average
                        self.slow = self.EMA(symbol, 21, Resolution.Daily).Current.Value
                        # creat a 55 day simple moving average
                        self.slower = self.SMA(symbol, 55, Resolution.Daily).Current.Value
                        
                        if (self.slow > self.slower):
                            if ((ttm_squeeze(symbol) and go_time_indicators(symbol)) and self.SPY_mom > 0.5):
                                self.TradeOptions(symbol)
                                self.update_ticket(symbol)
                            if ttm_squeeze(symbol) or (ema_squeeze(symbol) >= 3) or go_time_indicators(symbol):
                                if self.Portfolio[symbol].Quantity > 0:
                                    if (current_quantile == 1) and (symbol not in self.longs):
                                        self.existing_longs += 2
                                        self.update_ticket(symbol)
                                    elif (current_quantile > 1) and (symbol not in self.shorts):
                                        self.Liquidate(symbol)
                                        self.longs.remove(symbol)
                                        self.shorts.append(symbol)
                                elif self.Portfolio[symbol].Quantity < 0:
                                    if (current_quantile == self.nq) and (symbol not in self.shorts):
                                        self.existing_shorts += 1
                                        self.update_ticket(symbol)
                                    elif (current_quantile < self.nq) and (symbol not in self.longs):
                                        self.Liquidate(symbol)
                        # else:
                        #     self.update_ticket(symbol)
                    
                    elif avg_delta <= -5.5:
                        try:
                            self.Liquidate(symbol)
                            self.universe.remove(symbol)
                            self.longs.remove(symbol)
                            self.shorts.remove(symbol)
                        except:
                            pass
                        
        self.AddEquity('SPY', Resolution.Daily)
        self.SPY_avg_delta = DeltaModel(self.History(self.Symbol('SPY'), 25, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_vix_data = VixFix(self.History(self.Symbol('SPY'), 100, Resolution.Daily), self.Symbol('SPY')).run()
        self.SPY_mom = self.MOM('SPY', 10, Resolution.Daily).Current.Value
        
        self.take_profit()
                        
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Invalid:
            self.Log(str(orderEvent))
            
        if orderEvent.Status == OrderStatus.Filled: 
            order = self.Transactions.GetOrderById(orderEvent.OrderId)
            if order.Tag == 'pt':  # If hit profit target, update stop order quantity
                updateSettings = UpdateOrderFields()
                updateSettings.Quantity = self.stops[orderEvent.Symbol].Quantity - orderEvent.Quantity
                self.stops[orderEvent.Symbol].Update(updateSettings)
    
            elif order.Tag == 'sl': # If hit stop loss, cancel profit target orders
                self.Transactions.CancelOpenOrders(orderEvent.Symbol, "Hit stop price")
    
    def technical_setup(self, i):
        x = re.sub('[(){}<>| ]', '', str(i))
        self.AddEquity(x, Resolution.Daily)
        self.History(self.Symbol(x), 200, Resolution.Daily)
        if self.EMA(x, 50, Resolution.Daily).Current.Value >= self.EMA(x, 200, Resolution.Daily).Current.Value:
            if self.RSI(x, 14, Resolution.Daily).Current.Value < 30:
                return x
    
    def take_profit(self):
        if self.Portfolio.TotalUnrealizedProfit > (0.2 * self.Portfolio.TotalPortfolioValue):
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            stocks_invested_by_profit = sorted(stocks_invested, key=lambda x: self.Portfolio[x].UnrealizedProfit, reverse=True)
            for stock in stocks_invested_by_profit:
                holding = self.Portfolio[stock].Quantity
                avg_price = self.Portfolio[stock].AveragePrice
                holdings_profit = self.Portfolio[stock].UnrealizedProfit
                holdings_cost = avg_price * holding
                if stock in self.shorts:
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -holding)
                elif stock in self.longs:
                    half_holding = int(holding/2.0)
                    if holdings_profit >= holdings_cost * 1.5:
                        self.MarketOrder(stock, -half_holding)
        elif self.longs and self.shorts:
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            # liquidate stocks not in the trading list
            for stock in stocks_invested:
                holding = self.Portfolio[stock].Quantity
                avg_price = self.Portfolio[stock].AveragePrice
                holdings_profit = self.Portfolio[stock].UnrealizedProfit
                holdings_cost = avg_price * holding
                if holdings_profit > holdings_cost * 1.5:
                        self.Liquidate(stock)
        elif self.SPY_mom <= 0.0:
            for stock in self.Portfolio:
                try:
                    if stock.Value.Invested:
                        self.Liquidate(stock)
                except:
                    pass
    
    def update_ticket(self, stock):
        """
        Uses mean reversion to update stop loss and limit orders.
        """
        self.mean = self.EMA(stock, 20, Resolution.Daily)
        self.atr = self.ATR(stock, 20, Resolution.Daily)
        # Mean reversion when price is too low
        if self.Securities[stock].Price < self.mean.Current.Value - 2.0 * self.atr.Current.Value:
            holding = self.Portfolio[stock].Quantity
            marketTicket = self.MarketOrder(stock, quantity)
            limitTicket = self.LimitOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            stopTicket = self.StopMarketOrder(stock, -self.Portfolio[stock].Quantity, self.Securities[stock].Price - self.atr.Current.Value)
    
        # Mean reversion when price is too high
        if self.Securities[stock].Price > self.mean.Current.Value + 2.0 * self.atr.Current.Value:
            holding = self.Portfolio[stock].Quantity
            marketTicket = self.MarketOrder(stock, -holding)
            limitTicket = self.LimitOrder(stock, self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            stopTicket = self.StopMarketOrder(stock, self.Portfolio[stock].Quantity, self.Securities[stock].Price + self.atr.Current.Value)
            
            
    def TradeOptions(self, symbol):
        equity = self.AddEquity(symbol, Resolution.Minute)
        option = self.AddOption(symbol, Resolution.Minute)
        self.symbol = option.Symbol
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        option.SetFilter(-2, +2, timedelta(0), timedelta(60))
        # use the underlying equity as the benchmark
        self.SetBenchmark(equity.Symbol)
        self.call = symbol # Initialize the call contract
        
        if slice.OptionChains.Count == 0: return   
        for i in slice.OptionChains:
            if i.Key != self.symbol: continue
            chain = i.Value
            call = [x for x in chain if x.Right == 0] # filter the call options contracts
            # sorted the contracts according to their expiration dates and choose the ATM options
            contracts = sorted(sorted(call, key = lambda x: x.Expiry, reverse=True), 
                                            key = lambda x: abs(chain.Underlying.Price - x.Strike))
    
            if len(contracts) == 0: return    
            contract = contracts[0] 
            self.call = contract.Symbol
            
            if self.Securities[self.call].Price < (0.01 * self.Portfolio.TotalPortfolioValue):
                num_contracts = int((self.Portfolio.TotalPortfolioValue * 0.01)/self.Securities[self.call].Price)
                
            #if num_contracts > 0:
            self.Sell(symbol, num_contracts) # short the call options
            if self.Portfolio[symbol].Quantity == 0:
                self.Buy(symbol, 100)     # buy 100 the underlying stock
                self.Log("The stock price at time 0 S(0): {}".format(self.Securities[symbol].Price)) 
                
    def MarketOpen(self):
        return self.Time.hour != 0 and self.Time.minute == 1
from System import *
from QuantConnect import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.Market import *
from QuantConnect.Orders import OrderStatus
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Indicators import *
import numpy as np
from datetime import timedelta, datetime

### <summary>
### Example structure for structuring an algorithm with indicator and consolidator data for many tickers.
### </summary>
### <meta name="tag" content="consolidating data" />
### <meta name="tag" content="indicators" />
### <meta name="tag" content="using data" />
### <meta name="tag" content="strategy example" />
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):
        
        # This is the period of bars we'll be creating
        BarPeriod = TimeSpan.FromMinutes(10)
        # This is the period of our sma indicators
        SimpleMovingAveragePeriod = 10
        # This is the number of consolidated bars we'll hold in symbol data for reference
        RollingWindowSize = 10
        # Holds all of our data keyed by each symbol
        self.Data = {}
        # Contains all of our equity symbols
        EquitySymbols = ["AAPL","SPY","IBM"]
        
        self.SetStartDate(2014, 12, 1)
        self.SetEndDate(2015, 2, 1)
        
        # 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 a consolidator to consolidate data for this symbol on the requested period
            consolidator = TradeBarConsolidator(BarPeriod) if symbolData.Symbol.SecurityType == SecurityType.Equity else QuoteBarConsolidator(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].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]
            # this check proves that this symbol was JUST updated prior to this OnData function being called
            if symbolData.IsReady() and symbolData.WasJustUpdated(self.Time):
                if not self.Portfolio[symbol].Invested:
                    self.MarketOrder(symbol, 1)

    # 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):
        
        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
# Your New Python File
# Your New Python File
# Your New Python File
import pandas as pd
import numpy as np

class SpyAnalysis:
    """
    Bullish Count > 3. Max 5
    Bearish Count > 3. Max 8
    """
    def __init__(self, symbol, *args, **kwargs):
        super(SpyAnalysis, self).__init__()
        self.symbol = symbol
        self.count = 0
        self.tolerance = 0.00015

        # EMA Cross
        fastest = self.EMA(self.symbol, 14, Resolution.Daily).Current.Value
        fast = self.EMA(self.symbol, 21, Resolution.Daily).Current.Value
        slow = self.EMA(self.symbol, 50, Resolution.Daily).Current.Value
        base = self.SMA(self.symbol, 200, Resolution.Daily).Current.Value
        if fastest > fast * (1 + self.tolerance):
            self.count += 1
            if fast > slow * (1 + self.tolerance):
                self.count += 1
                if slow > base * (1 + self.tolerance):
                    self.count += 1
        elif fastest < fast * (1 + self.tolerance):
            self.count -= 1
            if fast < slow * (1 + self.tolerance):
                self.count -= 1
                if slow < base * (1 + self.tolerance):
                    self.count -= 1
        
        # RSI and RSI Crossover
        for period in [14, 21, 50, 200]:
            rsi = self.RSI(self.symbol, period, Resolution.Daily).Current.Value
            rsiAvg = IndicatorExtensions.SMA(rsi, period).Current.Value
            if rsi < 25:
                if period == 200:
                    self.count += 3
                elif period in [21, 50]:
                    self.count += 2
                else:
                    self.count += 1
            elif (25 < rsi) and (rsi < 50):
                if period == 200:
                    self.count += 3
                elif period in [21, 50]:
                    self.count += 2
                else:
                    self.count += 1
            elif (50 < rsi) and (rsi < 75):
                if period == 200:
                    self.count -= 2
                elif period in [21, 50]:
                    self.count -= 2
                else:
                    self.count -= 1
            elif rsi > 80:
                if period == 200:
                    self.count -= 3
                elif period in [21, 50]:
                    self.count -= 2
                else:
                    self.count -= 1
            if rsi > rsiAvg:
                if period == 200:
                    self.count += 3
                elif period in [21, 50]:
                    self.count += 2
                else:
                    self.count += 1
            elif rsiAvg > rsi:
                if period == 200:
                    self.count -= 3
                elif period in [21, 50]:
                    self.count -= 2
                else:
                    self.count -= 1
        
        # Momentum
        for period in [14, 21, 50, 200]:
            mom = self.MOM(self.symbol, period, Resolution.Daily).Current.Value
            mean = self.SMA(self.symbol, period, Resolution.Daily).Current.Value
            if mom > mean:
                if period == 200:
                    self.count += 3
                elif period in [21, 50]:
                    self.count += 2
                else:
                    self.count += 1
            elif mean > mom:
                if period == 200:
                    self.count -= 3
                elif period in [21, 50]:
                    self.count -= 2
                else:
                    self.count -= 1
        
        # Ultimate Oscillator
        ultosc = self.ULTOSC(self.symbol, 7, 14, 28, Resolution.Daily).Current.Value
        if ultosc < 25:
            self.count += 3
        elif (25 < ultosc) and (ultosc < 50):
            self.count += 1
        elif (25 < ultosc) and (ultosc < 50):
            self.count -= 1
        elif ultosc > 80:
            self.count -= 3
            
        return self.count
# Your New Python File
# Your New Python File
import os, sys, copy
import numpy as np

class LongTermAlgos:
    """
    This function deploys and employs various trading strategies to arrive at the best
    decision to buy/sell/hold a stock.
    """
    def __init__(self, data, *args, **kwargs):
        """
        :param data:
        :param args:
        :param kwargs:
        """
        super(LongTermAlgos, self).__init__()
        self.data = data
        self.algos = {}

        # import libraries
        from MeanReversion.main import MeanReversion
        from StatisticalArbitrage.main import StatsArbitrage
        from CrowdSourcing.main import CrowdSource
        from MachineLearning.main import MachineLearning
        from Momentum.main import Momentum
        from TrendFollowing.main import TrendFollowing
        from MarketMaking.main import MarketMaking
        from SentimentAnalysis.main import Sentiment

        self.algos['MeanReversion'] = MeanReversion
        self.algos['StatsticalArbitrage'] = StatsticalArbitrage
        self.algos['CrowdSourcing'] = CrowdSourcing
        self.algos['MachineLearning'] = MachineLearning
        self.algos['Momentum'] = Momentum
        self.algos['TrendFollowing'] = TrendFollowing
        self.algos['MarketMaking'] = MarketMaking
        self.algos['SentimentAnalysis'] = SentimentAnalysis


    def run(self):
        """
        :return:
        """
        for algo in self.algos.keys():
            trading_strategy = self.algos[algo](data = self.data)
            results = trading_strategy.run()

# Your New Python File