Overall Statistics |
Total Trades 64 Average Win 1.00% Average Loss -1.28% Compounding Annual Return -10.300% Drawdown 12.200% Expectancy -0.166 Net Profit -6.926% Sharpe Ratio -0.859 Probabilistic Sharpe Ratio 3.897% Loss Rate 53% Win Rate 47% Profit-Loss Ratio 0.78 Alpha -0.081 Beta -0.041 Annual Standard Deviation 0.099 Annual Variance 0.01 Information Ratio -1.036 Tracking Error 0.17 Treynor Ratio 2.06 Total Fees $355.08 |
import operator class FadingTheGap(QCAlgorithm): def Initialize(self): #Backtesting parameters self.SetStartDate(2017, 11, 1) self.SetEndDate(2018, 7, 1) self.SetCash(100000) self.minimumDollar = 20 self.maximumDollar = 5000 self.topVolume = 100 # Securities list that is dynamically changes by the universe coarse filter self.SecuritiesList = [] # Schedules self.AddEquity("SPY", Resolution.Daily) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 1), self.OpeningBar) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 2), self.Buy) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 45), self.ClosePositions) # Universe Settings self.UniverseSettings.Resolution = Resolution.Minute self.AddUniverse(self.CoarseSelectionFilter) # Dictionaries self.securityDelta = {} self.data = {} self.securityDeviations = {} def CoarseSelectionFilter(self, coarse): # Sort equities by volume - highest volume first sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True) # Filter equities by price filteredByPrice = [c.Symbol for c in sortedByDollarVolume if c.Price > self.minimumDollar and c.Price < self.maximumDollar] self.SecuritiesList = filteredByPrice[:self.topVolume] return self.SecuritiesList def OnSecuritiesChanged(self, changes): # When securities are added we create a SymbolData object for them for security in changes.AddedSecurities: symbol = security.Symbol self.data[symbol] = SymbolData(self, symbol) def OpeningBar(self): # Go through all the top traded securities of the day for symbol in self.SecuritiesList: # Retrieve the current day open of the same securities if not self.CurrentSlice.ContainsKey(symbol): continue if self.CurrentSlice[symbol] is None: continue if self.CurrentSlice[symbol].Open <= 0: continue if self.CurrentSlice[symbol].IsFillForward: continue currentOpen = self.CurrentSlice[symbol].Open self.securityDelta[symbol] = currentOpen - self.data[symbol].previousClose # reset our securityDeviations every morning before deviation calculations self.securityDeviations = {} def Buy(self): for symbol, value in self.data.items(): if value.std.IsReady and symbol in self.securityDelta: deviation = self.securityDelta[symbol] / value.std.Current.Value if deviation < -2: self.securityDeviations[symbol] = deviation # if there are symbols with more than 2 deviations today if len(self.securityDeviations) > 0: # retrives the symbol with the largest negative deviation buySymbol = min(self.securityDeviations.items(), key=operator.itemgetter(1))[0] self.SetHoldings(buySymbol, 1) self.Debug("BUY " + buySymbol.Value + " deviations: " + str(self.securityDeviations[buySymbol]) ) def ClosePositions(self): for kvp in self.Portfolio: if kvp.Value.Invested: self.Debug("SELL " + kvp.Key.Value) # Liquidate Portfolio self.Liquidate() class SymbolData: def __init__(self, algorithm, symbol): self.algorithm = algorithm self.symbol = symbol self.std = StandardDeviation(symbol, 60) self.previousClose = -1 # Initalize indicator with historical daily data history = algorithm.History(symbol, 100, Resolution.Daily) for bar in history.itertuples(): self.Update(bar.Index[1], bar.close) dailyConsolidator = TradeBarConsolidator(timedelta(days = 1)) algorithm.SubscriptionManager.AddConsolidator(symbol, dailyConsolidator) dailyConsolidator.DataConsolidated += self.OnConsolidated # Update previous day close and daily STD indicator def Update(self, time, close): self.std.Update(time, close) self.previousClose = close # daily consolidator updates our indicator and previous daily close def OnConsolidated(self, sender, bar): self.Update(bar.Time, bar.Close)