Quant Buffet放轻松,别过度思虑

房地产投资信托基金(REITs)中的趋势跟随效应

登录后收藏

学术论文

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

作者帕斯卡利斯·格拉巴达尼迪斯(Paskalis Glabadanidis)

机构
  • ?阿德莱德大学商学院。
论文摘要

我提供的证据表明,使用价值加权和等权重的美国 REIT 指数的月度回报数据(1980 年 1 月至 2010 年 12 月期间),移动平均交易策略在均值-方差(Mean-Variance)意义上优于买入并持有(Buy-and-Hold)基础资产。该策略的异常收益对 Carhart(1997)四因子模型的敏感性较低,并在扣除交易成本后,每年能产生 10% 至 15% 的经济和统计显著的 α 收益。这种优异表现在不同移动平均滞后期和子样本期内均保持稳健,而投资者情绪、流动性风险、经济周期、牛熊市状况以及信用利差等因素无法完全解释其收益来源。此外,该策略在随机生成和自助抽样(Bootstrapped)回报数据上同样有效。

移动平均策略的显著市场择时能力似乎是异常收益的主要驱动力。该策略的回报类似于相对于基础投资组合的“非完美实值保护性看跌期权”(Imperfect At-the-Money Protective Put)策略的回报。它成功避开了 2008 年初的市场暴跌,并在 20 个 REIT 指数的累积回报表现上明显优于买入并持有策略。此外,对 274 只个别 REIT 采用移动平均策略的实证结果进一步证实了 REIT 指数的研究发现。

策略概要

该策略使用跟踪美国房地产投资信托基金(REITs)指数的交易所交易基金(ETF)(例如 VNQ、RWR)或多元化的 REIT 组合。当 REIT 指数高于其 24 个月移动均线时,投资者做多 REITs;否则,持有无风险资产,并在每月收盘时重新平衡投资组合。

进阶方法针对每个 REIT 子行业进行独立择时,交易特定子行业的 ETF 或 REIT 组合。此方法通过利用子行业特定趋势,实现更具针对性的投资,并潜在地获得更高回报,同时遵循相同的移动均线择时规则和每月再平衡机制。

策略合理性

学术研究提供了几种解释该反常现象运作机制的理论。基本价值受到信息不完全、估值方法理解有限、投资者信念分歧,以及交易者和投资者在金融市场中的客观与行为偏差的影响。这些因素导致市场价格长期偏离基本价值。此外,房地产投资信托基金(REITs)对经济周期的敏感性也促成了统计上显著的价格趋势。

回测表现

波动率10.67%
夏普比率0.97
索提诺比率0.139
胜率54%

完整 Python 代码

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)