CDS index volatility #

This category group includes measures of historic return volatility and related leverage ratios for credit derivative swaps indices, particularly CDX and iTraxx investment-grade and high-yield indices for the U.S. and the euro area.

CDS index volatility #

Ticker : CRXRxEASD_NSA

Label : Estimated annualized standard deviation of CDS index return.

Definition : Annualized standard deviation of CDS index future return, % of notional, based on exponential moving average of daily returns.

Notes :

  • The standard deviation has been calculated based on an exponential moving average of daily returns with a half-time of 11 active trading days.

  • The source of the underlying market quotes is J.P. Morgan/DataQuery.

  • Returns are unfunded swap returns on the underlying CDS index based on J.P. Morgan calculation.

  • A new index series is determined on the basis of liquidity every six months. Positions are rolled accordingly.

Leverage ratio of vol-targeted CDS index position #

Ticker : CRXRxLEV10_NSA

Label : Leverage ratio of CDS index position for 10% annualized vol target.

Definition : CDS index leverage for a 10% annualized vol target, as ratio of contract notional relative to risk capital on which the return is calculated.

Notes :

  • Positions are scaled to a 10% volatility target based on historic standard deviations for an exponential moving average with a half-life of 11 days. Positions are rebalanced at the end of each month.

  • See further the related notes above on “CDS index volatility” ( CRXRxEASD_NSA ).

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.

cids_g2 = ["EUR", "USD"]
cids_cr = ["EIG", "EHY", "UIG", "UHY"]
cids = sorted(cids_g2 + cids_cr)
main = ["CRXRxEASD_NSA", "CRXRxLEV10_NSA"]
econ = ["PCREDITBN_SJA_P1M1ML12", "PCREDITGDP_SJA_D1M1ML12"]  # economic context
mark = ["CRXR_NSA", "CRXR_VT10", "CRCRY_NSA", "CRCRY_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_1 = df[df["cid"].isin(cids_cr)]
dfd_x = df[df["cid"].isin(["EUR", "USD"])]
dfd_2 = df.replace({"^EUR": "EIG", "^USD": "UIG"}, regex=True)
dfd_3 = df.replace({"^EUR": "EHY", "^USD": "UHY"}, regex=True)

dfd = pd.concat([dfd_1, dfd_2, dfd_3])

print("Download time from DQ: " + str(timedelta(seconds=end - start)))
Maximum number of tickers is 48
Downloading data from JPMaQS.
Timestamp UTC:  2023-06-02 23:20:49
Connection successful!
Number of expressions requested: 192
Requesting data: 100%|██████████████████████████| 10/10 [00:03<00:00,  3.20it/s]
Downloading data: 100%|█████████████████████████| 10/10 [00:16<00:00,  1.68s/it]
Download time from DQ: 0:00:22.030507

Availability #

cids_exp = cids_cr
msm.missing_in_df(dfd, xcats=main, cids=cids_exp)
Missing xcats across df:  set()
Missing cids for CRXRxEASD_NSA:  set()
Missing cids for CRXRxLEV10_NSA:  set()

JPMaQS contains four cross sections for CDS index performance data:

  • EHY: European high yield

  • EIG: European investment grade

  • UHY: U.S. high yield

  • UIG: U.S. investment grade

All series’ begin in the early 2000s.

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, 1))

print("Last updated:", date.today())
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/df695556d052ee083972fbab54c7e665548725b401c19571d39564c4412a1724.png
Last updated: 2023-06-03
xcatx = main
cidx = cids_exp

plot = msm.check_availability(
    dfd, xcats=xcatx, cids=cidx, start_size=(18, 1), start_years=False
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/ae302a65685c60c6428278dc5164291b5f9f43156cdd10449fdd8035b8c4bd7e.png
xcatx = main
cidx = cids_exp

plot = msp.heatmap_grades(
    dfd,
    xcats=xcatx,
    cids=cidx,
    size=(18, 1),
    title=f"Average vintage grades from {start_date} onwards",
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/cf4b6ac95e6d932439f53caa2b09cff4aa7317bcb87f5c150d09eff682aeb474.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=start_date,
    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=start_date,
    kind="box",
    size=(16, 4),
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/cde4068ccf361302f4407404eaed9786b1e9589b0d5fe899d2144d2e6b39faf4.png https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/9f842356c1cd9d6d01f6d8e458cad648a123e325913a08f0c281359d41e5c6e4.png

History #

CDS index volatility #

Average return volatility of high-yield indices has been near 7% (annualized) and for high-grade indices below 2%. In periods of market turmoil, high-yield volatility has soared to 35-40%.

xcatx = ["CRXRxEASD_NSA"]
cidx = cids_exp

msp.view_ranges(
    dfd,
    xcats=xcatx,
    cids=cidx,
    sort_cids_by="mean",
    start=start_date,
    kind="bar",
    title="Means and standard deviations of CDS index volatilities, since 2000",
    xcat_labels=["Standard deviation of weighted CDS index future returns"],
    size=(16, 8),
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/f532fac8c710d5900eb1d4906be50e9dae9e740e0e4aff9c99283d595475b604.png
xcatx = ["CRXRxEASD_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start=start_date,
    title="CDS index volatility across key market segments",
    title_adj=0.88,
    cumsum=False,
    ncol=2,
    same_y=False,
    size=(12, 7),
    aspect=2,
    all_xticks=True,
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/4698a609875ecacea93864cf4686c3cf4f3006be1ea3657871e7e2e695429d58.png

Leverage ratio of vol-targeted CDS index positions #

High-yield indices required on average more than 5 times the leverage of investment grade indices to pursure the same volatility target. Proclivity to high leverage was much greater prior to the subprime and great financial crises.

xcatx = ["CRXRxLEV10_NSA"]
cidx = cids_exp

msp.view_ranges(
    dfd,
    xcats=xcatx,
    cids=cidx,
    sort_cids_by="mean",
    start=start_date,
    title="Means and standard deviations of leverage ratios in vol-targeted CDS index positions",
    xcat_labels=["Leverage ratios"],
    kind="bar",
    size=(16, 8),
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/e0f011321f0702616fb5709cf0c7a3a697c478acef796022a0197991701866b9.png
xcatx = ["CRXRxLEV10_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start=start_date,
    title="Vol-targeted leverage ratio of CDS index positions across key market segments",
    title_adj=0.88,
    cumsum=False,
    ncol=2,
    same_y=False,
    size=(12, 7),
    aspect=2,
    all_xticks=True,
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/8643b0318ff809388c33ee4917d48f895b6cd90e01c501fbba506230ae34ad64.png

Importance #

Empirical Clues #

Historically, higher required leverage ratios have tended to entail higher vol-adjusted returns, possibly as compensation for tail risk.

There is some evidence to suggest that larger percentage changes in leverage ratios are associated with higher cumulative vol-adjusted returns.

xcatx = ["CRXRxLEV10_NSA", "CRXR_VT10"]
cidx = cids_exp

cr = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="Q",
    lag=0,
    xcat_aggs=["mean", "sum"],
    start="2000-01-01",
    xcat1_chg="pch",
    xcat_trims=[1.5, 20],
)
cr.reg_scatter(
    title="Percentage changes in leverage ratios and concurrent quarterly vol-targeted CDS index returns, since the early 2000s",
    labels=True,
    coef_box="lower right",
    xlab="% change in leverage ratio based on 10% vol target",
    ylab="Cumulative vol-adjusted return",
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/f8cdb7f3171c305b7e07cb80a2a18dedb09fd3414a3805f8f69cdbfdc33c6d58.png