I have recently gotten into trading and, though I went through the BootCamp and read through the documentation but I still feel like I have no idea what I'm doing. I guess I just don't have a great grasp of what all of the objects in LEAN are, how to use them properly, and how they all relate. Plus I am a self-taught programmer with little practical experience. In any case, I tried to implement an algorithm which selects equities from the US Market and trades them as follows:

Each day, invest equally in all equities which have reached or surpassed their 52-week high. Every minute for the remainder of the day, check for any other securities which have reached or surpassed the 52-week high to buy them as well. Also, liquidate any of these investments which have dropped below the 52-week high, as well as any investments which have reached above x% of the 52-week high (to secure profits). I know this last part can be done with sell stops/limits but I couldn't figure out how to implement this with everything else I have going on.

It wasn't working out too well (I didn't even finish any backtests because even for just a 1-month backtest, I was already realizing like -25% halfway through) and I'm wondering if maybe I didn't implement it properly. Moreover, the backtests were taking forever and kept giving me errors in the console that I didn't have enough margin. Here's the code if anyone has suggestions.

class VerticalOptimizedThrustAssembly(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 10, 12) # Set Start Date self.SetEndDate(2019, 11, 19) self.SetCash(100000) # Set Strategy Cash self.numCoarse = 500 self.percentToTop = 0.0 # Percent within 52-week high to trigger a buy self.percentToSecure = 0.05 # Percent above 52-week high to sell to secure profit self.symbolHighs = {} # Universe security symbols : their 52-week highs self.investments = {} # Currently held investments : the price at entry self.toLiquidate = False self.UniverseSettings.Resolution = Resolution.Minute self.SetUniverseSelection(CoarseFundamentalUniverseSelectionModel(self.CoarseSelectionFunction)) def OnData(self, data): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data ''' # Liquidate any held securities removed from the universe if self.toLiquidate: for security in self.changes.RemovedSecurities: if security.Invested: self.Liquidate(security.Symbol) self.toLiquidate = False total = 0 # Total number of securities comprising new portfolio toInvest = [] for symbol in self.symbolHighs.keys(): if not data.ContainsKey(symbol): continue if data[symbol] is None: continue if data[symbol].Price >= (1-self.percentToTop)*self.symbolHighs[symbol]: if symbol in self.investments.keys(): if self.investments[symbol] == 0: # Make sure we haven't sold the position today already continue elif data[symbol].Price >= (1+self.percentToSecure)*self.investments[symbol]: # Secure profit self.Liquidate(symbol) self.investments[symbol] = 0 continue total += 1 toInvest.append(symbol) elif self.Portfolio[symbol].Invested: self.Liquidate(symbol) if total > 0: weight = 1/total for symbol in toInvest: self.investments[symbol] = data[symbol].Price self.SetHoldings(symbol, weight) def CoarseSelectionFunction(self, coarse): self.investments = {} positiveUsa = [x for x in coarse if x.Price * x.Volume > 0 and x.Market == Market.USA] securities = sorted(positiveUsa, key=lambda x: x.DollarVolume)[:500] symbols = [c.Symbol for c in securities] historical = self.History(symbols, 365, Resolution.Daily) highs = historical.high.unstack(level=0) for c in symbols: self.symbolHighs[c] = max(highs[c]) return symbols def OnSecuritiesChanged(self, changes): self.changes = changes if len(changes.RemovedSecurities) > 0: self.toLiquidate = True for security in changes.RemovedSecurities: if security.Symbol in self.symbolHighs.keys(): del self.symbolHighs[security.Symbol]

Note: I did initially try to use rolling windows to get the 52-week high, but it seemed like I was making more Historical Data requests that way than the way it is currently set up, and the code was a lot messier since I had to delete the stored rolling windows of the securities which were removed from the universe, and make sure I was updating the rolling windows with the previous day's High, etc.

Author