Quant BuffetRelax, Not Over Thinking

Inflation Hedging Using Online Prices

Log in to collect

Strategy in a nutshell

The strategy focuses on nominal Treasury bonds and TIPS (or ETFs tracking them) of varying maturities. Using online inflation data from PriceStats, an Online Inflation Trend variable is calculated as the one-year percentile rank of the rolling 60-day median inflation. Trading rules are: if the trend exceeds 80%, go long the breakeven index (long TIPS, short nominal Treasuries); if below 20%, short the breakeven index (long Treasuries, short TIPS); if in between, no trade is made. The portfolio is dynamically rebalanced as new data arrives, typically daily. Backtests suggest better performance when applied directly to TIP ETFs without pairing with Treasuries.

Economic rationale

The strategy exploits the inefficiency of the TIPS market relative to inflation expectations. Online inflation indices are shown to predict official CPI movements effectively. By timing allocations between TIPS and nominal Treasuries based on these signals, investors can enhance returns during low-inflation periods and secure inflation protection when inflation rises, capitalizing on the predictive power of alternative, real-time data.

Backtest performance

Annualised return2.6%
Volatility2.4%
Beta0.04
Sharpe ratio48%
Maximum drawdown-3.7%
Win rate71%

Full Python code

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