Overall Statistics |
Total Orders 409 Average Win 5.14% Average Loss -2.60% Compounding Annual Return 30.517% Drawdown 42.000% Expectancy 0.581 Start Equity 1000000 End Equity 17163691.33 Net Profit 1616.369% Sharpe Ratio 0.802 Sortino Ratio 1.151 Probabilistic Sharpe Ratio 13.707% Loss Rate 47% Win Rate 53% Profit-Loss Ratio 1.98 Alpha 0.248 Beta -0.013 Annual Standard Deviation 0.308 Annual Variance 0.095 Information Ratio 0.525 Tracking Error 0.349 Treynor Ratio -18.914 Total Fees $64740.20 Estimated Strategy Capacity $16000.00 Lowest Capacity Asset EPIX W21WGWK0DLYD Portfolio Turnover 0.53% |
#region imports from AlgorithmImports import * #endregion # https://quantpedia.com/Screener/Details/162 class MomentumInSmallPortfolio(QCAlgorithm): _blacklisted_assets = ['TOPT T0KDYN9C3IHX'] # /datasets/issue/15180 def initialize(self): self.set_start_date(2008, 1, 1) self.set_end_date(2018, 9, 1) self.set_cash(1000000) self.universe_settings.resolution = Resolution.DAILY self.add_universe(self._coarse_selection_function, self._fine_selection_function) self.add_equity("SPY", Resolution.DAILY) self.schedule.on(self.date_rules.month_start("SPY"), self.time_rules.after_market_open("SPY"), self._rebalance) # Count the number of months that have passed since the algorithm starts self._months = -1 self._yearly_rebalance = True self._long = None self._short = None def _coarse_selection_function(self, coarse): if self._yearly_rebalance: # drop stocks which have no fundamental data or have low price self._filtered_coarse = [x.symbol for x in coarse if (x.has_fundamental_data) and str(x.symbol.id) not in self._blacklisted_assets] return self._filtered_coarse else: return Universe.UNCHANGED def _fine_selection_function(self, fine): if self._yearly_rebalance: # Calculate the yearly return and market cap top_market_cap = sorted(fine, key = lambda x: x.market_cap, reverse=True)[:int(len(self._filtered_coarse)*0.75)] has_return = [] for i in top_market_cap: history = self.history([i.symbol], timedelta(days=365), Resolution.DAILY) if not history.empty: close = history.loc[str(i.symbol)]['close'] i.returns = (close[0]-close[-1])/close[-1] has_return.append(i) sorted_by_return = sorted(has_return, key = lambda x: x.returns) self._long = [i.symbol for i in sorted_by_return[-10:]] self._short = [i.symbol for i in sorted_by_return[:10]] return self._long+self._short else: return Universe.UNCHANGED def _rebalance(self): # yearly rebalance self._months += 1 if self._months%12 == 0: self._yearly_rebalance = True def on_data(self, data): if not self._yearly_rebalance: return if self._long and self._short: stocks_invested = [x.key for x in self.portfolio if x.value.invested] # liquidate stocks not in the trading list for i in stocks_invested: if i not in self._long+self._short: self.liquidate(i) for i in self._short: self.set_holdings(i, -0.5/len(self._short)) for i in self._long: self.set_holdings(i, 0.5/len(self._long)) self._long = None self._short = None self._yearly_rebalance = False