Overall Statistics
# Your New Python File
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data import *
from QuantConnect.Data.Market import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import *
import numpy as np
from datetime import datetime


class VolumeWeightedAveragePriceExecutionModel(ExecutionModel):
    '''Execution model that submits orders while the current market price is 
    more favorable that the current volume weighted average price.'''

    def __init__(self):
        '''Initializes a new instance of the VolumeWeightedAveragePriceExecutionModel class'''
        self.targetsCollection = PortfolioTargetCollection()
        self.symbolData = {}

        # Gets or sets the maximum order quantity as a percentage of the current bar's volume.
        # This defaults to 0.01m = 1%. For example, if the current bar's volume is 100,
        # then the maximum order size would equal 1 share.
        self.MaximumOrderQuantityPercentVolume = 0.01


    def Execute(self, algorithm, targets):
        '''Executes market orders if the standard deviation of price is more
        than the configured number of deviations in the favorable direction.
        Args:
           algorithm: The algorithm instance
           targets: The portfolio targets'''

        # update the complete set of portfolio targets with the new targets
        self.targetsCollection.AddRange(targets)

        # for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call
        if self.targetsCollection.Count > 0:
            for target in self.targetsCollection.OrderByMarginImpact(algorithm):
                symbol = target.Symbol

                # calculate remaining quantity to be ordered
                unorderedQuantity = OrderSizing.GetUnorderedQuantity(algorithm, target)

                # fetch our symbol data containing our VWAP indicator
                data = self.symbolData.get(symbol, None)
                if data is None: return

                # check order entry conditions
                if self.PriceIsFavorable(data, unorderedQuantity):
                    # get the maximum order size based on total order value
                    maxOrderSize = OrderSizing.PercentVolume(data.Security, self.MaximumOrderQuantityPercentVolume)
                    orderSize = np.min([maxOrderSize, np.abs(unorderedQuantity)])

                    remainder = orderSize % data.Security.SymbolProperties.LotSize
                    missingForLotSize = data.Security.SymbolProperties.LotSize - remainder
                    # if the amount we are missing for +1 lot size is 1M part of a lot size
                    # we suppose its due to floating point error and round up
                    # Note: this is required to avoid a diff with C# equivalent
                    if missingForLotSize < (data.Security.SymbolProperties.LotSize / 1000000):
                        remainder -= data.Security.SymbolProperties.LotSize

                    # round down to even lot size
                    orderSize -= remainder
                    if orderSize != 0:
                        algorithm.MarketOrder(symbol, np.sign(unorderedQuantity) * orderSize)

            self.targetsCollection.ClearFulfilled(algorithm)


    def OnSecuritiesChanged(self, algorithm, changes):
        '''Event fired each time the we add/remove securities from the data feed
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm'''
        for removed in changes.RemovedSecurities:
            # clean up removed security data
            if removed.Symbol in self.symbolData:
                if self.IsSafeToRemove(algorithm, removed.Symbol):
                    data = self.symbolData.pop(removed.Symbol)
                    algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator)

        for added in changes.AddedSecurities:
            if added.Symbol not in self.symbolData:
                self.symbolData[added.Symbol] = SymbolData(algorithm, added)


    def PriceIsFavorable(self, data, unorderedQuantity):
        '''Determines if the current price is more than the configured
       number of standard deviations away from the mean in the favorable direction.'''
        if unorderedQuantity > 0:
            if data.Security.BidPrice < data.VWAP:
                return True
        else:
            if data.Security.AskPrice > data.VWAP:
                return True

        return False

    def IsSafeToRemove(self, algorithm, symbol):
        '''Determines if it's safe to remove the associated symbol data'''
        # confirm the security isn't currently a member of any universe
        return not any([kvp.Value.ContainsMember(symbol) for kvp in algorithm.UniverseManager])

class SymbolData:
    def __init__(self, algorithm, security):
        self.Security = security
        self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, security.Resolution)
        name = algorithm.CreateIndicatorName(security.Symbol, "VWAP", security.Resolution)
        self.vwap = IntradayVwap(name)
        algorithm.RegisterIndicator(security.Symbol, self.vwap, self.Consolidator)

    @property
    def VWAP(self):
       return self.vwap.Value

class IntradayVwap:
    '''Defines the canonical intraday VWAP indicator'''
    def __init__(self, name):
        self.Name = name
        self.Value = 0.0
        self.lastDate = datetime.min
        self.sumOfVolume = 0.0
        self.sumOfPriceTimesVolume = 0.0

    @property
    def IsReady(self):
        return self.sumOfVolume > 0.0

    def Update(self, input):
        '''Computes the new VWAP'''
        success, volume, averagePrice = self.GetVolumeAndAveragePrice(input)
        if not success:
            return self.IsReady

        # reset vwap on daily boundaries
        if self.lastDate != input.EndTime.date():
            self.sumOfVolume = 0.0
            self.sumOfPriceTimesVolume = 0.0
            self.lastDate = input.EndTime.date()

        # running totals for Σ PiVi / Σ Vi
        self.sumOfVolume += volume
        self.sumOfPriceTimesVolume += averagePrice * volume

        if self.sumOfVolume == 0.0:
           # if we have no trade volume then use the current price as VWAP
           self.Value = input.Value
           return self.IsReady

        self.Value = self.sumOfPriceTimesVolume / self.sumOfVolume
        return self.IsReady

    def GetVolumeAndAveragePrice(self, input):
        '''Determines the volume and price to be used for the current input in the VWAP computation'''

        if type(input) is Tick:
            if input.TickType == TickType.Trade:
                return True, float(input.Quantity), float(input.LastPrice)

        if type(input) is TradeBar:
            if not input.IsFillForward:
                averagePrice = float(input.High + input.Low + input.Close) / 3
                return True, float(input.Volume), averagePrice

        return False, 0.0, 0.0
import re

from PivotPoints import PivotPointsFloor

class LiquidETFAlpha(AlphaModel):
    def __init__(self, time, scheduler, daterules, timerules, debug):
        self.lea   = []
        self.mom   = []
        self.vwapd = []
        self.pivots = []
        self.Time = time
        self.securities = []
        self.Schedule = scheduler
        self.DateRules = daterules
        self.TimeRules = timerules
        self.Debug = debug
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(11,30), self.ShowData)
        
    def OnSecuritiesChanged(self, algorithm, changes):
        
        for security in changes.AddedSecurities:
            
            self.securities.append(security)
            
            symbol = security.Symbol
            self.mom.append({
                "symbol": symbol, 
                "indicator": algorithm.MOM(symbol, 30, Resolution.Minute)
            })
            self.vwapd.append({
                "symbol": symbol,
                "indicator": algorithm.VWAP(symbol, 1, Resolution.Minute)
            })
            self.pivots.append({
                "symbol": symbol,
                "indicator": PivotPointsFloor(symbol, Resolution.Daily)
            })
            algorithm.RegisterIndicator(self.pivots[-1]['symbol'], self.pivots[-1]['indicator'], Resolution.Daily)
    
    def ShowData(self):
        
        for security in self.vwapd:
            symbol = security['symbol']
            val = security['indicator'].Current.Value
            if re.match("^QQQ.*", str(symbol)):
                self.Debug( f"{self.Time} - {symbol} vwap: {val}" )
        
        for security in self.pivots:
            if security['indicator'].IsReady:
                symbol = security['symbol']
                val = security['indicator']
                if re.match("^QQQ.*", str(symbol)):
                    self.Debug( f"{self.Time} - {symbol} pivots: {val}" )

    def Update(self, algorithm, data):
        #2. Sort the list of dictionaries by indicator in descending order
        #ordered = sorted(self.mom, key=lambda kv: kv['indicator'].Current.Value, reverse=True)
        #3. Return a group of insights, emitting InsightDirection.Up for the first item of ordered, and InsightDirection.Flat for the second
        #return Insight.Group([
        #    Insight.Price(ordered[0]['symbol'], timedelta(1), InsightDirection.Up),
        #    Insight.Price(ordered[1]['symbol'], timedelta(1), InsightDirection.Flat)
        #])
        self.Time = algorithm.Time
        insights = [ ]
        
        #for security in self.securities:
            #if security.Symobl in data.keys():
                #pivot = [pivot for pivot in self.pivots if pivot['symbol'] == security.Symbol and pivot['indicator'].IsReady]
                #if pivot is not None:
                    #if data[security.Symbol].Low < pivot.Current.s3 and data[symbol].High > pivot.Current.s3:
                        #magnitude = (pivot.Current.s2 - pivot.Current.s3) / data[security.Symbol].Close
                        #insights.append(Insight(security.Symbol, 240, InsightType.Price, InsightDirection.Up, magnitude, 0.5))
            
        return Insight.Group( insights )
class PivotPointsFloor:
    def __init__(self, name, resolution, deviation=2):
        self.Name = name
        self.Time = datetime.min
        self.IsReady = False
        self.res = resolution
        self.hldev = deviation
        self.Value = 0
        ##
        # Extensive accessors
        self.r5 = None
        self.r4 = None
        self.r3 = None
        self.r2 = None
        self.r1 = None
        self.pp = None
        self.s1 = None
        self.s2 = None
        self.s3 = None
        self.s4 = None
        self.s5 = None
    
    def __str__(self):
        return self.__repr__()
    
    def __repr__(self):
        return "{{'Name':{0}, 'IsReady':{1}, 'Time': {2}, 'Values':{3} }}".format(self.Name, self.IsReady, self.Time, self.ValuesStr() )
        
    def Update(self, input):
        self.Time = input.EndTime
        
        self.pp = (input.High + input.Low + input.Close)/3
        
        self.r1 = self.pp*self.hldev - input.Low
        self.r2 = self.pp + input.High - input.Low
        self.r3 = input.High + self.hldev*(self.pp - input.Low)
        self.r4 = self.r3 - self.r2 + self.r3
        self.r5 = self.r3 - self.r2 + self.r4
        
        self.s1 = self.pp*self.hldev - input.High
        self.s2 = self.pp - input.High + input.Low
        self.s3 = input.Low - self.hldev*(input.High-self.pp)
        self.s4 = self.s3 - self.s2 + self.s3
        self.s5 = self.s3 - self.s2 + self.s4
        
        self.IsReady = True
        self.Value = self.pp
    
    def ValuesStr(self):
        return "({0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10})".format(self.r5, self.r4, self.r3, self.r2, self.r1, self.pp, self.s1, self.s2, self.s3, self.s4, self.s5)
class MaximumDrawdownPercentPerSecurity(RiskManagementModel):
    '''Provides an implementation of IRiskManagementModel that limits the drawdown per holding to the specified percentage'''

    def __init__(self, maximumDrawdownPercent = 0.05):
        '''Initializes a new instance of the MaximumDrawdownPercentPerSecurity class
        Args:
            maximumDrawdownPercent: The maximum percentage drawdown allowed for any single security holding'''
        self.maximumDrawdownPercent = -abs(maximumDrawdownPercent)

    def ManageRisk(self, algorithm, targets):
        '''Manages the algorithm's risk at each time step
        Args:
            algorithm: The algorithm instance
            targets: The current portfolio targets to be assessed for risk'''
        targets = []
        for kvp in algorithm.Securities:
            security = kvp.Value

            if not security.Invested:
                continue

            pnl = security.Holdings.UnrealizedProfitPercent
            if pnl < self.maximumDrawdownPercent:
                # liquidate
                targets.append(PortfolioTarget(security.Symbol, 0))

        return targets
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel

from Alpha import LiquidETFAlpha
#from ExecutionManager import VolumeWeightedAveragePriceExecutionModel
from RiskManager import MaximumDrawdownPercentPerSecurity

from datetime import timedelta

class MultidimensionalTachyonReplicator(QCAlgorithm):

    def Initialize(self):
        # Set Start Date so that backtest has 5+ years of data
        #self.SetStartDate(2014, 11, 1)
        self.SetStartDate(2019, 11, 1)
        #self.SetStartDate(2015, 11, 1)
        #self.SetEndDate(2015, 12, 31)
        
        self.SetCash(1000000)
        self.AddEquity('SPY')
        self.SetBenchmark('SPY') # Required
        self.SetBrokerageModel(AlphaStreamsBrokerageModel()) # Don't change
        ##
        # Universe
        self.UniverseSettings.Resolution = Resolution.Minute
        self.SetUniverseSelection(LiquidETFUniverse())
        ##
        # Alpha
        self.SetAlpha(LiquidETFAlpha(
            self.Time,
            self.Schedule,
            self.DateRules,
            self.TimeRules,
            self.Debug
        ))
        
        ##
        # Management
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
        self.SetRiskManagement(MaximumDrawdownPercentPerSecurity())
        self.SetExecution(ImmediateExecutionModel())
        #self.SetExecution(VolumeWeightedAveragePriceExecutionModel())


    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
        '''
        #if not self.Portfolio.Invested:
        #  self.SetHoldings("SPY", 1)
        pass

    def CoarseSelectionFunction(self, universe):
        selected = []
        universe = sorted(universe, key=lambda c: c.DollarVolume, reverse=True)
        universe = [c for c in universe if c.Price > 10][:100]

        for coarse in universe:
            symbol = coarse.Symbol

            if symbol not in self.averages:
                # 1. Call history to get an array of 200 days of history data
                history = self.History(symbol, 200, Resolution.Daily)

                #2. Adjust SelectionData to pass in the history result
                self.averages[symbol] = SelectionData(history)

            self.averages[symbol].update(self.Time, coarse.AdjustedPrice)

            if  self.averages[symbol].is_ready():
                if self.averages[symbol].fast > self.averages[symbol].slow:
                    selected.append(symbol)

        return selected[:10]

    def OnSecuritiesChanged(self, changes):
        pass
        #for security in changes.RemovedSecurities:
        #   self.Liquidate(security.Symbol)
        #for security in changes.AddedSecurities:
        #    self.SetHoldings(security.Symbol, 0.10)