Overall Statistics
Total Trades
6
Average Win
0.02%
Average Loss
-0.03%
Compounding Annual Return
0.006%
Drawdown
0.000%
Expectancy
0.139
Net Profit
0.013%
Sharpe Ratio
0.192
Probabilistic Sharpe Ratio
8.470%
Loss Rate
33%
Win Rate
67%
Profit-Loss Ratio
0.71
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
-0.572
Tracking Error
0.227
Treynor Ratio
7.739
Total Fees
$6.67
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

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 main(QCAlgorithm):

    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''

        self.SetStartDate(2018, 8, 20) #Set Start Date
        self.SetEndDate(2020,11,18)    #Set End Date
        
        self.initialcash=1000000 #Set Strategy Cash
        self.SetCash(self.initialcash)         
        self.singleStockAllocationInDollars= -10000 # - , (minus) means going short. -10000 means having a target of going short for an amount of 10000 $
        self.PercentageOfPortfolioToAllocateToEachSecurity = self.singleStockAllocationInDollars/self.initialcash

        self.SetBrokerageModel(BrokerageName.Alpaca)
        self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
        
        self.UniverseSettings.Resolution = Resolution.Hour # Timeframe to trade
        self.UniverseSettings.Leverage = 1
        
        self.benchmark="SPY"
        self.benchmark= self.AddEquity(self.benchmark, self.UniverseSettings.Resolution)
        self.SPY_EMA = self.EMA("SPY", 20, Resolution.Daily) # Filter of Price of SPY should be > 20 EMA to favor long entries, you can change 20
        

        self.SymbolDataDictionary = {}
        self.AddUniverse(self.CoarseSelectionFunction)

        # schedule an event to fire buys on a single day of the week, specifying hours and minutes
        self.Schedule.On(self.DateRules.Every(DayOfWeek.Friday), self.TimeRules.At(15, 50), self.buy_time)
        
        #schedule an event to Liquidate (exit all positions at the day and hours specified)
        self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.At(9, 10), self.sell_time)
        
    def buy_time(self):
        for kvp in self.SymbolDataDictionary:
            symbol=self.SymbolDataDictionary[kvp]
            if self.benchmark.Price > self.SPY_EMA.Current.Value : # Here we do the check of the condition SPY should be over EMA 20 Price of SPY should be > 20 EMA to favor long entries
                self.SetHoldings(kvp, self.PercentageOfPortfolioToAllocateToEachSecurity) #here the actual positions are initiated, in this case the symbols are 10, so every symbol receives 10% of the Portfolio. In this case being the cash 100000$ every stock gets an allocation of 10000$.
                
            
    def sell_time(self):
        self.Liquidate()
        
    
    def CoarseSelectionFunction(self, coarse):
        CoarseWithFundamental = [x for x in coarse if x.HasFundamentalData and x.Price > 1 and x.Price<50] #Price range, between 1 and 50 as in Excel spreadsheet example
        sortedByVolume = sorted(CoarseWithFundamental, key=lambda x: x.DollarVolume, reverse=True)
        # We are going to use a dictionary to refer the object that will keep the moving averages
        for kvp in sortedByVolume:
            if kvp.Symbol not in self.SymbolDataDictionary:
                self.SymbolDataDictionary[kvp.Symbol]=SymbolData(kvp.Symbol)
    
            instrument=self.SymbolDataDictionary[kvp.Symbol]
            instrument.update(kvp.EndTime, kvp.AdjustedPrice, kvp.DollarVolume)
            
        values = list(self.SymbolDataDictionary.values())
        
        ############################## Returns filter
        values = [x for x in values if x.percentage_change > 0.15]  # 0.10 means a 10% return, 0.15 means 15% and so on, you can change this
        
        
        ############################### Relative Volume filter
        values = [x for x in values if x.relative_volume > 0.2]  #you can change this
        
        
        ################################# RSI filter
        values = [x for x in values if x.RSI_IS_OK] 
        
        ################################# EMAs filter
        
        values = [x for x in values if x.EMAS_ARE_OK]
        
        

        return [ x.symbol for x in values]   # return [ x.symbol for x in values[:20] ] this to constrain the number of stocks returned, in this case 20
        
    
    def OnData(self, data): 
        
        
        #Take profit logic
        if self.Portfolio.Invested: 
            if self.Portfolio.TotalPortfolioValue >  self.initialcash* 1.05:# means a 5% take profit target, if the initial portfolio value is 100000 with 1.05 you will take profit when the value of portfolio is greater than 105 000 $.
                self.Liquidate()
        
        
        #Stop loss logic
        if self.Portfolio.Invested: 
            if self.Portfolio.TotalPortfolioValue < self.initialcash*0.90:  # means a 10% stop loss. In this case 0.9 means that the portfolio is valued a 90% of the original value, so if the initial value is 100 000 $ it means 90 000$, a 10% stop loss. if you set self.initialcash*0.5 means a 50% stop loss and so on.
                self.Liquidate()        
        
        #Stop loss on a single instrument logic 
        if self.Portfolio.Invested:
            for symbol in self.ActiveSecurities:
                if self.Portfolio[symbol.Key].UnrealizedProfit < -5000: #This means a stop loss of $5000 for the relative security
                    self.Debug(str(self.Time) + 'Stopping loss due to Unrealized Profit ' + str(self.Portfolio[symbol.Key].UnrealizedProfit) + ' on symbol '+ str(symbol.Key))
                    self.Liquidate(symbol.Key)
            
class SymbolData(object):
    def __init__(self, symbol):
        self.symbol = symbol
        self.EMA1 = ExponentialMovingAverage (2) #here we can decide the values of EMA1, you can change this 
        self.EMA2 = ExponentialMovingAverage (2) #here we can decide the values of EMA2, you can change this 
        self.RSI = RelativeStrengthIndex(200) #here we can decide the values of RSI, you can change this 
        self.PriceHistory = RollingWindow[float](2)# you can't change this
        self.DollarVolumeHistory = RollingWindow[float](30)# you can't change this
        self.percentage_change=0# you can't change this
        self.relative_volume=0# you can't change this
        self.EMAS_ARE_OK=False# you can't change this
        self.RSI_IS_OK=False# you can't change this
        
        

    def update(self, time, value, volume):
        
        if self.EMA1.Update(time, value) and self.EMA2.Update(time, value):# you can't change this
            EMA1 = self.EMA1.Current.Value# you can't change this
            EMA2 = self.EMA2.Current.Value# you can't change this
            self.EMAS_ARE_OK = value > EMA1 and value > EMA2# you can't change this
        
        if self.RSI.Update(time, value):# you can't change this
            RSI = self.RSI.Current.Value# you can't change this
            self.RSI_IS_OK = value > RSI# you can't change this
            
            
        self.PriceHistory.Add(value)
        self.DollarVolumeHistory.Add(volume)
        
       
        if self.PriceHistory.IsReady:# you can't change this
            self.percentage_change = (self.PriceHistory[0]-self.PriceHistory[1])/self.PriceHistory[1]# you can't change this

            
        if self.DollarVolumeHistory.IsReady:# you can't change this
            todays_volume=self.DollarVolumeHistory[0]# you can't change this
            thirtydaysvolume=0# you can't change this
            for i in range(0,self.DollarVolumeHistory.Count-1):# you can't change this
                thirtydaysvolume=self.DollarVolumeHistory[i]+thirtydaysvolume# you can't change this
            averagethirtydaysvolume=thirtydaysvolume/30   #let's divide by 30 # you can't change this
            self.relative_volume=(todays_volume-averagethirtydaysvolume)/averagethirtydaysvolume # you can't change this