Monetary aggregates #
This category group contains information states of growth and trends of nominal and real monetary aggregates. Monetary aggregates are banking system liabilities that at least partly function similar to traditional money. We use two definitions “narrow”, which is close to the concept of M1, and “broad”, which usually refers to the concept of M3 but in some countries has been preferable to use M2. Money growth can be indicative of liquidity growth, inflation pressure, and economic activity.
Narrow money growth #
Ticker : MNARROW_SJA_P1M1ML12 / _P1M1ML12_D1M1ML3 / _P3M3ML3AR / _P6M6ML6AR
Label : Narrow money, seasonally- and jump-adjusted: %oya / %oya, diff over 3m / % 3m/3m ar / % 6m/6m ar
Definition : Narrow money, seasonally- and jump-adjusted: % change over a year ago / % change over a year ago, difference over 3 months / % of latest 3 months over previous 3 months at an annualized rate / % of latest 6 months over previous 6 months at an annualized rate.
Notes :
-
Narrow money refers to the national definition of M1. M1 refers to the most liquid forms of money-like assets. All are liabilities of the banking system, including the central bank. Across most countries M1 includes physical currency in circulation, demand deposits that are accessible without restrictions, and, mainly in the past, traveler’s checks. There are some minor differences in the specific instruments included in M1 across countries, reflecting differences in financial systems, institutions, and regulations.
-
Seasonal adjustment factors are sequentially estimated as new data are released. This means that a new data vintage is created at every estimation.
-
Jump adjustment means that two types of outliers are adjusted for. Firstly, large “spikes” (i.e., two subsequent large moves of the seasonal index in opposite directions) are averaged. The causes for such spikes are often holiday shifts between two months, while the causes for jumps are often methodology changes. Secondly, large one-off jumps in the index are replaced by the local trend. The criteria for adjustment are statistically based on pattern recognition.
Ticker : RMNARROW_SJA_P1M1ML12 / _P1M1ML12_D1M1ML3 / _P3M3ML3AR / _P6M6ML6AR
Label : Real narrow money, seasonally- and jump-adjusted: %oya / %oya, diff over 3m / % 3m/3m ar / % 6m/6m ar
Definition : Real narrow money, seasonally- and jump-adjusted: % change over a year ago / % change over a year ago, difference over 3 months ago / % of latest 3 months over previous 3 months at an annualized rate / % of latest 6 months over previous 6 months at an annualized rate.
Notes :
-
Nominal narrow money is deflated by headline CPI to obtain real narrow money.
-
See notes on narrow money.
Broad money growth #
Ticker : MBROAD_SJA_P1M1ML12 / _P1M1ML12_D1M1ML3 / _P3M3ML3AR / _P6M6ML6AR
Label : Broad money, seasonally- and jump-adjusted: %oya / %oya, diff over 3m / % 3m/3m ar / % 6m/6m ar
Definition : Broad money, seasonally- and jump-adjusted: % change over a year ago / % change over a year ago, difference over 3 months / % of latest 3 months over previous 3 months at an annualized rate / % of latest 6 months over previous 6 months at an annualized rate.
Notes :
-
Broad money refers to M3 except for a few currency areas, which do not publish it. These are China (CNY), Israel (ILS), South Korea (KRW), Russia (RUB), Taiwan (TWD), and the United States (USD). In these cases we use M2 instead. Typically, M2 includes everything in M1, and adds savings deposits, time deposits, and money market mutual funds of retail clients. M3 usually includes everything in M2 plus, large time deposits, money market mutual funds of institutional clients, repurchase agreements, eurodollars, and some other still liquid assets.
-
Seasonal adjustment factors are sequentially re-estimated as new data are released. This means that a new data vintage is created at every estimation.
-
Jump adjustment means that two types of outliers are adjusted for. Firstly, large “spikes” (i.e., two subsequent large moves of the seasonal index in opposite directions) are averaged. The causes for such spikes are often holiday shifts between two months, while the causes for jumps are often methodology changes. Secondly, large one-off jumps in the index are replaced by the local trend. The criteria for adjustment are statistically based on pattern recognition.
Ticker : RMBROAD_SJA_P1M1ML12 / _P1M1ML12_D1M1ML3 / _P3M3ML3AR / _P6M6ML6AR
Label : Real broad money, seasonally- and jump-adjusted: %oya / %oya, diff over 3m / % 3m/3m ar / % 6m/6m ar
Definition : Real broad money, seasonally- and jump-adjusted: % change over a year ago / % change over a year ago, difference over 3 months / % of latest 3 months over previous 3 months at an annualized rate / % of latest 6 months over previous 6 months at an annualized rate.
Notes :
-
Nominal narrow money is deflated by headline CPI to obtain real narrow money.
-
See notes on broad money.
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 obtain the data. Here
tickers
is an array of ticker strings,
start_date
is the first release date to be considered and
metrics
denotes the types of information requested.
# 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",
"IDR",
"INR",
"KRW",
"MYR",
"PHP",
"SGD",
"THB",
"TWD",
] # EM Asia countries (without "HKD")
cids_dm = cids_dmca
cids_em = cids_latm + cids_emea + cids_emas
cids = sorted(cids_dm + cids_em)
# Quantamental categories of interest
main = [
# Real narrow
"RMNARROW_SJA_P1M1ML12",
"RMNARROW_SJA_P1M1ML12_D1M1ML3",
"RMNARROW_SJA_P3M3ML3AR",
"RMNARROW_SJA_P6M6ML6AR",
# Nominal narrow
"MNARROW_SJA_P1M1ML12",
"MNARROW_SJA_P1M1ML12_D1M1ML3",
"MNARROW_SJA_P3M3ML3AR",
"MNARROW_SJA_P6M6ML6AR",
# Nominal broad
"MBROAD_SJA_P1M1ML12",
"MBROAD_SJA_P1M1ML12_D1M1ML3",
"MBROAD_SJA_P3M3ML3AR",
"MBROAD_SJA_P6M6ML6AR",
# Real broad
"RMBROAD_SJA_P1M1ML12",
"RMBROAD_SJA_P1M1ML12_D1M1ML3",
"RMBROAD_SJA_P3M3ML3AR",
"RMBROAD_SJA_P6M6ML6AR",
]
# economic context
econ = [
"CPIH_SA_P1M1ML12",
"CPIC_SA_P1M1ML12",
"RGDP_SA_P1Q1QL4",
"INFTARGET_NSA",
"INFTEFF_NSA"
]
# market links
mark = [
"EQXR_VT10",
"EQCRY_VT10",
"EQXR_NSA",
"EQCRY_NSA",
"RIR_NSA",
"DU05YXR_VT10",
"DU10YXR_VT10",
"DU02YXR_VT10",
"FXXR_VT10",
"FXTARGETED_NSA",
"FXUNTRADABLE_NSA~"
]
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:
dfd = downloader.download(
tickers=tickers,
start_date=start_date,
metrics=["value", "eop_lag", "mop_lag", "grading"],
suppress_warning=True,
show_progress=True,
report_time_taken=True,
)
Maximum number of tickers is 1024
Downloading data from JPMaQS.
Timestamp UTC: 2024-09-19 13:53:39
Connection successful!
Requesting data: 100%|██████████| 205/205 [00:42<00:00, 4.88it/s]
Downloading data: 100%|██████████| 205/205 [01:00<00:00, 3.37it/s]
Time taken to download data: 120.13 seconds.
Some expressions are missing from the downloaded data. Check logger output for complete list.
376 out of 4096 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 9061 dates are missing.
Availability #
cids_exp = cids # cids expected in category panels
msm.missing_in_df(dfd, xcats=main, cids=cids_exp)
No missing XCATs across DataFrame.
Missing cids for MBROAD_SJA_P1M1ML12: []
Missing cids for MBROAD_SJA_P1M1ML12_D1M1ML3: []
Missing cids for MBROAD_SJA_P3M3ML3AR: []
Missing cids for MBROAD_SJA_P6M6ML6AR: []
Missing cids for MNARROW_SJA_P1M1ML12: []
Missing cids for MNARROW_SJA_P1M1ML12_D1M1ML3: []
Missing cids for MNARROW_SJA_P3M3ML3AR: []
Missing cids for MNARROW_SJA_P6M6ML6AR: []
Missing cids for RMBROAD_SJA_P1M1ML12: []
Missing cids for RMBROAD_SJA_P1M1ML12_D1M1ML3: []
Missing cids for RMBROAD_SJA_P3M3ML3AR: []
Missing cids for RMBROAD_SJA_P6M6ML6AR: []
Missing cids for RMNARROW_SJA_P1M1ML12: []
Missing cids for RMNARROW_SJA_P1M1ML12_D1M1ML3: []
Missing cids for RMNARROW_SJA_P3M3ML3AR: []
Missing cids for RMNARROW_SJA_P6M6ML6AR: []
Most developed countries have both broad and narrow countries available since the 1990’s with Sweden being an exception, and for the rest of countries they are available since the early 2000’s
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, 8))
print("Last updated:", date.today())
Last updated: 2024-09-19
plot = msm.check_availability(
dfd, xcats=xcatx, cids=cidx, start_size=(18, 8), start_years=False, start=start_date
)
Vintage grades are fairly uniform throughout the cross sections, with a lower average due to seasonal-adjustment reflecting a good proxy of real time data.
plot = msp.heatmap_grades(
dfd,
xcats=xcatx,
cids=cidx,
start=start_date,
size=(18, 8),
title=f"Average vintage grades, from {start_date} onwards",
)
narrow = [
"RMNARROW_SJA_P1M1ML12",
"MNARROW_SJA_P1M1ML12",
]
msp.view_ranges(
dfd,
xcats=narrow,
cids=cids_exp,
val="eop_lag",
title="End of observation period lags (ranges of time elapsed since end of observation period in days)",
start="2000-01-01",
kind="box",
size=(16, 4),
)
msp.view_ranges(
dfd,
xcats=narrow,
cids=cids_exp,
val="mop_lag",
title="Median of observation period lags (ranges of time elapsed since middle of observation period in days)",
start="2000-01-01",
kind="box",
size=(16, 4),
)
narrow = [
"RMBROAD_SJA_P1M1ML12",
"MBROAD_SJA_P1M1ML12",
]
msp.view_ranges(
dfd,
xcats=narrow,
cids=cids_exp,
val="eop_lag",
title="End of observation period lags (ranges of time elapsed since end of observation period in days)",
start="2000-01-01",
kind="box",
size=(16, 4),
)
msp.view_ranges(
dfd,
xcats=narrow,
cids=cids_exp,
val="mop_lag",
title="Median of observation period lags (ranges of time elapsed since middle of observation period in days)",
start="2000-01-01",
kind="box",
size=(16, 4),
)
History #
Narrow money #
Narrow money growth rates are prone to outliers. Credible inflation-targeting countries have posted similar ranges of expansion since the 1990s.
xcatx = [
"RMNARROW_SJA_P1M1ML12",
"MNARROW_SJA_P1M1ML12",
]
cidx = cids_exp
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cidx,
sort_cids_by="std",
start=start_date,
kind="box",
size=(16, 8),
title="Narrow money growth, jump-adjusted, % over a year ago",
xcat_labels=["Real", "Nominal"],
)
Narrow money growth has posted pronounced cycles over the past decades. Negative values are frequent occurrences.
xcatx = ["RMNARROW_SJA_P1M1ML12", "MNARROW_SJA_P1M1ML12"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start=start_date,
title="Narrow money, %oya",
xcat_labels=["Real", "Nominal"],
title_adj=1.02,
title_xadj=0.51,
title_fontsize=37,
legend_fontsize=17,
ncol=4,
same_y=False,
size=(16, 8),
aspect=1.7,
all_xticks=True,
)
Cross-country correlation of reported narrow money growth has been mostly positive, but Japan and some EM countries have shown mostly idiosyncratic behaviour.
xcatx = ["MNARROW_SJA_P1M1ML12"]
cidx = cids_exp
msp.correl_matrix(
dfx,
xcats=xcatx,
cids=cidx,
size=(20, 14),
cluster=True,
freq="M",
title="Monthly cross correlations of narrow money growth information states since 1993",
)
Broad money #
Broad money growth rates likewise show cyclical patterns but with many erratic movements.
xcatx = ["RMBROAD_SJA_P1M1ML12", "MBROAD_SJA_P1M1ML12"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start=start_date,
title="Broad money, %oya",
xcat_labels=["Real", "Nominal"],
title_adj=1.02,
title_xadj=0.51,
title_fontsize=37,
legend_fontsize=17,
ncol=4,
same_y=False,
size=(16, 8),
aspect=1.7,
all_xticks=True,
)
Cross-country correlation of M3 growth has been fairly diverse.
xcatx = ["MBROAD_SJA_P1M1ML12"]
cidx = cids_exp
msp.correl_matrix(
dfx,
xcats=xcatx,
cids=cidx,
size=(20, 14),
cluster=True,
freq="M",
title="Monthly cross correlations of narrow money growth information states since 1993",
)
Importance #
Research links #
“First, governments can capture real resources through base money creation (seigniorage) Seigniorage represents the real revenues a government acquires by using newly issued money to buy goods and non-money asset.” Macrosynergy
“Moreover, the moment investors anticipate inflationary financing, interest rates would rise, reducing the gains from debt monetization, up to the point of undermining its effectiveness altogether.” Macrosynergy
Empirical clues #
Since money growth is positively related to inflation, financial expansion an activity growth, it should negatively affect duration returns. And since few market participants follow money growth carefully, it should also be a predictor of future returns.
Indeed, there has been significant negative correlation between narrow money growth and subsequent 5-year or 2-year IRS fixed receiver returns, both at a monthly and quarterly frequency. Broad money growth posted similar predictive results. The negative correlation has been stable across sub-samples.
In the below analysis Turkey has been excluded to its massive data outliers.
cr_eq = msp.CategoryRelations(
dfd,
xcats=["MNARROW_SJA_P1M1ML12", "DU05YXR_VT10"],
cids=list(set(cids) - set(["TRY"])),
freq="Q",
lag=1,
xcat_aggs=["last", "sum"],
start="2000-01-01",
)
cr_eq.reg_scatter(
title="Nominal narrow money growth and subsequent 5-year duration returns, 27 DM/EM countries, since 2000",
labels=False,
coef_box="upper right",
xlab="Nominal narrow money, %oya, end-of-month information state",
ylab="5-year IRS fixed-receiver return, next quarter",
prob_est="map",
size=(9, 6),
)
DU05YXR_VT10 misses: ['BRL', 'PEN', 'PHP', 'RON'].
cr_eq = msp.CategoryRelations(
dfd,
xcats=["MBROAD_SJA_P1M1ML12", "DU05YXR_VT10"],
cids = list(set(cids)-set(["TRY"])),
freq="Q",
lag=1,
xcat_aggs=["last", "sum"],
start="2000-01-01",
)
cr_eq.reg_scatter(
title="Nominal broad money growth and subsequent 5-year duration returns, 27 DM/EM countries, since 2000",
labels=False,
coef_box="lower left",
xlab="Nominal broad money, %oya, end-of-month information state",
ylab="5-year IRS fixed-receiver return, next quarter",
prob_est="map",
separator=2012,
size=(9, 6),
)
DU05YXR_VT10 misses: ['BRL', 'PEN', 'PHP', 'RON'].
There is some evidence of a positive predictive relationship between short-term money growth, whether broad or narrow, and subsequent equity returns. The significantly positive forward correlation holds for both monthly and quarterly frequencies. It is stronger for emerging markets than for developed countries.
cids_eq = list(set(cids) - set(
["CLP", "COP", "CZK", "HUF", "IDR", "ILS", "NOK", "NZD", "PEN", "PHP", "RON", "RUB"]
)) # countries with equity index futures
cr_eq = msp.CategoryRelations(
dfd,
xcats=["MBROAD_SJA_P3M3ML3AR", "EQXR_NSA"],
cids=cids_eq,
freq="q",
lag=1,
xcat_aggs=["last", "sum"],
start="2000-01-01",
)
cr_eq.reg_scatter(
labels=False,
coef_box="lower right",
title="Money growth and subsequent equity index futures returns, 20 DM/EM countries, since 2000",
xlab="Broad money, % 3m/3m, seasonally and jump-adjusted rate",
ylab="Equity index futures return, next quarter",
prob_est="map",
size=(9, 6),
)
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 (Philippine 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).