Directional risk basket carry#

The category group includes estimated carry measures of directional risk asset baskets for three asset classes: credit, equity, FX. A global composite is also provided.

The main purpose of generic risk basket carry is to serve as a benchmark for calculating relative carry of other contracts.

Nominal directional risk basket carry#

Ticker: DRBCRY_NSA

Label: Risk basket carry, % annualized.

Definition: Nominal expected carry on global asset class or composite (directional) basket of contracts, % annualized.

Notes:

  • Carry is defined as the return for unchanged market prices. For the credit (CDS index) basket, this is simply the spread implied by the default swap. For FX forwards, it is the 1-month forward implied interest rate differential. For equity, the carry needs to be estimated: market price is interpreted as the price of existing capital stock and carry is the difference between (i) the average of forward earnings and dividend yield and (ii) a short-term funding rate.

  • Note that real carry (DRBXR_CRR) is typically economically more meaningful than nominal carry.

  • The global directional risk basket and its constituent asset class baskets are sets of liquid contracts whose performance metrics are good proxies for key market segments, formed by macro-criteria. Rebalancing is monthly-based on either fixed or inverse volatility weights. Inverse volatility weights are based on exponential lookback windows of daily returns with a half-life of 11 days.

  • If a contract or composite is missing within a basket, the weights are transferred to the available contracts to produce a long and smooth history. Thus, the assumption is that if a contract is missing, the basket is formed by the remaining available contracts.

  • The global equity index future basket (GEQ) is a fixed-weighted composite of Standard and Poor’s 500 Composite (40%), EURO STOXX 50 (25%), Nikkei 225 Stock Average (10%) FTSE 100 (10%), and Hang Seng China Enterprises (15%).

  • The global credit index (GCR) is an inverse-volatility weighted basket of CDX and iTraxx investment-grade and high-yield indices for the U.S. and the euro area.

  • The global currency basket (GFX) focuses on small, emerging market and commodity currencies (excluding pegs) and is an inverse volatility-weighted composite of 1-month forward shorts in USD or EUR against AUD, INR, KRW, NOK, NZD, PLN, RUB, SEK, TRY, ZAR. See Appendix 1 for the explanation of currency symbols.

  • The global directional risk basket (GLB) is a volatility-weighted composite of the above 3 global asset class baskets. For older history where credit or currency baskets are not available, the remaining constituents have been used for convenience.

Real directional risk basket carry#

Ticker: DRBCRR_NSA

Label: Real risk basket carry, % annualized.

Definition: Real expected carry on global asset class or composite (directional) basket of contracts, % annualized.

Notes:

  • Real carry is nominal carry adjusted for inflation effects. Inflation trends conceptually erode the value of nominal assets, even if these are only implied in a derivatives position. For FX forwards, the implied nominal interest rate differential is adjusted by an expected inflation differential. For equity, the discount rate is converted into a real rate. Indeed without this adjustment, equity carry is understated in all countries that have positive inflation rates and massively understated in high inflation countries. For credit (default swaps), the real carry is equal to the nominal carry.

  • The importance of inflation suggests that real carry measures are economically more meaningful, even if there can be estimation errors in real-time inflation expectations.

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.

# Define cross sections (currency tickers)

cids = ["GCR", "GEQ", "GFX", "GLB"]
# Define quantamental indicators (category tickers)

main = ["DRBCRR_NSA", "DRBCRY_NSA"]
econ = []  # economic context
mark = ["DRBXR_NSA"]  # market links

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

start_date = "1990-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,
    )
    end = timer()

dfd = df

print("Download time from DQ: " + str(timedelta(seconds=end - start)))
Maximum number of tickers is 12
Downloading data from JPMaQS.
Timestamp UTC:  2023-06-02 16:02:37
Connection successful!
Number of expressions requested: 48
Download time from DQ: 0:00:15.372742

Availability#

cids_exp = cids  # cids expected in category panels
msm.missing_in_df(dfd, xcats=main, cids=cids_exp)
Missing xcats across df:  set()
Missing cids for DRBCRR_NSA:  set()
Missing cids for DRBCRY_NSA:  set()

The broad global directional risk basket carry series’ are available by the early 2000s.

The cross section identifiers refer to the global

  • CDS index basket (GCR),

  • equity index future basket (GEQ),

  • small, EM and commodity currency basket (GFX), and

  • cross-asset directional risk basket (GLB).

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())
../_images/Directional risk basket carry_16_0.png
Last updated: 2023-06-02
xcatx = main
cidx = cids_exp

plot = msm.check_availability(
    dfd, xcats=xcatx, cids=cidx, start_size=(18, 1), start_years=False
)
../_images/Directional risk basket carry_17_0.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",
)
../_images/Directional risk basket carry_18_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=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),
)
../_images/Directional risk basket carry_19_0.png ../_images/Directional risk basket carry_19_1.png

History#

Inflation adjustment reveals that real equity carry has historically (since 2000) been higher than real FX carry, opposite to what one would see in nominal carry metrics.

xcatx = ["DRBCRY_NSA", "DRBCRR_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 risk basket carries, since 2001",
    kind="bar",
    xcat_labels=["Nominal", "Real"],
    size=(16, 8),
)
../_images/Directional risk basket carry_22_0.png
xcatx = ["DRBCRY_NSA", "DRBCRR_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start="2000-01-01",
    title="Real and nominal risk basket carries",
    xcat_labels=["Nominal", "Real"],
    title_adj=1.02,
    title_xadj=0.45,
    # cumsum=False,
    ncol=2,
    same_y=False,
    size=(12, 7),
    aspect=1.5,
    label_adj=0.15,
)
../_images/Directional risk basket carry_23_0.png

Real carry has not generally been positively correlated across asset classes. In particular, FX carry has been largely uncorrelated from credit and equity.

xcatx = "DRBCRR_NSA"
cidx = cids_exp

msp.correl_matrix(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start="2000-01-01",
    title="Cross-sectional correlations for risk basket carry, since 2001",
    size=(10, 7),
)
../_images/Directional risk basket carry_25_0.png

Importance#

Empirical clues#

There is evidence of a positive correlation between real directional risk basket carry and subsequent cumulative monthly basket returns. This is consistent prior and post the 2008 financial crisis.

xcatx = ["DRBCRR_NSA", "DRBXR_NSA"]
cidx = cids_exp

cr = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="M",
    lag=1,
    xcat_aggs=["last", "sum"],
    xcat_trims=[11, 5],
    start="2001-01-01",
)

cr.reg_scatter(
    title="Risk basket (real) carry and subsequent cumulative monthly returns",
    coef_box="lower right",
    # labels=True,
    xlab="Risk basket carry",
    ylab="Risk basket return",
    separator=2008,
)
../_images/Directional risk basket carry_31_0.png

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