Overall Statistics |
Total Trades 506 Average Win 0.18% Average Loss -0.06% Compounding Annual Return 8.756% Drawdown 5.300% Expectancy 0.085 Net Profit 1.344% Sharpe Ratio 0.623 Probabilistic Sharpe Ratio 43.018% Loss Rate 74% Win Rate 26% Profit-Loss Ratio 3.13 Alpha -0.056 Beta 0.239 Annual Standard Deviation 0.097 Annual Variance 0.009 Information Ratio -2.737 Tracking Error 0.156 Treynor Ratio 0.253 Total Fees $1144.38 |
class Gap_Up(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 10, 1) # Set Start Date self.SetCash(100000) # Set Strategy Cash # Creates "SPY" Equity self.symbol = self.AddEquity('SPY', Resolution.Minute).Symbol # Initiates our Universe on the Daily Resolution self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFilter) # Schedule for 10 minutes before market close self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol, 10), self.BeforeMarketClose) # Whether or not to trade a given stock self.stop_trading = False # Whether a stock has already been traded self.made_trade = False # Dictionary of data for the universe selection self.stateData = { } # Dictionary of data for the stocks that satisfy the gap conditions self.Gaps = {} # Value for determining when the day starts self.curr_day = -1 def OnData(self, data): # If the market is not open, return if not self.IsMarketOpen(self.symbol): return # Get current day open if self.curr_day != self.Time.day: for symbol in self.Gaps: # Resets StopTrading and MadeTrade for each stock in Gaps self.Gaps[symbol].StopTrading = False self.Gaps[symbol].MadeTrade = False # If the symbol exists, set the open to the days open price if data.ContainsKey(symbol) and data[symbol] is not None: self.Gaps[symbol].Open = data[symbol].Open # Else, set the "Open" to -1 else: self.Gaps[symbol].Open = -1 self.curr_day = self.Time.day # Checks to make sure all symbols in Gaps contain the data we need # If they don't sets StopTrading to True for symbol, gap in self.Gaps.items(): # If the stock should not be traded, continue and StopTrading is True if gap.StopTrading: continue # If the the symbol does not have an open or close price, continue and StopTrading is True elif gap.Open < 0 or gap.Close < 0: gap.StopTrading = True continue # if gap up doesn't meet our threshold, continue and StopTrading is True elif gap.Open - gap.Close <= 0: gap.StopTrading = True continue # If symbol contains no data, continue elif not data.ContainsKey(symbol) or data[symbol] is None: continue curr_price = data[symbol].Close # Gives a decimal value so that SetHoldings always invests an equal amount per stock order_perc = 1 / len(self.Gaps) # Executes a trade for the given symbol if not gap.MadeTrade: self.SetHoldings(symbol, order_perc) gap.MadeTrade = True def BeforeMarketClose(self): # Liquidate all assets self.Liquidate() for symbol in self.Gaps: # If the symbol exists, sets the close for the day to Gaps.Close if self.CurrentSlice.ContainsKey(symbol) and self.CurrentSlice[symbol] is not None: self.Gaps[symbol].Close = self.Securities[symbol].Price # Otherwise, the close equals -1, so it will be flitered out else: self.Gaps[symbol].Close = -1 # Sets the StopTrading back to False self.Gaps[symbol].StopTrading = False def OnSecuritiesChanged(self, changed): # Removes removed securites from Gaps for security in changed.RemovedSecurities: self.Gaps.pop(security.Symbol) # Adds Added Securites to Gaps for security in changed.AddedSecurities: self.Gaps[security.Symbol] = Gap() def CoarseSelectionFilter(self, coarse): self.coarse = coarse # We are going to use a dictionary to refer the object that will keep the moving averages # Adds the stocks that fit the volume criteria to the dictionary for c in coarse: if c.Symbol not in self.stateData: self.stateData[c.Symbol] = SelectionData(c.Symbol, 10) # Update the stateData to make sure it has the most recent stock data avg = self.stateData[c.Symbol] avg.update(c.EndTime, c.AdjustedPrice, c.DollarVolume) values = [x for x in self.stateData.values() if x.is_above_vol and x.price >= 1 and x.price <= 100] #values.sort(key=lambda x: x.volume, reverse=True) # Makes sure price is between 1 and 100 #filtered = [symbol for symbol, sd in self.stateData.items() if sd.price >= 1 and sd.price <= 100] return [ x.symbol for x in values[:10] ] # return filtered[:50] class Gap: def __init__(self): self.Close = -1 self.Open = -1 self.MadeTrade = False self.StopTrading = False class SelectionData(object): def __init__(self, symbol, period): self.symbol = symbol self.volume = 0 self.price = 0 self.sma = SimpleMovingAverage(period) self.is_above_vol = False def update(self, time, price, volume): self.volume = volume self.price = price if self.sma.Update(time, volume): self.is_above_vol = self.sma.Current.Value > 3500000