Overall Statistics |
Total Orders 47187 Average Win 0.01% Average Loss -0.01% Compounding Annual Return -5.907% Drawdown 35.900% Expectancy -0.104 Start Equity 10000000 End Equity 7116915.22 Net Profit -28.831% Sharpe Ratio -0.841 Sortino Ratio -0.812 Probabilistic Sharpe Ratio 0.000% Loss Rate 46% Win Rate 54% Profit-Loss Ratio 0.66 Alpha -0.051 Beta -0.061 Annual Standard Deviation 0.066 Annual Variance 0.004 Information Ratio -0.715 Tracking Error 0.175 Treynor Ratio 0.912 Total Fees $116954.12 Estimated Strategy Capacity $11000.00 Lowest Capacity Asset QES WRXDDCLORBS5 Portfolio Turnover 0.80% |
#region imports from AlgorithmImports import * #endregion # https://quantpedia.com/Screener/Details/199 class ROAEffectWithinStocks(QCAlgorithm): def initialize(self): self.set_start_date(2015, 1, 1) self.set_end_date(2020, 8, 1) self.set_cash(10000000) self.set_security_initializer(BrokerageModelSecurityInitializer( self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices))) self.settings.minimum_order_margin_portfolio_percentage = 0 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) self._monthly_rebalance = False self._coarse = False def _coarse_selection_function(self, coarse): if self._monthly_rebalance: self._coarse = True return [x.symbol for x in coarse if x.has_fundamental_data] return Universe.UNCHANGED def _fine_selection_function(self, fine): if self._monthly_rebalance: fine =[i for i in fine if i.earning_reports.basic_average_shares.three_months != 0 and i.earning_reports.basic_eps.twelve_months != 0 and i.valuation_ratios.pe_ratio != 0 # sales is greater than 10 million and i.valuation_ratios.sales_per_share*i.earning_reports.diluted_average_shares.value > 10000000 and i.operation_ratios.roa.value != 0] # sort into 2 halfs based on market capitalization sorted_market_cap = sorted(fine, key=lambda x: x.market_cap, reverse=True) top = sorted_market_cap[:int(len(sorted_market_cap)*0.5)] bottom = sorted_market_cap[-int(len(sorted_market_cap)*0.5):] # each half is then divided into deciles based on Return on Assets (ROA) sorted_top_by_roa = sorted(top, key=lambda x: x.operation_ratios.roa.value, reverse=True) sorted_bottom_by_roa = sorted(bottom, key=lambda x: x.operation_ratios.roa.value, reverse=True) # long top decile from each market capitalization group long_ = sorted_top_by_roa[:int(len(sorted_top_by_roa)*0.1)] + sorted_bottom_by_roa[:int(len(sorted_top_by_roa)*0.1)] self._long_stocks = [i.symbol for i in long_] # short bottom decile from each market capitalization group short = sorted_top_by_roa[-int(len(sorted_top_by_roa)*0.1):] + sorted_bottom_by_roa[-int(len(sorted_top_by_roa)*0.1):] self._short_stocks = [i.symbol for i in short] return self._long_stocks + self._short_stocks else: return Universe.UNCHANGED def _rebalance(self): self._monthly_rebalance = True def on_data(self, data): if not (self._monthly_rebalance and self._coarse): return self._coarse = False self._monthly_rebalance = False long_stocks = [x for x in self._long_stocks if self.securities[x].price] long_weight = 0.5 / len(long_stocks) targets = [PortfolioTarget(x, long_weight) for x in long_stocks] short_stocks = [x for x in self._short_stocks if self.securities[x].price] short_weight = -0.5 / len(short_stocks) targets.extend([PortfolioTarget(x, short_weight) for x in short_stocks]) self.set_holdings(targets, True)