| 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)