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