| 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)