Overall Statistics |
Total Trades 3275 Average Win 0.44% Average Loss -0.72% Compounding Annual Return 0% Drawdown 103.500% Expectancy -0.234 Net Profit -103.758% Sharpe Ratio -0.594 Probabilistic Sharpe Ratio 0% Loss Rate 53% Win Rate 47% Profit-Loss Ratio 0.62 Alpha -0.351 Beta -0.05 Annual Standard Deviation 0.599 Annual Variance 0.359 Information Ratio -0.737 Tracking Error 0.613 Treynor Ratio 7.089 Total Fees $4788.07 Estimated Strategy Capacity $24000.00 Lowest Capacity Asset SIEB R735QTJ8XC9X |
# region imports from AlgorithmImports import * # endregion # https://quantpedia.com/Screener/Details/54 class MomentumandStateofMarketFiltersAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2011, 1, 1) self.SetEndDate(2018, 8, 1) self.SetCash(100000) # add Wilshire 5000 Total Market Index data self.wilshire_symbol = self.AddData(Fred, Fred.Wilshire.Price5000, Resolution.Daily).Symbol self.W5000Return = self.ROC(self.wilshire_symbol, 252) # initialize the RateOfChange indicator of Wilshire 5000 total market index history = self.History(self.wilshire_symbol, 500, Resolution.Daily) for tuple in history.loc[self.wilshire_symbol].itertuples(): self.W5000Return.Update(tuple.Index, tuple.value) self.Debug("W5000 Rate of Change indicator isReady: "+ str(self.W5000Return.IsReady)) self.AddEquity("SPY", Resolution.Daily) self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction) self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.At(0, 0), self.rebalance) # mark it's the start of each month self.month_start = False # mark the coarse universe selection has finished self.selection = False self.momp = {} self.lookback = 20*6 self.long = None self.short = None self.tlt = self.AddEquity("TLT", Resolution.Daily).Symbol def CoarseSelectionFunction(self, coarse): coarse = [x for x in coarse if (x.HasFundamentalData and x.AdjustedPrice > 1)] for i in coarse: if i.Symbol not in self.momp: self.momp[i.Symbol] = SymbolData(i.Symbol, self.lookback, self) else: self.momp[i.Symbol].MOMP.Update(self.Time, i.AdjustedPrice) if self.month_start: self.selection = True self.MOMPReady = {symbol: SymbolData for symbol, SymbolData in self.momp.items() if SymbolData.MOMP.IsReady} if self.MOMPReady: # sort stocks by 6-month momentum sortByMOMP = sorted(self.MOMPReady, key = lambda x: self.MOMPReady[x].MOMP.Current.Value, reverse = True) self.long = sortByMOMP[:20] self.short = sortByMOMP[-20:] return self.long+self.short else: return [] else: return [] def rebalance(self): # rebalance every month self.month_start = True def OnData(self, data): if self.month_start and self.selection: self.month_start = False self.selection = False if self.long is None or self.short is None: return # if the previous 12 months return on the broad equity market was positive if self.W5000Return.Current.Value > 0: stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested] for i in stocks_invested: if i not in self.long+self.short: self.Liquidate(i) short = [symbol for symbol in self.short if symbol in data.Bars] short_weight = 0.5/len(short) # goes short on the prior six-month losers (lowest decile) for short_symbol in short: self.SetHoldings(short_symbol, -short_weight) # goes long on the prior six-month winners (highest decile) long = [symbol for symbol in self.long if symbol in data.Bars] long_weight = 0.5/len(long) for long_symbol in long: self.SetHoldings(long_symbol, long_weight) else: self.Liquidate() self.SetHoldings(self.tlt, 1) class SymbolData: '''Contains data specific to a symbol required by this model''' def __init__(self, symbol, lookback, algorithm): self.symbol = symbol self.MOMP = MomentumPercent(lookback) trade_bars = algorithm.History[TradeBar](symbol, lookback, Resolution.Daily) for trade_bar in trade_bars: self.MOMP.Update(trade_bar.EndTime, trade_bar.Close)