Quant BuffetRelax, Not Over Thinking

Trendfollowing Effect within REITs

Log in to collect

Academic paper

The Market Timing Power of Moving Averages: Evidence from US REIT Indexes

AuthorsPaskalis Glabadanidis

Institute
  • ?Essential Services Commission of South Australia

Strategy in a nutshell

: Monthly U.S. REIT Trendfollowing with Subsector Timing

This monthly strategy targets U.S. REITs via ETFs (e.g., VNQ, RWR) or diversified REIT portfolios. The investor goes long when the index is above its 24-month moving average and holds risk-free assets otherwise. Advanced implementations time individual REIT subsectors independently using subsector ETFs or portfolios, rebalancing monthly to capture targeted trends.

Economic rationale

REIT prices deviate from fundamentals due to incomplete information, valuation misunderstandings, dispersed beliefs, and behavioral biases. Their sensitivity to business cycles produces persistent price trends, enabling trend-following strategies to systematically exploit these anomalies.

Backtest performance

Annualised return14.38%
Volatility10.67%
Beta0.375
Sharpe ratio0.97
Sortino ratio0.139
Win rate54%

Full Python code

from AlgorithmImports import *
class TrendfollowingEffectREITs(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100_000)
data: Equity = self.AddEquity('VNQ', Resolution.Daily)
data.SetLeverage(5)
self.vnq: Symbol = data.Symbol

data: Equity = self.AddEquity('SHY', Resolution.Daily)
data.SetLeverage(5)
self.shy: Symbol = data.Symbol

period: int = 24 * 21
self.SetWarmUp(period, Resolution.Daily)

self.data: SimpleMovingAverage = self.SMA(self.vnq, period, Resolution.Daily)
# Warmup SMA.
history: DataFrame = self.History(self.Symbol(self.vnq), period, Resolution.Daily)
if not history.empty:
    closes = history.loc[self.vnq].close
    for time, close in closes.items():
        self.data.Update(time, close)

self.recent_month: int = -1

def OnData(self, slice: Slice) -> None:
if self.recent_month == self.Time.month:
    return
self.recent_month = self.Time.month

# if self.vnq in data and self.shy in data:
#     if data[self.vnq] and data[self.shy]:
        
if self.Securities[self.vnq].Price > self.data.Current.Value:
    if self.Portfolio[self.shy].Invested:
        self.Liquidate(self.shy)
    self.SetHoldings(self.vnq, 1)
else:
    if self.Portfolio[self.vnq].Invested:
        self.Liquidate(self.vnq)
    self.SetHoldings(self.shy, 1)