“投资宇宙由名义国债和不同期限的TIPS组成,使用PriceStats的通胀数据。引入在线通胀趋势变量,基于60天中值在线通胀的1年百分位排名。根据规则:在线通胀趋势>80%时做多TIPS,<20%时做空TIPS,20%-80%不交易。策略会动态调整。回测显示原策略表现不佳,修改为只交易TIP ETF后表现有所改善。”
资产类别:债券、ETF、掉期 | 区域:美国 | 频率:每日 | 市场:债券 | 关键词:通胀,对冲
策略概述
投资宇宙由名义国债和不同期限的TIPS(可以是ETF的代表)组成。该策略使用来自PriceStats的全球和国家级通胀数据,这是一家与“万价项目”相关的经济数据科学公司。作者引入了一个变量,用来捕捉在线通胀趋势的拐点。这个变量(在线通胀趋势)等于滚动60天中值在线通胀的1年百分位排名。我们可以根据以下三条规则构建这个基于替代数据的债券时机策略:如果在线通胀趋势 > 80%,则我们做多盈亏平衡指数(做多100%的TIPS,做空100%的名义国债);否则,如果< 20%,则做空盈亏平衡指数(做多名义国债,做空TIPS);如果在20%-80%之间,则不进行交易。假设策略会根据新信息(通常是每日)动态调整。
Quantpedia的评论:我们按照论文的建议进行了回测,但该策略的表现持续为负。因此,我们修改了规则,不使用国债,只做多/做空TIP ETF(TIPS)。之后,策略的表现有所改善。
策略合理性
关于预测消费者价格指数(CPI)的文献非常丰富,作者显然是在以往研究的基础上进行了改进。正如他们所称,“在线通胀指数”是官方CPI通胀的强大预测指标。TIPS市场在通胀调查预测方面存在低效。我们展示的策略利用了作者的发现,即在线通胀能够预测美国名义国债与TIPS之间的盈亏平衡通胀利差变化。投资策略的核心是通过在TIPS和国债之间动态配置资金,在低通胀时期赚取更高收益,并在高通胀时期获得通胀保护。
论文来源
A Dynamic Approach Using Online Prices
- Alberto Cavallo,哈佛大学商学院
- Megan Czasonis,State Street Corporate
- William B. Kinlaw,State Street Global Markets
- David Turkington,State Street Associates
<摘要>
过去40多年里,有大量文献研究了通胀与资产价格之间的关系。大多数研究集中于股票、债券或商品的通胀对冲属性,假设它们是静态的买入并持有组合。很少有研究探讨主动管理策略的通胀对冲属性。在本文中,我们使用从21个国家的多渠道零售商网站抓取的数百万商品价格生成的高频通胀指数。首先,我们展示了这些系列包含关于官方政府通胀发布的前瞻性信息,并发现在线通胀指数可以预测美国名义国债与通胀挂钩国债(TIPS)收益率之间盈亏平衡通胀利差的变化。然后,我们测试了一种投资策略,利用这种市场低效,通过在TIPS和名义国债之间动态配置资金来获利。动态策略为投资者提供了在实现通胀低于市场预期时捕捉名义债券价格上涨的潜力,以及在实现通胀高于市场预期时捕捉TIPS价格上涨的潜力。

回测表现
| 年化收益率 | 2.6% |
| 波动率 | 2.4% |
| Beta | 0.04 |
| 夏普比率 | 48% |
| 索提诺比率 | N/A |
| 最大回撤 | -3.7% |
| 胜率 | 71% |
完整python代码
from AlgorithmImports import *
from typing import List
from data_tools import CustomFeeModel, QuantpediaInflationUS, InflationData
# endregion
class InflationHedgingUsingOnlinePrices(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2008, 1, 1)
self.SetEndDate(2015, 8, 1)
self.SetCash(100000)
self.leverage:int = 5
self.index_ps_period:int = 60
self.median_period:int = 21 * 12
self.SetWarmUp(self.median_period, Resolution.Daily)
self.upper_percentile_threshold:int = 80
self.lower_percentile_threshold:int = 20
data = self.AddEquity('TIP', Resolution.Daily)
data.SetFeeModel(CustomFeeModel())
data.SetLeverage(self.leverage)
self.tip:Symbol = data.Symbol
data = self.AddEquity('IEF', Resolution.Daily)
data.SetFeeModel(CustomFeeModel())
data.SetLeverage(self.leverage)
self.ief:Symbol = data.Symbol
# Source: http://www.thebillionpricesproject.com/datasets/
self.inflation_index:Symbol = self.AddData(
QuantpediaInflationUS, 'US_ONLINE_INFLATION', Resolution.Daily).Symbol
self.inflation_data:InflationData = InflationData(self.index_ps_period, self.median_period)
def OnData(self, data: Slice):
self.Liquidate()
if not (self.inflation_index in data and data[self.inflation_index]):
self.Liquidate()
else:
index_ps:float = data[self.inflation_index].Value
self.inflation_data.update_index_ps_values(index_ps)
if self.inflation_data.index_ps_values_ready():
self.inflation_data.update_medians()
if self.inflation_data.medians_ready():
online_inflation_trend:float = self.inflation_data.get_latest_median()
median_values:List[float] = self.inflation_data.get_medians()
upper_threshold:float = np.percentile(median_values, self.upper_percentile_threshold)
lower_threshold:float = np.percentile(median_values, self.lower_percentile_threshold)
if online_inflation_trend > upper_threshold:
# if Online Inflation Trend > 80%, then we go long breakeven index (long 100% TIPS, short 100% nominal Treasuries)
self.SetHoldings(self.tip, 1)
self.SetHoldings(self.ief, -1)
elif online_inflation_trend < lower_threshold:
# if Online Inflation Trend < 20%: short breakeven index (long nominal Treasuries, short TIPS)
self.SetHoldings(self.tip, -1)
self.SetHoldings(self.ief, 1)
else:
self.Liquidate()
