Duration volatility risk premia #
The category group contains simple estimates of duration volatility risk premia based on interest rate swaps (IRS). They are calculated as the difference between implied and expected realized volatility divided by expected realized volatility. Conceptually, a positive volatility risk premium means that market participants demand a surcharge for exposure to rates volatility. Expected realized volatility is estimated by recent realized volatility, which is assumed to be an unbiased estimator over the short term.
Duration volatility risk premia (2-year duration) #
Ticker : IRVRP03M02Y_NSA / IRVRP06M02Y_NSA / IRVRP01Y02Y_NSA
Label : Volatility risk premia for 2-year IRS receivers with swaption maturity of: 3 months / 6 months / 1 year
Definition : IRS volatility risk premia for 2-year duration of the underlying receiver swap and swaption maturity of: 3 months / 6 months / 1 year
Notes :
-
Duration volatility risk premia are defined to be the difference between implied and realized volatility of forward-starting swap rates’ changes divided by the realized volatility of these rate changes. The metrics are unitless and refer to a fractional deviation.
-
Implied volatility is the parameter that yields the market price of a swaption when substituted into the option pricing formula under the assumption of an arithmetic Brownian motion.
-
Realised volatility is the standard deviation of an exponential moving average of daily forward-starting IRS yield changes with a half-life of 11 days, a convention frequently used for risk management.
-
The source of the underlying quotes is J.P. Morgan/Dataquery. Note that for the calculation of duration volatility risk premia, the use of IRS yields and returns are equivalent.
-
For more information on the calculations, see Appendix 1 .
Duration volatility risk premia (3-year duration) #
Ticker : IRVRP03M03Y_NSA / IRVRP06M03Y_NSA / IRVRP01Y03Y_NSA
Label : Volatility risk premia for 3-year IRS receivers with swaption maturity of: 3 months / 6 months / 1 year
Definition : IRS volatility risk premia for 3-year duration of the underlying receiver swap and swaption maturity of: 3 months / 6 months / 1 year
Notes :
-
See the important notes for ‘Duration volatility risk premia (2-year duration)’.
-
For further information on the volatility risk premia calculations, see Appendix 1 .
IRS volatility risk premia (5-year duration) #
Ticker : IRVRP03M05Y_NSA / IRVRP06M05Y_NSA / IRVRP01Y05Y_NSA
Label : Volatility risk premia for 5-year IRS receivers with swaption maturity of: 3 months / 6 months / 1 year
Definition : IRS volatility risk premia for 5-year duration of the underlying receiver swap and swaption maturity of: 3 months / 6 months / 1 year
Notes :
-
See the important notes for ‘Duration volatility risk premia (2-year duration)’.
-
For further information on the volatility risk premia calculations, see Appendix 1 .
Imports #
Only the standard Python data science packages and the specialized
macrosynergy
package are needed.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import math
import os
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 = [
"USD",
"EUR",
"GBP",
"NOK",
"PLN",
"SEK",
"CHF",
"JPY",
"ILS",
"ZAR",
]
tails = ["02Y", "03Y", "05Y"]
expiries = ["03M", "06M", "01Y"]
main = []
for e in expiries:
for t in tails:
main.append(f"IRVRP{e}{t}_NSA")
econ = ["FXXRxEASD_NSA", "BXBGDPRATIO_NSA_12MMA"] # economic context
mark = [
"EQXR_NSA",
"EQXR_VT10",
"FXXR_NSA",
"FXXR_VT10",
"DU05YXR_NSA",
"DU05YXR_VT10",
"DU02YXR_NSA",
"DU02YXR_VT10",
] # market links
xcats = main + econ + mark
# Download series from J.P. Morgan DataQuery by tickers
start_date = "2000-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()
assert downloader.check_connection()
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 190
Downloading data from JPMaQS.
Timestamp UTC: 2023-10-23 14:13:06
Connection successful!
Number of expressions requested: 760
Requesting data: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 38/38 [00:11<00:00, 3.18it/s]
Downloading data: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 38/38 [00:16<00:00, 2.31it/s]
Download time from DQ: 0:00:39.168976
Availability #
cids_exp = cids # cids expected in category panels
msm.missing_in_df(dfd, xcats=main, cids=cids_exp)
Missing xcats across df: []
Missing cids for IRVRP01Y02Y_NSA: []
Missing cids for IRVRP01Y03Y_NSA: []
Missing cids for IRVRP01Y05Y_NSA: []
Missing cids for IRVRP03M02Y_NSA: []
Missing cids for IRVRP03M03Y_NSA: []
Missing cids for IRVRP03M05Y_NSA: []
Missing cids for IRVRP06M02Y_NSA: []
Missing cids for IRVRP06M03Y_NSA: []
Missing cids for IRVRP06M05Y_NSA: []
Start dates for quantamental indicators of duration volatility risk premia are mixed, even for developed markets.
Disclaimer : JPMaQS has discovered an anomaly with the quality of swaption implied yield volatility data sources used in a number of emerging markets Interest Rate Variance Risk Premia indicators. Our sources are reviewing these datasets. While this process takes place, we have decided to suspend the following cross-sections: HKD, HUF and KRW.
Once the data sources complete their review, JPMaQS would revisit the data quality and are planning to resume the availability of these indicators in Q1 2024.
For the explanation of currency symbols, which are related to currency areas or countries for which categories are available, please view Appendix 2 .
xcatx = main
cidx = cids_exp
dfx = msm.reduce_df(dfd, xcats=xcatx, cids=cidx)
dfs = msm.check_startyears(
dfx,
)
msm.visual_paneldates(dfs, size=(12, 4))
print("Last updated:", date.today())
Last updated: 2023-10-23
xcatx = main
cidx = cids_exp
plot = msm.check_availability(
dfd, xcats=xcatx, cids=cidx, start_size=(12, 4), start_years=False
)
xcatx = main
cidx = cids_exp
plot = msp.heatmap_grades(
dfd,
xcats=xcatx,
cids=cidx,
size=(12, 4),
title=f"Average vintage grades from {start_date} onwards",
)
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=start_date,
kind="box",
size=(12, 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=start_date,
kind="box",
size=(12, 4),
)
History #
Premia for swaptions with 2-year duration #
Volatility risk premia, in most countries, have been positive since 2000. They have been highest for Switzerland and lowest for the United States.
xcatx = ["IRVRP03M02Y_NSA", "IRVRP06M02Y_NSA", "IRVRP01Y02Y_NSA"]
cidx = cids_exp
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cidx,
sort_cids_by="mean",
start="2000-01-01",
title="Means and standard deviations of volatility risk premia for IRS options, 2-year duration, since 2000",
xcat_labels=["3-month maturity", "6-month maturity", "1-year maturity"],
kind="bar",
size=(16, 8),
)
xcatx = ["IRVRP03M02Y_NSA", "IRVRP06M02Y_NSA", "IRVRP01Y02Y_NSA"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start="2000-01-01",
title="Volatility risk premia for IRS swap options, 2-year duration",
title_adj=0.92,
xcat_labels=["3-month maturity", "6-month maturity", "1-year maturity"],
ncol=3,
same_y=False,
# label_adj=0.05,
aspect=1.7,
all_xticks=False,
)
With exception of South Africa, volatility risk premia have been positively correlated across countries.
xcatx = "IRVRP06M02Y_NSA"
cidx = cids_exp
dfd_vrp7 = dfd[dfd["xcat"] == "IRVRP06M02Y_NSA"][
["real_date", "cid", "xcat", "value"]
].set_index("real_date")
dfw_vrp7 = dfd_vrp7.groupby(["cid", "xcat"]).resample("W").mean().reset_index()
# cidx = list(set(cids_exp) - set(["ZAR"]))
msp.correl_matrix(
dfw_vrp7,
xcats=xcatx,
cids=cidx,
title="Cross-sectional correlations of volatility risk premia for IRS swap options, 6-month maturity, 2-year duration, since 2000",
size=(20, 14),
)
Premia for swaptions with 3-year duration #
Volatility risk premia for 3-year duration swaps had a similar history to those with 2-year duration, albeit with slightly lower peaks in some episodes of high uncertainty.
xcatx = ["IRVRP06M02Y_NSA", "IRVRP06M03Y_NSA"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start="2000-01-01",
title="Volatility risk premia for IRS swap options, 6-month maturity",
title_adj=0.92,
xcat_labels=["2-year duration", "3-year duration"],
ncol=4,
same_y=False,
label_adj=0.05,
aspect=1.7,
all_xticks=False,
)
Premia for swaptions with 5-year duration #
For 5-year duration, peaks have not been as pronounced as for shorter durations.
xcatx = ["IRVRP06M02Y_NSA", "IRVRP06M05Y_NSA"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start="2000-01-01",
title="Volatility risk premia for IRS swap options, 6-month maturity",
title_adj=0.95,
xcat_labels=["2-year duration", "5-year duration"],
ncol=4,
same_y=False,
label_adj=0.05,
aspect=1.7,
all_xticks=False,
)
Importance #
Research Links #
“Volatility plays an important role in determining risk premiums that investors demand for bearing interest rate risk…The volatility of the yield curve is an important predictor of future bond returns…This volatility is better identified through interest rate options.” Joslin
“The analysis of the U.S. nominal term structure…shows that agents dislike high uncertainty and demand compensation for volatility risks. And the time variation of the term premium is driven by the compensation for inflation volatility risk that is distinct from consumption volatility risk. The central role of inflation volatility risk in explaining the time-varying term premium is consistent with other empirical evidence including survey data.” Doh
“Bond variance risk premia display pronounced spikes during crisis periods. We show that variance risk premia encompass a broad spectrum of macroeconomic uncertainty. Uncertainty about the nominal and the real side of the economy increase variance risk premia but uncertainty about monetary policy has a strongly negative effect. We document that bond variance risk premia predict excess returns on Treasuries,stocks, corporate bonds and mortgage-backed securities, both in-sample and out-of-sample. Furthermore, this predictability is not subsumed by other standard predictors.” Mueller, Vedolin and Yen
Empirical Clues #
Over the last 20 years, volatility risk premia have been negatively correlated with subsequent quarterly IRS receiver returns. The negative correlation was particularly prevalent in the largest, most liquid markets.
xcatx = ["IRVRP03M02Y_NSA", "DU02YXR_VT10"]
cidx = ["EUR", "USD"]
cr = msp.CategoryRelations(
dfd,
xcats=xcatx,
cids=cidx,
freq="Q",
lag=1,
xcat_aggs=["last", "sum"],
fwin=1,
start="2002-01-01",
)
cr.reg_scatter(
title="Volatility risk premia and subsequent duration returns (only USD and EUR)",
labels=True,
coef_box="upper right",
xlab="Volatility risk premium (3-m swaption, 2-y duration), end of quarter",
ylab="Vol-targeted 2-year IRS returns, next quarter",
)
Appendices #
Appendix 1: Calculation methodology #
The category group contains estimates of duration volatility risk premia , which are defined as the difference between implied and realized volatility of forward-starting interest rate swap rate differentials divided by the realized volatility of the same. Thus, the basic formula is simply:
where \(\sigma_i(\tau, \delta)\) is the volatility implied by the market for at-the-money swap options with time to maturity \(\tau\) and duration (“tail”) of the underlrying swap \(\delta\) , and \(\sigma_r(H)\) is the realised (historical) volatility, extracted using an exponentially weighted moving average filter of half-life \(H\) . The volatility risk premium is unitless and refers to the fractional deviation of implied volatility from realised volatility.
Notes :
-
Implied volatility is the paramter \(\sigma_i\) which when substituted into the option pricing formula for arithmetic Brownian motion yields the market price for swap options. It codifies the standard deviation of the underlying forward starting swap rate differential, and will generally be a function of both the strike of the option ( \(K\) ), the time to maturity of the option ( \(\tau\) ), and the duration of the underlying swap ( \(\delta\) ). This trivariate mapping \(\sigma_i: K \times \tau \times \delta \mapsto \mathbb{R}^+\) is known as the volatility cube (in contrast to e.g. the FX or equity market where we speak of volatility surfaces ).
-
Swap rates can go negative, which suggests that the standard Black-Scholes formula with log-normal returns is not appropriate. We define the forward starting swap rate \(F_t^{\tau, \delta}\) as the expected interest rate prevailing over the time interval \([\tau, \tau+\delta]\) . Formally we model the dynamics thereof as \begin{equation} dF_t^{\tau, \delta} = \sigma_i dW_t \end{equation} where \(dW_t\) is a Brownian increment. When we speak of the differential of a forward starting swap rate we mean the daily difference \begin{equation} r_t = F_t^{\tau, \delta} - F_{t-1}^{\tau, \delta}. \end{equation}
-
Realised volatility is here defined as the running standard deviation of forward starting swap rate differentials, exponentially weighted through time: \begin{equation} \sigma_{r,t} = \sqrt{252 \cdot \sum_{k=0}^\infty \lambda^k r_{t-k}^2}, \end{equation} where \(\lambda\) is a decay parameter. Following the RiskMetrics convention we set \(\lambda = 0.94\) , or identically, the half-life \(H\) equal to ~11 days (the value for \(k\) which renders \(\lambda^k \approx 0.5\) ). The \(\sqrt{252}\) is an annualisation factor reflecting the fact that swaps typically have 252 observation periods in a year. Assuming that returns are i.i.d.: \(\text{Var}[r_{\text{yearly}}]=\text{Var}[r_1+r_2+\cdots+r_{252}]=\text{Var}[r_1]+\text{Var}[r_2]+\cdots+\text{Var}[r_{252}]=252 \cdot\text{Var}[r_{\text{daily}}]\) .
-
Implied volatility codifies the market’s expectations of future uncertainty. Meanwhile realised volatility looks backwards in time. Empirical evidence suggests implied volatility tends to exceed realised volatility (the so-called premium).
Appendix 2: 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).