Real interest rates#

This category group contains various measures of local-currency real interest rates. Nominal interest rate measures are selected such that they are roughly comparable across countries. They are adjusted by using either vintages of formulaic estimates of inflation expectations or (backward-looking) vintages of recent CPI inflation trends.

Real short-term interest rates#

Ticker: RIR_NSA / RIRB_NSA

Label: Real short-term interest rate: expectations-based / backward looking

Definition: Main 1-month money market rate or closest proxy: adjusted for inflation expectations / adjusted for latest CPI trend

Notes:

  • For many countries, the short-term interest rate was the 1-month local-currency LIBOR rate until December 2021.

  • At the end of 2021, LIBOR started to be phased out and was replaced on the 15th December 2021 by overnight index swap (OIS) rates in Switzerland, the Eurozone, Great Britain, Japan and the United States. Australia switched to OIS rates on the 1st September 2022. These rates have become the new standard.

  • The following currency areas have used rates other than the 1-month LIBOR rates (prior to the LIBOR reform) for the whole sample history:

    • Brazil: Interbank rate - interbank deposit certificates

    • Canada: 1 month term spot forward rate

    • Colombia: 3-month interbank rate (fixing)

    • Czech Republic: 2-week repo rate

    • New Zealand: 90-day bank bill rate

    • Taiwan: 1-year IRS rate

  • The Phillipines use the Manila interbank 1-month discount rate prior to the 2nd January 2006, after which the 1-month swap rate is used.

  • Russia uses the 1-month Moscow price rate prior to the 15th April 2011, after which the average of the Moscow price rate and the 1-month OIS rate is used.

  • Inflation expectation refers to a 1-year ahead estimated inflation expectation according to a Macrosynergy methodology. See notes on the category INFE1Y_JA here.

  • The latest CPI trend refers to the last recorded CPI growth trend (six months over previous six months), seasonally and jump-adjusted, using headline and core rates with equal weights. For more information, see the documentation here.

Real policy-driven interest rates#

Ticker: RPIR_NSA / RPIRB_NSA

Label: Real policy-driven short-term interest rate: expectations-based / backward looking

Definition: A 1-month money market rate or closest proxy that typically serves as an indication of local monetary policy: adjusted for inflation expectations / adjusted for latest CPI trend

Notes:

  • For most countries, the policy-driven and main short-term interest rates are identical. For some countries, there have been (or still are) better metrics for tracking monetary policy intentions. These include:

    • AUD: 1-month OIS rate

    • BRL: Overnight Selic rate

    • CHF: 1-month OIS rate and 1-month deposit rate

    • CLP: 3-month interbank rate (fixing)

    • EUR: 1-month OIS rate

    • INR: 1-month MIBOR and reverse repo rate

    • JPY: 1-month OIS rate

    • NZD: 1-month OIS rate

  • Inflation expectation refers to a 1-year ahead estimated inflation expectation according to a Macrosynergy methodology. See notes on the category INFE1Y_JA here.

  • The latest CPI trend refers to the last recorded CPI growth trend (six months over previous six months), seasonally and jump-adjusted, using headline and core rates with equal weights. For more information, see the documentation here.

Longer-term real IRS yields#

Ticker: RYLDIRS02Y_NSA / RYLDIRS05Y_NSA / RYLDIRS02YB_NSA / RYLDIRS05YB_NSA

Label: Real IRS yield: 2-year maturity, expectations-based / 5-year maturity, expectations-based / 2-year maturity, backward looking / 5-year maturity, backward looking

Definition: Main local interest rate swap yield minus inflation expections: 2-year maturity, adjusted for inflation expectations / 5-year maturity, adjusted for inflation expectations / 2-year maturity, adjusted for latest CPI trend / 5-year maturity, adjusted for latest CPI trend

Notes:

  • The nominal yield is the yield on the fixed receiver positions in the main interest rate swap contracts traded in the currency area.

  • Inflation expectation refers to a 2-year or 5-year ahead estimated inflation expectation according to a Macrosynergy methodology. See notes on the categories INFE2Y_JA and INFE5Y_JA here.

  • The latest CPI trend refers to the last recorded CPI growth trend (six months over previous six months), seasonally and jump-adjusted, using headline and core rates with equal weights. For more information, see the documentation here.

Imports#

Only the standard Python data science packages and the specialized macrosynergy package are needed.

import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import math

import json
import yaml

import macrosynergy.management as msm
import macrosynergy.panel as msp
import macrosynergy.signal as mss
import macrosynergy.pnl as msn


from macrosynergy.download import JPMaQSDownload

from timeit import default_timer as timer
from datetime import timedelta, date, datetime

import warnings

warnings.simplefilter("ignore")

The JPMaQS indicators we consider are downloaded using the J.P. Morgan Dataquery API interface within the macrosynergy package. This is done by specifying ticker strings, formed by appending an indicator category code <category> to a currency area code <cross_section>. These constitute the main part of a full quantamental indicator ticker, taking the form DB(JPMAQS,<cross_section>_<category>,<info>), where <info> denotes the time series of information for the given cross-section and category. The following types of information are available:

  • value giving the latest available values for the indicator

  • eop_lag referring to days elapsed since the end of the observation period

  • mop_lag referring to the number of days elapsed since the mean observation period

  • grade denoting a grade of the observation, giving a metric of real time information quality.

After instantiating the JPMaQSDownload class within the macrosynergy.download module, one can use the download(tickers,start_date,metrics) method to easily download the necessary data, where tickers is an array of ticker strings, start_date is the first collection date to be considered and metrics is an array comprising the times series information to be downloaded.

# Cross-sections of interest

cids_dmca = [
    "AUD",
    "CAD",
    "CHF",
    "EUR",
    "GBP",
    "JPY",
    "NOK",
    "NZD",
    "SEK",
    "USD",
]  # DM currency areas
cids_dmec = ["DEM", "ESP", "FRF", "ITL", "NLG"]  # DM euro area countries
cids_latm = ["BRL", "COP", "CLP", "MXN", "PEN"]  # Latam countries
cids_emea = ["CZK", "HUF", "ILS", "PLN", "RON", "RUB", "TRY", "ZAR"]  # EMEA countries
cids_emas = [
    "CNY",
    # "HKD",
    "IDR",
    "INR",
    "KRW",
    "MYR",
    "PHP",
    "SGD",
    "THB",
    "TWD",
]  # EM Asia countries

cids_dm = cids_dmca + cids_dmec
cids_em = cids_latm + cids_emea + cids_emas

cids = sorted(cids_dm + cids_em)
main = [
    "RIR_NSA",
    "RPIR_NSA",
    "RYLDIRS02Y_NSA",
    "RYLDIRS05Y_NSA",
    "RIRB_NSA",
    "RPIRB_NSA",
    "RYLDIRS02YB_NSA",
    "RYLDIRS05YB_NSA",
]

econ = [
    "NIR_NSA",
    "NPIR_NSA",
    "CPIC_SJA_P6M6ML6AR",
    "CPIC_SJA_P3M3ML3AR",
    "CPIH_SJA_P6M6ML6AR",
]  # economic context

mark = [
    "EQXR_NSA",
    "EQXR_VT10",
    "DU02YXR_NSA",
    "DU02YXR_VT10",
    "DU05YXR_NSA",
    "DU05YXR_VT10",
]  # market links

xcats = main + econ + mark
# Download series from J.P. Morgan DataQuery by tickers

start_date = "2002-01-01"
tickers = [cid + "_" + xcat for cid in cids for xcat in xcats]
print(f"Maximum number of tickers is {len(tickers)}")

# Retrieve credentials

client_id: str = os.getenv("DQ_CLIENT_ID")
client_secret: str = os.getenv("DQ_CLIENT_SECRET")

# Download from DataQuery

with JPMaQSDownload(client_id=client_id, client_secret=client_secret) as downloader:
    start = timer()
    df = downloader.download(
        tickers=tickers,
        start_date=start_date,
        metrics=["value", "eop_lag", "mop_lag", "grading"],
        suppress_warning=True,
        show_progress=True,
    )
    end = timer()

dfd = df

print("Download time from DQ: " + str(timedelta(seconds=end - start)))
Maximum number of tickers is 703
Downloading data from JPMaQS.
Timestamp UTC:  2023-07-19 16:21:21
Connection successful!
Number of expressions requested: 2812
Requesting data: 100%|███████████████████████████████████████████████████████████████| 141/141 [00:45<00:00,  3.12it/s]
Downloading data: 100%|██████████████████████████████████████████████████████████████| 141/141 [01:07<00:00,  2.07it/s]
Download time from DQ: 0:02:23.023349

Availability#

cids_exp = sorted(list(set(cids) - set(cids_dmec)))  # cids expected in category panels
msm.missing_in_df(dfd, xcats=main, cids=cids_exp)
Missing xcats across df:  []
Missing cids for RIRB_NSA:  []
Missing cids for RIR_NSA:  []
Missing cids for RPIRB_NSA:  []
Missing cids for RPIR_NSA:  []
Missing cids for RYLDIRS02YB_NSA:  ['RON', 'BRL', 'PEN', 'PHP', 'MYR']
Missing cids for RYLDIRS02Y_NSA:  ['RON', 'BRL', 'PEN', 'PHP', 'MYR']
Missing cids for RYLDIRS05YB_NSA:  ['RON', 'BRL', 'PEN', 'PHP', 'MYR']
Missing cids for RYLDIRS05Y_NSA:  ['RON', 'BRL', 'PEN', 'PHP', 'MYR']

Quantamental series’ of real interest rates are typically available from the early 2000s for most developed markets. China, Colombia, Russia and Thailand are notable late-starters. Time series’ for real swap yields are not available for the Phillipines, Malaysia, Brazil, Peru and Romania.

For the explanation of currency symbols, which are related to currency areas or countries for which categories are available, please view Appendix 1.

xcatx = main
cidx = cids_exp

dfx = msm.reduce_df(dfd, xcats=xcatx, cids=cidx)
dfs = msm.check_startyears(
    dfx,
)
msm.visual_paneldates(dfs, size=(18, 4))

print("Last updated:", date.today())
../_images/Real interest rates_18_0.png
Last updated: 2023-07-19
xcatx = main
cidx = cids_exp

plot = msm.check_availability(
    dfd, xcats=xcatx, cids=cidx, start_size=(18, 4), start_years=False
)
../_images/Real interest rates_19_0.png

Average vintage grading is higher for longer-dated yields as the long-dated inflation expectations are based more on concurrent inflation targets, which do not require vintage estimation.

xcatx = main
cidx = cids_exp

plot = msp.heatmap_grades(
    dfd,
    xcats=xcatx,
    cids=cidx,
    size=(18, 4),
    title=f"Average vintage grades from {start_date} onwards",
)
../_images/Real interest rates_21_0.png
xcatx = main
cidx = cids_exp

msp.view_ranges(
    dfd,
    xcats=xcatx,
    cids=cidx,
    val="eop_lag",
    title="End of observation period lags (ranges of time elapsed since end of observation period in days)",
    start="2002-01-01",
    kind="box",
    size=(16, 4),
)
msp.view_ranges(
    dfd,
    xcats=xcatx,
    cids=cidx,
    val="mop_lag",
    title="Median of observation period lags (ranges of time elapsed since middle of observation period in days)",
    start="2002-01-01",
    kind="box",
    size=(16, 4),
)
../_images/Real interest rates_22_0.png ../_images/Real interest rates_22_1.png

History#

Real short-term interest rates#

Real interest rates have been diverse across countries, in terms of means and standard deviations, and generally quite variable over time relative to their means.

xcatx = ["RIR_NSA", "RPIR_NSA"]
cidx = cids_exp

msp.view_ranges(
    dfd,
    xcats=xcatx,
    cids=cidx,
    sort_cids_by="mean",
    start=start_date,
    kind="box",
    title="Means and standard deviations of real short-term interest rates, expectations-based, since 2002",
    xcat_labels=["Real", "Real policy-driven"],
    size=(16, 8),
)
../_images/Real interest rates_26_0.png
xcatx = ["RIR_NSA", "RPIR_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start=start_date,
    title="Main and policy-driven real interest rates, expectations-based",
    title_adj=1.03,
    title_xadj=0.44,
    title_fontsize=27,
    legend_fontsize=17,
    label_adj=0.075,
    xcat_labels=["Real", "Real policy-driven"],
    ncol=4,
    same_y=False,
    size=(12, 7),
    aspect=1.7,
    all_xticks=True,
)
../_images/Real interest rates_27_0.png

Backward-looking inflation adjustment can lead to very different real rate estimates in times when the concurrent published inflation trend is well above or below the effective inflation target.

In inflationary periods, this leads to a greater compression in real rates. In temporary lowflation or deflation periods, the backward-looking real rates are typically higher.

xcatx = ["RIR_NSA", "RIRB_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start=start_date,
    title="Real expectations-based and backward-looking interest rates",
    title_adj=1.03,
    title_xadj=0.46,
    title_fontsize=27,
    legend_fontsize=17,
    label_adj=0.075,
    xcat_labels=["Expectation", "Backward"],
    ncol=4,
    same_y=False,
    size=(12, 7),
    aspect=1.7,
    all_xticks=True,
)
../_images/Real interest rates_29_0.png

Cross-sectional correlations of short-term real interest rates across currency areas have mostly been positive. Russia and China display notable idiosyncratic dynamics.

xcatx = "RIR_NSA"
cidx = cids_exp

msp.correl_matrix(dfd, xcats="RIR_NSA", cids=cidx, cluster=True, size=(20, 14))
../_images/Real interest rates_31_0.png

Longer-term real IRS yields#

As with short-term real interest rates, cross-sectional and intertemporal differences of longer-term real rates have been fairly wide relative to their means.

Most countries have experienced both negative and sizable positive real interest rates over the sample period.

xcatx = ["RYLDIRS02Y_NSA", "RYLDIRS05Y_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start=start_date,
    title="Real 2-year and 5-year interest rate swap yields, expectations-based",
    title_adj=1.03,
    title_fontsize=27,
    legend_fontsize=17,
    title_xadj=0.46,
    label_adj=0.075,
    xcat_labels=["2-year", "5-year"],
    ncol=4,
    same_y=False,
    size=(12, 7),
    aspect=1.7,
    all_xticks=True,
)
../_images/Real interest rates_34_0.png

Backward-looking inflation adjustment, for both 2-year and 5-year yields, can produce very different levels of estimated real swap yields compared to expectations-based adjustment.

xcatx = ["RYLDIRS02Y_NSA", "RYLDIRS02YB_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start=start_date,
    title="Real 2-year interest rate swap yields",
    xcat_labels=["Expectations-based", "Backward-looking"],
    title_adj=1.03,
    title_fontsize=27,
    title_xadj=0.45,
    legend_fontsize=17,
    label_adj=0.075,
    ncol=4,
    same_y=False,
    size=(12, 7),
    aspect=1.7,
    all_xticks=True,
)
../_images/Real interest rates_36_0.png
xcatx = ["RYLDIRS05Y_NSA", "RYLDIRS05YB_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start=start_date,
    title="Real 5-year interest rate swap yields",
    title_adj=1.03,
    title_xadj=0.44,
    title_fontsize=27,
    legend_fontsize=17,
    label_adj=0.075,
    xcat_labels=["Expectations-based", "Backward-looking"],
    ncol=4,
    same_y=False,
    size=(12, 7),
    aspect=1.7,
    all_xticks=True,
)
../_images/Real interest rates_37_0.png

Importance#

Empirical clues#

Most analysts would expect that higher real interest rates bode well for duration and high-grade fixed income returns, whilst poorly for equity returns.

Indeed, there is evidence of a positive association between real interest rates and subsequent monthly IRS returns in developed markets.

xcatx = ["RIR_NSA", "DU02YXR_NSA"]
cidx = cids_dmca

cr = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="M",
    lag=1,
    xcat_aggs=["mean", "sum"],
    start=start_date,
    years=None,
)

cr.reg_scatter(
    title="Real short-term interest rates and next-month IRS returns, 2-year maturity, developed markets, since 2002",
    labels=False,
    coef_box="upper left",
    xlab="Real short-term interest rate, expectations-based, % annualized",
    ylab="2-year IRS fixed receiver return",
)
../_images/Real interest rates_44_0.png
xcatx = ["RIR_NSA", "DU05YXR_NSA"]
cidx = cids_dmca

cr = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="M",
    lag=1,
    xcat_aggs=["mean", "sum"],
    start=start_date,
    years=None,
)

cr.reg_scatter(
    title="Real short-term interest rates and next-month IRS returns, 5-year maturity, developed markets, since 2002",
    labels=False,
    coef_box="upper left",
    xlab="Real short-term interest rate, expectations-based, % annualized",
    ylab="5-year IRS fixed receiver return",
)
../_images/Real interest rates_45_0.png

Moreover, there is evidence of a positive and significant relation between real swap yields and subsequent receiver returns in developed markets at a monthly frequency.

xcatx = ["RYLDIRS05Y_NSA", "DU05YXR_NSA"]
cidx = cids_dmca

cr = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="M",
    lag=1,
    xcat_aggs=["last", "sum"],
    start=start_date,
    years=None,
)

cr.reg_scatter(
    title="Real 5-year swap yields (expectations-based) and next-month IRS receiver returns, 5-year maturity, developed markets, since 2002",
    labels=False,
    coef_box="upper left",
    xlab="Real 5-year swap yields, expectations-based, % annualized",
    ylab="Next month 5-year IRS fixed receiver return",
)
../_images/Real interest rates_47_0.png

Finally, pooled OLS regression provides evidence that real yields have predictive power with respect to subsequent monthly (or quarterly) equity index future returns, at least in developed markets. Moreover, the positive intercept is highly statistically significant, meaning that the real yield needs to be quite large before the average cumulative equity index future return becomes negative.

xcatx = ["RYLDIRS05Y_NSA", "EQXR_NSA"]
cidx = list(set(cids_dmca) - set(["NOK", "NZD"]))

cr = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="M",
    lag=1,
    xcat_aggs=["last", "sum"],
    start=start_date,
    years=None,
)

cr.reg_scatter(
    title="Real 5-year swap yields (expectations-based) and subsequent equity returns for developed markets since 2002",
    labels=False,
    coef_box="lower left",
    xlab="Real 5-year swap yields, expectations-based, % annualized",
    ylab="Next month equity index future return",
)
../_images/Real interest rates_49_0.png
cr.ols_table()
                            OLS Regression Results                            
==============================================================================
Dep. Variable:               EQXR_NSA   R-squared:                       0.011
Model:                            OLS   Adj. R-squared:                  0.011
Method:                 Least Squares   F-statistic:                     22.99
Date:                Wed, 19 Jul 2023   Prob (F-statistic):           1.74e-06
Time:                        17:32:06   Log-Likelihood:                -5870.4
No. Observations:                2028   AIC:                         1.174e+04
Df Residuals:                    2026   BIC:                         1.176e+04
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==================================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
----------------------------------------------------------------------------------
const              0.8004      0.102      7.879      0.000       0.601       1.000
RYLDIRS05Y_NSA    -0.3088      0.064     -4.795      0.000      -0.435      -0.182
==============================================================================
Omnibus:                      184.265   Durbin-Watson:                   1.927
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              340.146
Skew:                          -0.615   Prob(JB):                     1.37e-74
Kurtosis:                       4.585   Cond. No.                         1.74
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

Appendices#

Appendix 1: Currency symbols#

The word ‘cross-section’ refers to currencies, currency areas or economic areas. In alphabetical order, these are AUD (Australian dollar), BRL (Brazilian real), CAD (Canadian dollar), CHF (Swiss franc), CLP (Chilean peso), CNY (Chinese yuan renminbi), COP (Colombian peso), CZK (Czech Republic koruna), DEM (German mark), ESP (Spanish peseta), EUR (Euro), FRF (French franc), GBP (British pound), HKD (Hong Kong dollar), HUF (Hungarian forint), IDR (Indonesian rupiah), ITL (Italian lira), JPY (Japanese yen), KRW (Korean won), MXN (Mexican peso), MYR (Malaysian ringgit), NLG (Dutch guilder), NOK (Norwegian krone), NZD (New Zealand dollar), PEN (Peruvian sol), PHP (Phillipine peso), PLN (Polish zloty), RON (Romanian leu), RUB (Russian ruble), SEK (Swedish krona), SGD (Singaporean dollar), THB (Thai baht), TRY (Turkish lira), TWD (Taiwanese dollar), USD (U.S. dollar), ZAR (South African rand).