Overall Statistics
Total Trades
260
Average Win
2.30%
Average Loss
-1.23%
Compounding Annual Return
47.275%
Drawdown
31.600%
Expectancy
0.313
Net Profit
66.903%
Sharpe Ratio
1.36
Probabilistic Sharpe Ratio
55.938%
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
1.88
Alpha
0.496
Beta
-0.157
Annual Standard Deviation
0.337
Annual Variance
0.114
Information Ratio
0.479
Tracking Error
0.459
Treynor Ratio
-2.926
Total Fees
$351.39
Estimated Strategy Capacity
$19000000.00
import math

class NadionHorizontalFlange(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2020, 1, 1)

        #Cash to invest
        self.SetCash(100000)


        self.SetWarmUp(45)
        

        self.totalTradable = 5
        

        self.positionSize = 1/self.totalTradable
        

        self.symbolDataBySymbol = {}
        

        self.washTimer = {}
        

        self.sellTimer = {}
        

        self.buyPrice = {}
        

        self.atrAtPurchase = {}
        

        self.lastMonth = -1
        

        self.AddUniverse(self.Coarse, self.Fine)
        

        self.UniverseSettings.Resolution = Resolution.Daily
        

        self.Schedule.On(self.DateRules.EveryDay(),
                 self.TimeRules.At(0, 0),
                 self.reduceWash)
        
        
        self.Schedule.On(self.DateRules.EveryDay(),
                self.TimeRules.At(0, 0),
                self.reduceSellTimer)     
                

        
    def Coarse(self, coarse):
     

        if self.Time.month == self.lastMonth:
            return Universe.Unchanged
        self.lastMonth = self.Time.month
        

        sortedByVolume = sorted([x for x in coarse if x.Price > 5], key = lambda x: x.DollarVolume, reverse = True)
        

        return [x.Symbol for x in sortedByVolume]
    
    def Fine(self, fine):

        sortedBySector = sorted([x for x in fine if x.CompanyReference.CountryId == "USA"
                                        and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"]
                                        and (self.Time - x.SecurityReference.IPODate).days > 180
                                        and x.MarketCap > 3e8],
                               key = lambda x: x.CompanyReference.IndustryTemplateCode)
        sortedBySector = sorted([x for x in sortedBySector], key = lambda x: x.MarketCap, reverse = True)[:50]

        return [x.Symbol for x in sortedBySector]

        
    def OnSecuritiesChanged(self, changes):
 
        for x in changes.AddedSecurities:
            symbol = x.Symbol

            smaFast = self.SMA(symbol, 10, Resolution.Daily)
            smaSlow = self.SMA(symbol, 20, Resolution.Daily)
            atr = self.ATR(symbol, 45, Resolution.Daily)
            history = self.History(symbol, 45, Resolution.Daily)

            for tuple in history.loc[symbol].itertuples():

                smaFast.Update(tuple.Index, tuple.close)
                smaSlow.Update(tuple.Index, tuple.close)

            symbolData = SymbolData(symbol, smaFast, smaSlow, atr)
            self.symbolDataBySymbol[symbol] = symbolData


            self.washTimer[symbol] = 0
 
            self.sellTimer[symbol] = 0

    def OnData(self, data):

        if self.IsWarmingUp: 
           return
        

        for symbol, symbolData in self.symbolDataBySymbol.items():

        

            if self.washTimer[symbol] > 0:
                continue

            smaFast = symbolData.SMAFast
            smaSlow = symbolData.SMASlow
            atr = symbolData.ATR
  

            if not self.Portfolio[symbol].Invested:
                if smaFast.Current.Value > smaSlow.Current.Value:
 
                    self.SetHoldings(symbol, self.positionSize)
                    self.sellTimer[symbol] = 150
                    self.buyPrice[symbol] = self.Securities[symbol].Close
                    self.atrAtPurchase[symbol] = atr.Current.Value

            if self.Portfolio[symbol].Invested:
                if self.sellTimer[symbol] <= 0:
                    if (self.Portfolio[symbol].UnrealizedProfit < 0):
                        self.washTimer[symbol] = 31
                    self.Liquidate(symbol)

                    
                elif self.Securities[symbol].Close >= (self.buyPrice[symbol] + (4 * self.atrAtPurchase[symbol])):
                    if (self.Portfolio[symbol].UnrealizedProfit < 0):
                        self.washTimer[symbol] = 31
                    self.Liquidate(symbol)
                    
                elif self.Securities[symbol].Close <= (self.buyPrice[symbol] - (2 * self.atrAtPurchase[symbol])):
                    if (self.Portfolio[symbol].UnrealizedProfit < 0):
                        self.washTimer[symbol] = 31
                    self.Liquidate(symbol)

                    
    def reduceWash(self):
        for symbol, count in self.washTimer.items():
            if count > 0:
                self.washTimer[symbol] -= 1
                
    def reduceSellTimer(self):
         for symbol, count in self.sellTimer.items():
            if count > 0:
                self.sellTimer[symbol] -= 1                
                    


            
class SymbolData:
      def __init__(self, symbol, smaFast, smaSlow, atr):
        self.SMAFast = smaFast
        self.SMASlow = smaSlow
        self.ATR = atr