| Overall Statistics |
|
Total Trades 2333 Average Win 0.10% Average Loss -0.17% Compounding Annual Return 11.129% Drawdown 27.200% Expectancy 0.297 Net Profit 122.595% Sharpe Ratio 0.698 Loss Rate 20% Win Rate 80% Profit-Loss Ratio 0.62 Alpha 0.017 Beta 5.009 Annual Standard Deviation 0.157 Annual Variance 0.025 Information Ratio 0.581 Tracking Error 0.157 Treynor Ratio 0.022 Total Fees $12027.60 |
from datetime import datetime, timedelta
class MomentumInREIT(QCAlgorithm):
def Initialize(self):
#rebalancing should occur in July
self.SetStartDate(2010,12,15) #Set Start Date
self.SetEndDate(2018,7,15) #Set End Date
self.SetCash(1000000) #Set Strategy Cash
self.UniverseSettings.Resolution = Resolution.Daily
self.filtered_fine = None
self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction)
self.AddEquity("SPY", Resolution.Daily)
#monthly scheduled event
self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.At(23, 0), self.rebalance)
self.months = -1
self.quarterly_rebalance = False
def CoarseSelectionFunction(self, coarse):
if self.quarterly_rebalance:
# drops penny stocks and stocks with no fundamental data
self.filtered_coarse = [x.Symbol for x in coarse if (float(x.Price) > 1)
and (x.HasFundamentalData)
and float(x.Volume) > 10000]
return self.filtered_coarse
else:
return []
def FineSelectionFunction(self, fine):
if self.quarterly_rebalance:
#filters out the companies that are not REITs
fine = [x for x in fine if (x.CompanyReference.IsREIT == 1)]
#calculating the 11 month (1-month lagged) returns
start = self.Time-timedelta(days = 365)
end = self.Time-timedelta(days = 30)
for x in fine:
hist = self.History([x.Symbol],start,end,Resolution.Daily)
if not hist.empty:
start_price = hist["close"].iloc[0]
end_price = hist["close"].iloc[-1]
x.momentum = (end_price-start_price)/start_price
fine = [x for x in fine if hasattr(x, 'momentum')]
#we sort REITs based on their returns
sorted_filter = sorted(fine, key=lambda x: x.momentum)
self.filtered_fine = [i.Symbol for i in sorted_filter]
return self.filtered_fine
else:
return []
def rebalance(self):
#quarterly rebalance
self.months+=1
if self.months%3 == 0:
self.quarterly_rebalance = True
def OnData(self, data):
if not self.quarterly_rebalance: return
if self.filtered_fine:
portfolio_size = int(len(self.filtered_fine)/3)
#pick the upper trecile to short and the lower decile to long
long_stocks = self.filtered_fine[-portfolio_size:]
stocks_invested = [x.Key for x in self.Portfolio]
for i in stocks_invested:
#liquidate the stocks not in our filtered_fine list
if i not in long_stocks:
self.Liquidate(i)
#long the stocks in the list
elif i in long_stocks:
self.SetHoldings(i, 1/(portfolio_size))
self.quarterly_rebalance = False
self.filtered_fine = None