| Overall Statistics |
|
Total Orders 556 Average Win 0.14% Average Loss -0.09% Compounding Annual Return 7.245% Drawdown 1.700% Expectancy -0.068 Start Equity 100000 End Equity 107238.29 Net Profit 7.238% Sharpe Ratio -0.117 Sortino Ratio -0.171 Probabilistic Sharpe Ratio 61.863% Loss Rate 62% Win Rate 38% Profit-Loss Ratio 1.47 Alpha -0.01 Beta 0.077 Annual Standard Deviation 0.039 Annual Variance 0.002 Information Ratio -0.465 Tracking Error 0.154 Treynor Ratio -0.06 Total Fees $596.45 Estimated Strategy Capacity $2000.00 Lowest Capacity Asset YGMZ XIU99CJS1PPH Portfolio Turnover 0.64% Drawdown Recovery 77 |
#region imports
from AlgorithmImports import *
#endregion
# https://quantpedia.com/Screener/Details/51
class MomentumShortTermReversalAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(datetime.now() - timedelta(365))
self.set_cash(100000)
self.universe_settings.resolution = Resolution.DAILY
self.settings.seed_initial_prices = True
self._prices_by_symbol = {}
self._decrease_winner = []
self._increase_loser = []
date_rule = self.date_rules.month_start("SPY")
self.universe_settings.schedule.on(date_rule)
self.add_universe(self._select)
self.schedule.on(date_rule, self.time_rules.midnight, self._rebalance)
self.set_warmup(252, Resolution.DAILY)
def _select(self, fundamental):
for f in fundamental:
symbol = f.symbol
self._prices_by_symbol[symbol] = self._prices_by_symbol.get(symbol, RollingWindow(13))
self._prices_by_symbol[symbol].add(f.adjusted_price)
prices_by_symbol = {s: p for s, p in self._prices_by_symbol.items() if p.is_ready}
if len(prices_by_symbol) < 50:
return Universe.UNCHANGED
count = math.floor(len(prices_by_symbol)/3)
def calc_yearly_return(data):
prices = data[1]
return prices[0]/prices[-1] - 1
sorted_by_return = sorted(prices_by_symbol.items(), key=calc_yearly_return, reverse=True)
def calc_garr_ratio(data):
price = np.array([i for i in data[1]])
returns = (price[:-1]-price[1:])/price[1:]
GARR_12 = np.prod([(1+i)**(1/12) for i in returns])-1
GARR_1 = (1+returns[0])**(1/12)-1
return data[0], GARR_1 / GARR_12
winners = sorted(sorted_by_return[:count], key=calc_garr_ratio)[:50]
losers = sorted(sorted_by_return[-count:], key=calc_garr_ratio, reverse=True)[:50]
self._decrease_winner = [symbol for symbol, x in winners]
self._increase_loser = [symbol for symbol, x in losers]
return self._decrease_winner + self._increase_loser
def _rebalance(self):
if self.is_warming_up:
return
if not (self._decrease_winner and self._increase_loser):
return
weight = -.25/len(self._increase_loser)
targets = [PortfolioTarget(s, weight) for s in self._increase_loser]
weight = .25/len(self._decrease_winner)
targets += [PortfolioTarget(s, weight) for s in self._decrease_winner]
self.set_holdings(targets, True)