Overall Statistics
Total Trades
525
Average Win
0.21%
Average Loss
-0.29%
Compounding Annual Return
70.073%
Drawdown
24.900%
Expectancy
-0.143
Net Profit
24.479%
Sharpe Ratio
1.615
Probabilistic Sharpe Ratio
55.890%
Loss Rate
50%
Win Rate
50%
Profit-Loss Ratio
0.70
Alpha
0
Beta
0
Annual Standard Deviation
0.449
Annual Variance
0.202
Information Ratio
1.615
Tracking Error
0.449
Treynor Ratio
0
Total Fees
$525.00
Estimated Strategy Capacity
$3400000.00
class TrialHighalgorithm(QCAlgorithm):
        
        class SymbolData(object):
    
            def __init__(self, symbol, algorithm):
                self.Symbol = symbol
                self.algorithm = algorithm # reference to the algorithm object so we can make a history call
                
                # this is the buy property that we will use in OnData to filter the symbols that meet our criteria
                self.buy = False
                self.symbolSma = SimpleMovingAverage(200) 
                
                # init windows, most recent value is self.highs[0], second most recent is self.highs[1], etc...
                self.highs = RollingWindow[float](252)
                self.opens = RollingWindow[float](252)
                self.closes = RollingWindow[float](252)
        
                history = algorithm.History(symbol, 252, Resolution.Daily)
                for index, row in history.loc[symbol].iterrows():
                    self.update(index, row["high"], row["open"], row["close"])
                    
            # update windows, sma
            def update(self, time, high, opn, close):
                self.highs.Add(high)
                self.opens.Add(opn)
                self.closes.Add(close)
                self.symbolSma.Update(time, close)
                
                # add [0] just so that list is not empty during initializing phase
                self.buy = (max((list(self.highs) + [0])[1:]) < self.highs[0]) & (self.closes[0] > self.opens[0])
                    

        def Initialize(self):
            self.SetStartDate(2020, 11, 1)
            #self.SetEndDate(2020, 11, 11)
            self.SetCash(10000) 
            self.numberOfSymbols = 200
            
            self.res = Resolution.Daily
            
            self.averages = {}
            self.symbols = []
            self.sma = {}
            self.universe = {}
            self.selectedSymbols = []
            
            self.SPY = self.AddEquity('SPY', self.res).Symbol
            
            self.SetTimeZone(TimeZones.HongKong)
            self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
            
            self.AddUniverse(self.CoarseSelectionFunction)
            self.UniverseSettings.Resolution = self.res

        def CoarseSelectionFunction(self, coarse):

            filtered = [ x for x in coarse if (x.HasFundamentalData) and (x.Price > 1) and ( x.Volume > 500000) and (x.DollarVolume > 100000) ]
            filtered.sort(key=lambda x: x.DollarVolume, reverse=True)
            
            symbols = [ x.Symbol for x in filtered[:self.numberOfSymbols] ]
            
            for symbol in symbols:
                if symbol not in self.universe:
                    self.universe[symbol] = TrialHighalgorithm.SymbolData(symbol, self)
                    self.sma[symbol] =  self.universe[symbol].symbolSma
                
            return list(self.universe.keys())


        # this is called daily because our resolution is Resolution.Daily
        def OnData(self, data):
    
            # update all the securities in our universe using the latest hihg, open, close data
            for symbol in self.universe.keys():
                
                # make sure we have data, because sometimes we dont
                if self.Securities.ContainsKey(symbol) and self.Securities[symbol] != None:
                    
                    time = self.Time
                    high = self.Securities[symbol].High
                    opn = self.Securities[symbol].Open
                    close = self.Securities[symbol].Close
                    
                    # update function
                    self.universe[symbol].update(time, high, opn, close)
            
            # now select all the symbols that meet the buy criteria (this is the 'buy' property of our symboldata object)
            self.selectedSymbols = [x for x in self.universe.keys() if self.universe[x].buy ]
            
            for x in self.selectedSymbols:
                self.SetHoldings(x, 0.01)