Overall Statistics
Total Orders
1198
Average Win
0.18%
Average Loss
-0.22%
Compounding Annual Return
4.518%
Drawdown
31.300%
Expectancy
0.088
Start Equity
1000000
End Equity
1247343.24
Net Profit
24.734%
Sharpe Ratio
0.047
Sortino Ratio
0.058
Probabilistic Sharpe Ratio
2.542%
Loss Rate
41%
Win Rate
59%
Profit-Loss Ratio
0.83
Alpha
-0.048
Beta
0.766
Annual Standard Deviation
0.156
Annual Variance
0.024
Information Ratio
-0.553
Tracking Error
0.117
Treynor Ratio
0.01
Total Fees
$8216.68
Estimated Strategy Capacity
$75000.00
Lowest Capacity Asset
RRF R735QTJ8XC9X
Portfolio Turnover
0.89%
Drawdown Recovery
124
#region imports
from AlgorithmImports import *
#endregion


class MomentumInREIT(QCAlgorithm):

    def initialize(self):
        self.set_start_date(self.end_date - timedelta(5*365))
        self.settings.seed_initial_prices = True
        self.set_cash(1_000_000)
        date_rule = self.date_rules.month_start("SPY")
        self.universe_settings.resolution = Resolution.DAILY
        self._universe = self.add_universe(date_rule, self._select_assets)
        # Add a monthly Scheduled Event.
        self.schedule.on(date_rule, self.time_rules.midnight, self._rebalance)
        self.set_warm_up(timedelta(100))
        
    def _new_quarter(self):
        return self.time.month % 3 == 1

    def _select_assets(self, fundamentals):
        if not self._new_quarter():
            return Universe.UNCHANGED
        # Drop penny stocks, stocks with no fundamental data, 
        # and companies that aren't REITs.
        fundamentals = [
            f for f in fundamentals 
            if (f.price > 1 
                and f.has_fundamental_data 
                and f.volume > 10_000 
                and f.company_reference.is_reit)
        ]  
        # Calculate the 11 month (1-month lagged) returns of all 
        # the remaining assets.
        history = self.history(
            [f.symbol for f in fundamentals], 
            self.time - timedelta(365), 
            self.time - timedelta(30), 
            Resolution.DAILY
        ).close.unstack(0).dropna(axis=1)
        sorted_by_momentum = list((history.iloc[-1] / history.iloc[0]).sort_values().index)
        # Select the 1/3 of assets with the greatest momentum.
        return sorted_by_momentum[-int(len(sorted_by_momentum)/3):]
    
    def _rebalance(self, wait_for_new_quarter=True):
        if wait_for_new_quarter and not self._new_quarter():
            return
        targets = [
            PortfolioTarget(symbol, 1/len(self._universe.selected)) 
            for symbol in self._universe.selected
        ]
        self.set_holdings(targets, True)
    
    def on_warmup_finished(self):
        self._rebalance(False)