Overall Statistics |
Total Orders 1415 Average Win 0.21% Average Loss -0.20% Compounding Annual Return 12.205% Drawdown 26.500% Expectancy 0.485 Start Equity 1000000 End Equity 2394834.50 Net Profit 139.483% Sharpe Ratio 0.608 Sortino Ratio 0.628 Probabilistic Sharpe Ratio 12.670% Loss Rate 27% Win Rate 73% Profit-Loss Ratio 1.04 Alpha 0.005 Beta 0.867 Annual Standard Deviation 0.137 Annual Variance 0.019 Information Ratio -0.077 Tracking Error 0.091 Treynor Ratio 0.096 Total Fees $12582.94 Estimated Strategy Capacity $530000.00 Lowest Capacity Asset AJX VY25795D7GIT Portfolio Turnover 0.73% |
#region imports from AlgorithmImports import * #endregion class MomentumInREIT(QCAlgorithm): def initialize(self): #rebalancing should occur in July self.set_start_date(2010, 12, 15) self.set_end_date(2018, 7, 15) self.set_cash(1000000) self.universe_settings.resolution = Resolution.DAILY self._filtered_fine = None self.add_universe(self._coarse_selection_function, self._fine_selection_function) self.add_equity("SPY", Resolution.DAILY) #monthly scheduled event self.schedule.on(self.date_rules.month_start("SPY"), self.time_rules.at(23, 0), self._rebalance) self._months = -1 self._quarterly_rebalance = False def _coarse_selection_function(self, coarse): if self._quarterly_rebalance: # drops penny stocks and stocks with no fundamental data return [x.symbol for x in coarse if float(x.price) > 1 and x.has_fundamental_data and float(x.volume) > 10000] else: return [] def _fine_selection_function(self, fine): if self._quarterly_rebalance: #filters out the companies that are not REITs fine = [x for x in fine if x.company_reference.is_reit] #calculating the 11 month (1-month lagged) returns start = self.time - timedelta(365) end = self.time - timedelta(30) for x in fine: hist = self.history([x.symbol], start, end, Resolution.DAILY) if not hist.empty: start_price = hist["close"].iloc[0] end_price = hist["close"].iloc[-1] x.momentum = (end_price - start_price) / start_price fine = [x for x in fine if hasattr(x, 'momentum')] #we sort REITs based on their returns sorted_filter = sorted(fine, key=lambda x: x.momentum) self._filtered_fine = [i.symbol for i in sorted_filter] return self._filtered_fine else: return [] def _rebalance(self): #quarterly rebalance self._months += 1 if self._months % 3 == 0: self._quarterly_rebalance = True def on_data(self, data): if not self._quarterly_rebalance: return if self._filtered_fine: portfolio_size = int(len(self._filtered_fine)/3) #pick the upper trecile to short and the lower decile to long long_stocks = self._filtered_fine[-portfolio_size:] stocks_invested = [x.key for x in self.portfolio] for i in stocks_invested: #liquidate the stocks not in our filtered_fine list if i not in long_stocks: self.liquidate(i) #long the stocks in the list elif i in long_stocks: self.set_holdings(i, 1/(portfolio_size)) self._quarterly_rebalance = False self._filtered_fine = None