Overall Statistics |
Total Orders 160 Average Win 0.16% Average Loss -0.01% Compounding Annual Return 7.199% Drawdown 19.700% Expectancy 11.724 Start Equity 1000000 End Equity 1366852.85 Net Profit 36.685% Sharpe Ratio 0.408 Sortino Ratio 0.45 Probabilistic Sharpe Ratio 10.392% Loss Rate 3% Win Rate 97% Profit-Loss Ratio 12.11 Alpha -0.02 Beta 0.917 Annual Standard Deviation 0.107 Annual Variance 0.011 Information Ratio -0.545 Tracking Error 0.048 Treynor Ratio 0.048 Total Fees $241.59 Estimated Strategy Capacity $7100000.00 Lowest Capacity Asset CRHCY R735QTJ8XC9X Portfolio Turnover 0.07% |
#region imports from AlgorithmImports import * #endregion # https://quantpedia.com/Screener/Details/26 class BooktoMarketAnomaly(QCAlgorithm): def initialize(self): self.set_start_date(2014, 1, 1) self.set_end_date(2018, 7, 1) self.set_cash(1000000) self._sorted_by_bm = None self.set_security_initializer(BrokerageModelSecurityInitializer( self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices))) self.add_universe(self.coarse_selection_function, self.fine_selection_function) self.add_equity("SPY") 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 def coarse_selection_function(self, coarse): if self._yearly_rebalance: # drop stocks which have no fundamental data or have low price return [x.symbol for x in coarse if (x.has_fundamental_data)] else: return Universe.UNCHANGED def fine_selection_function(self, fine): if self._yearly_rebalance: # Filter stocks with positive PB Ratio fine = [x for x in fine if (x.valuation_ratios.pb_ratio > 0)] top_market_cap = sorted(fine, key=lambda x: x.market_cap, reverse=True)[:int(len(fine)*0.2)] # sorted stocks in the top market-cap list by book-to-market ratio top_bm = sorted(top_market_cap, key=lambda x: 1 / x.valuation_ratios.pb_ratio, reverse=True)[:int(len(top_market_cap)*0.2)] self._sorted_by_bm = [i.symbol for i in top_bm] total_market_cap = np.sum([i.market_cap for i in top_bm]) # calculate the weight with the market cap self._weights = {} for i in top_bm: self._weights[str(i.symbol)] = i.market_cap/total_market_cap return self._sorted_by_bm 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._sorted_by_bm: 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._sorted_by_bm: self.liquidate(i) # goes long on stocks with the highest book-to-market ratio for i in self._sorted_by_bm: self.set_holdings(i, self._weights[str(i)]) self._yearly_rebalance = False