Equity index future carry #
The category group contains daily indicators of equity index carry. These are based on equity yields and local nominal or real funding costs. A currency area’s equity yield is estimated based on analysts’ dividends and earnings expectations for the most liquid available local index.
Nominal equity index carry #
Ticker : EQCRY_NSA / EQCRY_VT10
Label : Nominal equity index future carry: % annualized / % annualized for 10% volatility target.
Definition : Estimated carry on main country equity index, based on the difference between (i) average of expected forward dividend and earnings yield and (ii) the main local-currency nominal short-term interest rate: % annualized of notional of the contract / % annualized of risk capital on position scaled to 10% (annualized) volatility target.
Notes :
-
The index-related predicted dividend and earnings yields are based on forecasts of the IBES sample of analysts. Since both yields are used for carry calculation and there is no universally accepted convention, JPMaQS uses an average of the 12-month forward expectations of earnings and dividend yields. We call this average the “equity yield”.
-
The nominal carry is the equity yield minus the local 1-month interbank or OIS rate or its closest proxy.
-
For volatility targeting, positions are scaled to 10% vol-target based on historic standard deviation for an exponential moving average with a half-life of 11 days. Positions are rebalanced at the end of each month.
-
See Appendix 1 for the list of equity indicies used for each currency area.
Real equity index carry #
Ticker : EQCRR_NSA / EQCRR_VT10
Label : Real equity index future carry: % annualized / % annualized for 10% volatility target.
Definition : Estimated carry on main country equity index, based on the difference between (i) average of expected forward dividend and earnings yield and (ii) the main local-currency real short-term interest rate: % annualized of notional of the contract / % annualized of risk capital on position scaled to 10% (annualized) volatility target.
Notes :
-
Real carry means that the conventional (nominal) carry is adjusted for the effect of expected inflation. Since high inflation does not conceptually reduce the equity yield, which is calculated on the basis of a real asset, but does reduce funding costs, which is calculated on the basis of a nominal liability, it is the only funding cost proxy that must be adjusted. Hence, rather than using a nominal interest rate, this carry indicator uses a real interest rate.
-
The real interest rate is the main local 1-month interbank or OIS rate, or closest proxy, minus inflation expectation. The latter are the 1-year ahead estimated inflation expectations according to Macrosynergy methodology.
-
See the notes on
INFE1Y_JA
in “Inflation expectations (Macrosynergy methodology)”.
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_dmeq = ["AUD", "CAD", "CHF", "EUR", "GBP", "JPY", "SEK", "USD"]
cids_eueq = ["DEM", "ESP", "FRF", "ITL", "NLG"]
cids_aseq = ["CNY", "HKD", "INR", "KRW", "MYR", "SGD", "THB", "TWD"]
cids_exeq = ["BRL", "TRY", "ZAR"]
cids_nueq = ["MXN", "PLN"]
cids = sorted(cids_dmeq + cids_eueq + cids_aseq + cids_exeq + cids_nueq)
main = ["EQCRR_NSA", "EQCRR_VT10", "EQCRY_NSA", "EQCRY_VT10"]
econ = ["INFE5Y_JA", "RIR_NSA"] # economic context
mark = [
"EQXR_NSA",
"EQXR_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 208
Downloading data from JPMaQS.
Timestamp UTC: 2024-02-23 12:38:04
Connection successful!
Requesting data: 100%|██████████| 42/42 [00:09<00:00, 4.37it/s]
Downloading data: 100%|██████████| 42/42 [00:11<00:00, 3.67it/s]
Some expressions are missing from the downloaded data. Check logger output for complete list.
48 out of 832 expressions are missing. To download the catalogue of all available expressions and filter the unavailable expressions, set `get_catalogue=True` in the call to `JPMaQSDownload.download()`.
Some dates are missing from the downloaded data.
2 out of 6302 dates are missing.
Download time from DQ: 0:00:25.011261
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 EQCRR_NSA: []
Missing cids for EQCRR_VT10: []
Missing cids for EQCRY_NSA: []
Missing cids for EQCRY_VT10: []
Quantamental indicators for equity index future carry are typically available, for developed markets, by the early 2000s. Many emerging markets only have data available from 2004 onwards.
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=(18, 4))
print("Last updated:", date.today())
Last updated: 2024-02-23
xcatx = main
cidx = cids_exp
plot = msm.check_availability(
dfd, xcats=xcatx, cids=cidx, start_size=(18, 4), start_years=False
)
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",
)
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),
)
History #
Equity carry in % of notional #
There have been large differences in real and nominal carry. Naturally, the nominal measure in high-inflation markets would have massively underestimated the real carry on a funded equity derivative. This illustrates that standard nominal equity carry can be misleading.
The importance of inflation suggests that real carry measures are economically more meaningful, even if there can be signficant estimation errors in real-time inflation expectations. Real carry measures are more even and comparable across countries.
xcatx = ["EQCRY_NSA", "EQCRR_NSA"]
cidx = cids_exp
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cidx,
sort_cids_by="mean",
start="2000-01-01",
kind="bar",
title="Means and standard deviations of real and nominal equity index carry, % of notional",
xcat_labels=["Nominal", "Real"],
size=(16, 8),
)
xcatx = ["EQCRY_NSA", "EQCRR_NSA"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start="2000-01-01",
title="Real and norminal equity index carry, % of notional",
title_fontsize=27,
legend_fontsize=17,
xcat_labels=["Nominal", "Real"],
ncol=4,
same_y=False,
size=(12, 7),
aspect=1.5,
all_xticks=True,
)
Cross-country correlations of real equity have been mostly postive since since 2000.
xcatx = "EQCRR_NSA"
cidx = cids_exp
msp.correl_matrix(
dfd,
xcats=xcatx,
cids=cidx,
title="Cross-sectional correlations of real equity index future carry, since 2000",
size=(20, 14),
)
Vol-targeted equity index carry #
Vol-targeted real equity carry has typically averaged 1%-5% across countries. Due to the combination of fast volatility-adjustment and sluggish equity yield revisions, the indicator has a lot more short-term variability than non-targeted carry. That volatility is all driven by recent market price fluctuations.
xcatx = ["EQCRY_VT10", "EQCRR_VT10"]
cidx = cids_exp
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cidx,
sort_cids_by="mean",
start="2000-01-01",
kind="bar",
title="Means and standard deviations of real and nominal equity index carry, % of notional, 10% vol-target",
xcat_labels=["Nominal", "Real"],
size=(16, 8),
)
xcatx = ["EQCRY_VT10", "EQCRR_VT10"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start="2000-01-01",
title="Real and nominal equity index carry, % of notional, 10% vol-targeting",
title_fontsize=27,
legend_fontsize=17,
xcat_labels=["Nominal", "Real"],
ncol=4,
same_y=True,
size=(12, 7),
aspect=1.5,
all_xticks=True,
)
Importance #
Research Links #
“Forward earnings yields and equity carry are plausible indicators of risk premia embedded in equity index futures prices. Data for a panel of 25 developed and emerging markets from 2000 to 2018 show that index forward earnings yields have been correlated with market uncertainty across countries and time. Earnings yields have been highest in emerging countries. However, equity carries have not, because they depend on local funding conditions and only indicate the country risk premium that is specific to equity. Both yield and carry metrics display convincing and consistent positive correlation with subsequent index futures returns. Simulations show that for proper equity long-short strategies active volatility adjustment of both signals and positions is essential in order to balance risk premia with the actual state of riskiness of the market.” Macrosynergy
“Forward earnings yields are a key metric for the valuation of an equity market. Helpfully, I/B/E/S and DataStream publish forward earnings forecasts of analysts on a market-wide index basis. Unfortunately, updates of these data are delayed by multiple lags. This can make them inaccurate and misleading in times of rapidly changing macroeconomic conditions. Indeed, there is strong empirical evidence that equity index price changes predict future forward earnings revisions significantly and for all of the world’s 25 most liquid local equity markets. This predictability can be used to enhance the precision of real-time earnings yield data and avoid misleading trading signals.” Macrosynergy
Empirical Clues #
There is some evidence of a positive correlation between real equity carry and subsequent returns at a monthly frequency, for developed markets.
xcatx = ["EQCRR_NSA", "EQXR_NSA"]
cidx = cids_dmeq
cr = msp.CategoryRelations(
dfd,
xcats=xcatx,
cids=cidx,
freq="Q",
lag=1,
xcat_aggs=["last", "sum"],
start="2000-01-01",
)
cr.reg_scatter(
title="Real equity carry and subsequent quarterly equity returns",
labels=False,
coef_box="lower right",
xlab="Historic real equity carry",
ylab="Equity index future return (next quarter)",
)
There is some evidence of predictive power in real equity carry for the direction of subsequent monthly equity returns, for developed markets. Moreover, real carry appears to be a better predictor of directional equity returns than nominal carry, with an increase in balanced accuracy of around 0.1.
sr = mss.SignalReturnRelations(
dfd,
rets=xcatx[1],
sigs=[xcatx[0], "EQCRY_NSA"],
cids=cids_dmeq,
)
sr.accuracy_bars()
Appendices #
Appendix 1: Equity index specification #
The following equity indices have been used for futures return calculations in each currency area:
-
AUD: Standard and Poor’s / Australian Stock Exchange 200
-
BRL: Brazil Bovespa
-
CAD: Standard and Poor’s / Toronto Stock Exchange 60 Index
-
CHF: Swiss Market (SMI)
-
CNY: Shanghai Shenzhen CSI 300
-
DEM: DAX 30 Performance (Xetra)
-
ESP: IBEX 35
-
EUR: EURO STOXX 50
-
FRF: CAC 40
-
GBP: FTSE 100
-
HKD: Hang Seng China Enterprises
-
INR: CNX Nifty (50)
-
ITL: FTSE MIB Index
-
JPY: Nikkei 225 Stock Average
-
KRW: Korea Stock Exchange KOSPI 200
-
MXN: Mexico IPC (Bolsa)
-
MYR: FTSE Bursa Malaysia KLCI
-
NLG: AEX Index (AEX)
-
PLN: Warsaw General Index 20
-
SEK: OMX Stockholm 30 (OMXS30)
-
SGD: MSCI Singapore (Free)
-
THB: Bangkok S.E.T. 50
-
TRY: Bist National 30
-
TWD: Taiwan Stock Exchange Weighed TAIEX
-
USD: Standard and Poor’s 500 Composite
-
ZAR: FTSE / JSE Top 40
For the older history of the Standard and Poor 500 (1990s), earnings yields have been used rather than the average of dividend and earnings yields.
See Appendix 2 for the list of currency symbols used to represent each cross-section.
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).