Overall Statistics
Total Trades
219
Average Win
0.17%
Average Loss
-0.16%
Compounding Annual Return
39.611%
Drawdown
2.200%
Expectancy
0.165
Net Profit
3.342%
Sharpe Ratio
2.663
Loss Rate
42%
Win Rate
58%
Profit-Loss Ratio
1.02
Alpha
0.144
Beta
8.896
Annual Standard Deviation
0.113
Annual Variance
0.013
Information Ratio
2.507
Tracking Error
0.113
Treynor Ratio
0.034
Total Fees
$293.29
from clr import AddReference
AddReference("System.Core")
AddReference("System.Collections")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")

from System import *
from System.Collections.Generic import List
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
import numpy as np
class VerticalCalibratedRegulators(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 3, 1)  # Set Start Date
        self.SetEndDate(2019, 4, 5)
        self.SetCash(100000)  # Set Strategy Cash
        # self.AddEquity("SPY", Resolution.Minute)
        self.__numberOfSymbols = 100
        self.__numberOfSymbolsFine = 5
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)

        self.smav = {}
        self.rsi = {}
        self.adx = {}
        self.atr = {}
        self.sma = {}
        self.selectedSymbols = []
        self._changes = None
        
    # sort the data by daily dollar volume and take the top 'NumberOfSymbols'
    def CoarseSelectionFunction(self, coarse):
        
        filtered = [ x for x in coarse if x.HasFundamentalData and x.Price > 1 and x.DollarVolume > 2500000 ]
        sortedByDollarVolume = sorted(filtered, key=lambda x: x.DollarVolume, reverse=True)
        
        # return the symbol objects of the top entries from our sorted collection
        return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ]

    
    # sort the data by P/E ratio and take the top 'NumberOfSymbolsFine'
    def FineSelectionFunction(self, fine):
        # sort descending by P/E ratio
        sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.PERatio, reverse=True)

        ## Retrieve 20 days of historical data for each symbol
        symbols = [x.Symbol for x in sortedByPeRatio]
        history = self.History(symbols, 150, Resolution.Daily)
        ## Iterate through symbols
        for symbol in symbols:
            ## Find hsitory for specific symbol
            if str(symbol) in history.index.get_level_values(0):
                symbolVolumeHistory = history.loc[str(symbol)]
                if symbolVolumeHistory.empty:
                    self.Log("EMPTY dataframe!")
    
                ## Create SMA for symbol and register it with algorithm
                else:
                    symbolSMAv = SimpleMovingAverage(50)
                    symbolRSI = RelativeStrengthIndex(3)
                    symbolADX = AverageDirectionalIndex(7)
                    symbolATR = AverageTrueRange(10)
                    symbolSMA = SimpleMovingAverage(150)
    
                # Iterate through historical data
                for tuple in symbolVolumeHistory.itertuples():
                    # notice: should add symbol in the TradeBar
                    bar = TradeBar(tuple.Index, symbol, tuple.open, tuple.high, tuple.low, tuple.close, tuple.volume)     
                    ## Update SMA with data time and volume
                    symbolSMAv.Update(tuple.Index, tuple.volume)
                    symbolRSI.Update(tuple.Index, tuple.close)
                    symbolADX.Update(bar)
                    symbolATR.Update(bar)
                    symbolSMA.Update(tuple.Index, tuple.close)
                
                self.Log(f'{symbol.Value} SMAv: {symbolSMAv.Current.Value}')  
                self.Log(f'{symbol.Value} RSI: {symbolRSI.Current.Value}')
                self.Log(f'{symbol.Value} ADX: {symbolADX.Current.Value}')
                self.Log(f'{symbol.Value} ATR: {symbolATR.Current.Value}')
                self.Log(f'{symbol.Value} SMA: {symbolSMA.Current.Value}')
                    
                ## Add SMA to dictionary so you can access it later
                self.smav[symbol] = symbolSMAv
                self.rsi[symbol] = symbolRSI
                self.adx[symbol] = symbolADX
                self.atr[symbol] = symbolATR
                self.sma[symbol] = symbolSMA
                #self.Debug(f' {symbol.Value} Price ' + str(symbolVolumeHistory['close'][-1]) + 'SMA' + str(self.sma[symbol]))
            else:
                symbols.pop(symbols.index(symbol))

        ## Perform SMA filtering conditions and select/return the symbols you want to add to your universe
        ## Fine Selection will use only these ones
        
        self.selectedSymbols = [ x for x in symbols if self.smav[x].Current.Value > 500000 and self.rsi[x].Current.Value < 30 and history.loc[str(x)]['close'][-1] > self.sma[x].Current.Value  ]
        
        return self.selectedSymbols
        
    def OnData(self, data):
        # if we have no changes, do nothing
        if self._changes is None: return

        # liquidate removed securities
        for security in self._changes.RemovedSecurities:
            if security.Invested:
                self.Liquidate(security.Symbol)

        # we want 20% allocation in each security in our universe
        for security in self._changes.AddedSecurities:
            self.SetHoldings(security.Symbol, 0.1)

        self._changes = None


    # this event fires whenever we have changes to our universe
    def OnSecuritiesChanged(self, changes):
        self._changes = changes