Overall Statistics
Total Orders
1234
Average Win
0.18%
Average Loss
-0.22%
Compounding Annual Return
4.442%
Drawdown
31.200%
Expectancy
0.078
Start Equity
1000000
End Equity
1242807.66
Net Profit
24.281%
Sharpe Ratio
0.034
Sortino Ratio
0.041
Probabilistic Sharpe Ratio
2.459%
Loss Rate
41%
Win Rate
59%
Profit-Loss Ratio
0.84
Alpha
-0.05
Beta
0.762
Annual Standard Deviation
0.155
Annual Variance
0.024
Information Ratio
-0.572
Tracking Error
0.117
Treynor Ratio
0.007
Total Fees
$8459.14
Estimated Strategy Capacity
$46000.00
Lowest Capacity Asset
RRF R735QTJ8XC9X
Portfolio Turnover
0.91%
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.set_cash(1_000_000)
        self.settings.seed_initial_prices = True
        # Add a universe of REITs.
        date_rule = self.date_rules.month_start('SPY')
        self.universe_settings.schedule.on(date_rule)
        self.universe_settings.resolution = Resolution.DAILY
        self._universe = self.add_universe(self._select_assets)        
        # Add a Scheduled Event to rebalance the portfolio quarterly.
        self.schedule.on(date_rule, self.time_rules.at(8, 0), self._rebalance)
        # Add a warm-up period so we don't need to wait until the 
        # first quarter to enter the market.
        self.set_warm_up(timedelta(100))
        
    def _select_assets(self, fundamentals):
        if not self._quarter_start():
            return Universe.UNCHANGED
        # Select liquid REITs trading above $1.
        reits = [
            f.symbol for f in fundamentals
            if (f.company_reference.is_reit and 
                f.has_fundamental_data and 
                f.price > 1 and 
                f.volume > 10_000)
        ]        
        # Calculate the 11 month (1-month lagged) returns.
        history = self.history(reits, self.time - timedelta(365), self.time - timedelta(30)).close.unstack(0)
        momentum_by_symbol = (history.iloc[-1] / history.iloc[0] - 1).dropna()
        # Select the top 1/3 of assets with the greatest momentum.
        return list(momentum_by_symbol.sort_values().iloc[-int(len(momentum_by_symbol)/3):].index)

    def _quarter_start(self):
        return self.time.month % 3 == 1

    def _rebalance(self, skip_guard=False):
        if not self._quarter_start() and not skip_guard:
            return
        # Form an equal-weighted portfolio.
        weight = 1/len(self._universe.selected)
        self.set_holdings([PortfolioTarget(symbol, weight) for symbol in self._universe.selected], True)
    
    def on_warmup_finished(self):
        self._rebalance(True)