Overall Statistics |
Total Orders 4170 Average Win 0.20% Average Loss -0.28% Compounding Annual Return -9.385% Drawdown 62.100% Expectancy -0.120 Start Equity 100000 End Equity 47335.78 Net Profit -52.664% Sharpe Ratio -0.511 Sortino Ratio -0.396 Probabilistic Sharpe Ratio 0.000% Loss Rate 48% Win Rate 52% Profit-Loss Ratio 0.71 Alpha -0.062 Beta -0.059 Annual Standard Deviation 0.132 Annual Variance 0.017 Information Ratio -0.856 Tracking Error 0.182 Treynor Ratio 1.136 Total Fees $4127.60 Estimated Strategy Capacity $30000.00 Lowest Capacity Asset BONE UUP8WPRH3SKL Portfolio Turnover 1.85% |
# region imports from AlgorithmImports import * # endregion # https://quantpedia.com/Screener/Details/54 class MomentumAndStateOfMarketFiltersAlgorithm(QCAlgorithm): _blacklisted_assets = [ "DYN RRWGXYWP5HET", # /datasets/issue/16852 "NIHD SML8IVC2ZZHH", # /datasets/issue/16854 "HERO TD6B1QW5DBHH", # /datasets/issue/16856 ] def initialize(self): self.set_start_date(2011, 1, 1) self.set_end_date(2018, 8, 1) self.set_cash(100000) self.settings.minimum_order_margin_portfolio_percentage = 0 # add Wilshire 5000 Total Market Index data self.wilshire_symbol = self.add_data(Fred, Fred.Wilshire.PRICE_5000, Resolution.DAILY).symbol self.w5000_return = 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 t, value in history.loc[self.wilshire_symbol]['value'].items(): self.w5000_return.update(t, value) self.debug("W5000 Rate of Change indicator isReady: " + str(self.w5000_return.is_ready)) self.universe_settings.resolution = Resolution.DAILY self.add_universe(self._coarse_selection_function) self.schedule.on( self.date_rules.month_start(Symbol.create("SPY", SecurityType.EQUITY, Market.USA)), self.time_rules.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.add_equity("TLT", Resolution.DAILY).symbol def _coarse_selection_function(self, coarse): 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.adjusted_price) if self._month_start: coarse_by_symbol = {c.symbol: c for c in coarse} self._selection = True momp_ready = { symbol: symbol_data for symbol, symbol_data in self._momp.items() if (symbol_data.momp.is_ready and symbol not in self._blacklisted_assets and symbol in coarse_by_symbol and coarse_by_symbol[symbol].adjusted_price > 5 and coarse_by_symbol[symbol].has_fundamental_data) } if momp_ready: # sort stocks by 6-month momentum sort_by_momp = sorted(momp_ready, key=lambda x: momp_ready[x].momp.current.value, reverse=True) self._long = sort_by_momp[:20] self._short = sort_by_momp[-20:] return self._long + self._short return [] def _rebalance(self): # rebalance every month self._month_start = True def on_data(self, data): if self._month_start and self._selection: self._month_start = False self._selection = False if not (self._long and self._short): return targets = [] # if the previous 12 months return on the broad equity market was positive if self.w5000_return.current.value > 0: longs = [symbol for symbol in self._long if symbol in data.bars] long_weight = 0.25/len(longs) for symbol in longs: targets.append(PortfolioTarget(symbol, long_weight)) shorts = [symbol for symbol in self._short if symbol in data.bars] short_weight = -0.25/len(shorts) for symbol in shorts: targets.append(PortfolioTarget(symbol, short_weight)) else: targets.append(PortfolioTarget(self._tlt, 1)) self.set_holdings(targets, True) class SymbolData: 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.end_time, trade_bar.close)