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)