Overall Statistics Total Trades 3590 Average Win 0.14% Average Loss -0.11% Compounding Annual Return 2.622% Drawdown 10.900% Expectancy 0.050 Net Profit 7.149% Sharpe Ratio 0.353 Loss Rate 55% Win Rate 45% Profit-Loss Ratio 1.35 Alpha 0.16 Beta -7.401 Annual Standard Deviation 0.074 Annual Variance 0.006 Information Ratio 0.109 Tracking Error 0.074 Treynor Ratio -0.004 Total Fees \$91593.67
```# https://quantpedia.com/Screener/Details/13
# The investment universe consists of the 100 biggest companies by market capitalization.
# The investor goes long on the 10 stocks with the lowest performance in the previous month
# and goes short on the 10 stocks with the greatest performance from the previous month.
# The portfolio is rebalanced weekly.
from QuantConnect.Data.UniverseSelection import *
import math
import numpy as np
import pandas as pd
import scipy as sp

class ShortTermReversalAlgorithm(QCAlgorithm):

def Initialize(self):

self.SetStartDate(2016, 1, 1)  # Set Start Date
self.SetEndDate(2018, 9, 1)    # Set Start Date
self.SetCash(5000000)          # Set Strategy Cash
self.lookback = 20

self.UniverseSettings.Resolution = Resolution.Daily
self.num_screener = 20
self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Monday), self.TimeRules.AfterMarketOpen("SPY", 0), self.Rebalance)
self.weekly_rebalance = True
self.filtered_coarse = []
self.filtered_fine = []

def CoarseSelectionFunction(self, coarse):
if self.weekly_rebalance:
# drop stocks which have no fundamental data or have too low prices
selected = [x for x in coarse if (x.HasFundamentalData) and (float(x.Price) > 5)]
# rank the stocks by dollar volume
filtered = sorted(selected, key=lambda x: x.DollarVolume, reverse=True)
self.filtered_coarse = [ x.Symbol for x in filtered[:1000]]
return self.filtered_coarse
else:
return self.filtered_fine

def FineSelectionFunction(self, fine):
if self.weekly_rebalance:
filtered_fine = [x for x in fine if x.EarningReports.BasicEPS.TwelveMonths > 0
and x.ValuationRatios.PERatio > 0
and x.EarningReports.BasicAverageShares.ThreeMonths > 0
and x.EarningReports.BasicAverageShares.ThreeMonths > 0]
# filter 100 stocks with the top market cap
top = sorted(filtered_fine, key = lambda x: x.EarningReports.BasicAverageShares.ThreeMonths * (x.EarningReports.BasicEPS.TwelveMonths*x.ValuationRatios.PERatio), reverse=True)[:100]
self.filtered_fine = [i.Symbol for i in top]
return self.filtered_fine
else:
return self.filtered_fine

def OnData(self, data):
# update the indicator value for newly added securities
symbolData.ROC.Update(IndicatorDataPoint(symbol, self.Time, self.Securities[symbol].Close))

if  self.weekly_rebalance and self.filtered_fine:
# sorted the stocks by the monthly return (RateOfReturn)
invested = [x.Key for x in self.Portfolio if x.Value.Invested]
for i in invested:
if i not in short_stocks+long_stocks:
self.Liquidate(i)

for short in short_stocks:
for long in long_stocks:

self.weekly_rebalance = False

def Rebalance(self):
self.weekly_rebalance = True

def OnSecuritiesChanged(self, changes):

for removed in changes.RemovedSecurities:
# warm up the indicator with history price for newly added securities

symbolData = SymbolData(symbol, self.lookback)
if str(symbol) in history.index:
symbolData.WarmUpIndicator(history.loc[str(symbol)])

class SymbolData:
'''Contains data specific to a symbol required by this model'''

def __init__(self, symbol, lookback):
self.symbol = symbol
self.ROC = RateOfChange(lookback)

def WarmUpIndicator(self, history):
# warm up the RateOfChange indicator with the history request
for tuple in history.itertuples():
item = IndicatorDataPoint(self.symbol, tuple.Index, float(tuple.close))
self.ROC.Update(item)                        ```