FX forward volatility #

The category group includes basic generic estimates of historic annualized standard deviations of FX forward-returns and related generic leverage measures for 10% annualized volatility targets. Their main purpose in JPMaQS is to facilitate the adjustment of quantamental indicators, factors and returns for volatility across FX forward markets.

Annualized standard deviation of FX forward return #

Ticker : FXXRxEASD_NSA / FXXRUSDxEASD_NSA

Label : Annualized standard deviation of FX forward return: vs. dominant cross / vs. USD.

Definition : Annualized estimated standard deviation of 1-month FX forward return, % of notional, based on exponential moving average of daily returns: vs. dominant cross / vs. USD.

Notes :

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

  • The default returns are calculated for a contract that is long the local currency of the cross section against its dominant traded benchmark. For most currencies, the benchmark is the dollar. For some European currencies (Switzerland, the Czech Republic, Hungary, Norway, Poland, Romania, Sweden), the benchmark is the euro. For Great Britain, Turkey and Russia, an equally weighted basked of dollars and euros have been used.

  • A separate category for returns against the USD alone has been added for convenience.

  • For the following currencies, returns are based on non-deliverable contracts: IDR, INR, KRW, CNY, MYR and TWD.

  • For some currencies, returns include periods of low liquidity and FX targeting. If one wishes to ‘blacklist’ such periods one should use the non-tradability and FX-target dummies, which have category ticker codes FXUNTRADABLE_NSA and FXTARGETED_NSA .

  • A notable example of such a period is Malaysia in the early 2000s. The statistics in this period are artefacts of the managed exchange rate regime and the data generation process. It is not indicative of the actual exchange rate volatility, hence should be discounted from any analysis.

  • For more information on FX targeting, see the notes for FX tradeability and flexibility .

Leverage ratio of vol-targeted FX forward position #

Ticker : FXXRxLEV10_NSA / FXXRUSDxLEV10_NSA

Label : Leverage ratio of FX forward position for a 10% annualized vol target: based on dominant cross / based on USD.

Definition : FX forward leverage for a 10% annualized vol target, as a ratio of contract notional relative to risk capital on which the return is calculated: based on dominant cross / based on USD.

Notes :

  • This serves as the leverage ratio for a 10% annualized volatility target and is inversely proportional to the estimated annualized standard deviation of the return on a USD 1-month forward notional position.

  • The leverage ratio is capped to 5, in order to avoid excessive leverage in periods of FX pegs or dysfunctional markets.

  • See further the above related notes on “Annualized standard deviation of FX forward return” ( FXXRxEASD_NSA ).

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 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 os

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_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",
    "HKD",
    "IDR",
    "INR",
    "KRW",
    "MYR",
    "PHP",
    "SGD",
    "THB",
    "TWD",
]  # EM Asia countries
cids_dm = cids_dmca + cids_dmec
cids_em = cids_latm + cids_emea + cids_emas
cids = sorted(cids_dm + cids_em)
main = ["FXXRxEASD_NSA", "FXXRxLEV10_NSA", "FXXRUSDxEASD_NSA", "FXXRUSDxLEV10_NSA"]
econ = ["BXBGDPRATIO_NSA_12MMA", "FXCRY_NSA", "FXXRBETAvGDRB_NSA"]  # economic context
mark = ["FXXR_NSA", "FXXR_VT10", "FXTARGETED_NSA", "FXUNTRADABLE_NSA"]  # 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,
    )
    end = timer()

dfd = df

print("Download time from DQ: " + str(timedelta(seconds=end - start)))
Maximum number of tickers is 418
2023-03-27T14:55:54.883984  UTC
Number of expressions requested : 1672
Number of expressions returned  : 1376
(Number of unavailable expressions  : 296)
Some expressions were unavailable, and were not returned.
Check logger output for more details.
Number of missing time-series from the Database: 0.
Download time from DQ: 0:01:37.770946

Availability #

cids_exp = sorted(
    list(set(cids) - set(cids_dmec + ["HKD", "USD"]))
)  # cids expected in category panels
msm.missing_in_df(dfd, xcats=main, cids=cids_exp)
Missing xcats across df:  set()
Missing cids for FXXRUSDxEASD_NSA:  set()
Missing cids for FXXRUSDxLEV10_NSA:  set()
Missing cids for FXXRxEASD_NSA:  set()
Missing cids for FXXRxLEV10_NSA:  set()

Quantamental indicators for FX forward volatility are available from 2000 for most currency areas. The notable exceptions are Indonesia, Romania and Russia.

For the explanation of currency symbols, which are related to currency areas or countries for which categories are available, please view Appendix 1 .

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())
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/106719a3b6106acd68905b4404785e5899ef48c5657535c762462173547a12c4.png
Last updated: 2023-03-27
xcatx = main
cidx = cids_exp

plot = msm.check_availability(
    dfd, xcats=xcatx, cids=cidx, start_size=(18, 4), start_years=False
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/2e30f158deee9f6ed69372f75f7d07adab51330cefb613ca4a525308f8ec87a6.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/68738710589e3839fedb5421a6a008670548f4534315c309ba94f46109d39bb4.png https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/f124bdccd50cd767f8952ec694b9337c1810214e8364a1f30ebaf0f814d5a9c8.png

History #

Annualized standard deviations of FX forward return #

Across countries, average annualized standard deviations have ranged from under 5% to close to 20%. FX return variations was lowest for currencies with a high degree of exchange rate management by the central bank. Standard deviations have been quite diverse and time variant. RUB and TRY have exceeded 100% annualized volatility in past episodes.

xcatx = ["FXXRxEASD_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 FX forward return annualized standard deviations, since 2000",
    xcat_labels=["Annualised standard deviations of weighted daily returns"],
    size=(16, 8),
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/1283017bf1bffa7d2c204472e40d5db3328a7ff890e894dc721e9927fa8c4c88.png
xcatx = ["FXXRxEASD_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start="2000-01-01",
    title="FX forward volatility, exponential lookback, 11-day half-life, % ar",
    ncol=4,
    same_y=False,
    size=(12, 7),
    aspect=1.7,
    all_xticks=True,
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/326a89d486b9f60e510aca93fa3037ecfc148cdc5037621bfb3a00385ad38915.png

Correlation of FX volatility has been positive across currencies. However, CNY, which has been heavily managed by an effective exchange rate target, has been a notable exception. Also USDTRY/EURTRY and USDTHB forward volatility have been only weakly correlated with other volatilities.

xcatx = "FXXRxEASD_NSA"
cidx = cids_exp

msp.correl_matrix(
    dfd,
    xcats=xcatx,
    cids=cidx,
    title="Cross-sectional correlations for weighted FX forward return annualized standard deviations",
    size=(20, 14),
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/d4fa0eadc87ebd4d20e97336311ffdd0772e1c9a924cda7b4f75f31d8f64f6d5.png

Leverage ratios of vol-targeted FX forward positions #

Average leverage ratios across currencies have ranged from less than 1 to close to 4. The upper boundary of 5x leverage is typically reached in currency areas and periods of tight exchange rate targeting.

xcatx = ["FXXRxLEV10_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 leverage ratios of volatility-targeted FX forward positions",
    size=(16, 8),
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/4b3aabbac00dd370ef826fe9c1ef37dcc661b7f18fdbc0b3d1f57f85d3d625d1.png
xcatx = ["FXXRxLEV10_NSA"]
cidx = cids_exp

msp.view_timelines(
    dfd,
    xcats=xcatx,
    cids=cidx,
    start=start_date,
    title="Leverage ratios of vol-targeted FX forward positions",
    ncol=4,
    same_y=True,
    size=(12, 7),
    aspect=1.7,
    all_xticks=True,
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/31ca675dfbeafa73d9a13d9a6ea542c479cc9ab35a8f3c5c78841746d96c17f5.png

Importance #

Empirical Clues #

dfb = dfd[dfd["xcat"].isin(["FXTARGETED_NSA", "FXUNTRADABLE_NSA"])].loc[
    :, ["cid", "xcat", "real_date", "value"]
]
dfba = (
    dfb.groupby(["cid", "real_date"])
    .aggregate(value=pd.NamedAgg(column="value", aggfunc="max"))
    .reset_index()
)
dfba["xcat"] = "FXBLACK"
fxblack = msp.make_blacklist(dfba, "FXBLACK")
fxblack
{'BRL': (Timestamp('2012-12-03 00:00:00'), Timestamp('2013-09-30 00:00:00')),
 'CHF': (Timestamp('2011-05-02 00:00:00'), Timestamp('2016-06-30 00:00:00')),
 'CNY': (Timestamp('2000-01-03 00:00:00'), Timestamp('2023-03-24 00:00:00')),
 'CZK': (Timestamp('2014-01-01 00:00:00'), Timestamp('2017-07-31 00:00:00')),
 'HKD': (Timestamp('2000-01-03 00:00:00'), Timestamp('2023-03-24 00:00:00')),
 'ILS': (Timestamp('2000-01-03 00:00:00'), Timestamp('2005-12-30 00:00:00')),
 'INR': (Timestamp('2000-01-03 00:00:00'), Timestamp('2004-12-31 00:00:00')),
 'MYR_1': (Timestamp('2000-01-03 00:00:00'), Timestamp('2007-11-30 00:00:00')),
 'MYR_2': (Timestamp('2018-07-02 00:00:00'), Timestamp('2023-03-24 00:00:00')),
 'PEN': (Timestamp('2021-07-01 00:00:00'), Timestamp('2021-07-30 00:00:00')),
 'RON': (Timestamp('2000-01-03 00:00:00'), Timestamp('2005-11-30 00:00:00')),
 'RUB_1': (Timestamp('2000-01-03 00:00:00'), Timestamp('2005-11-30 00:00:00')),
 'RUB_2': (Timestamp('2022-02-01 00:00:00'), Timestamp('2023-03-24 00:00:00')),
 'SGD': (Timestamp('2000-01-03 00:00:00'), Timestamp('2023-03-24 00:00:00')),
 'THB': (Timestamp('2007-01-01 00:00:00'), Timestamp('2008-11-28 00:00:00')),
 'TRY_1': (Timestamp('2000-01-03 00:00:00'), Timestamp('2003-09-30 00:00:00')),
 'TRY_2': (Timestamp('2020-01-01 00:00:00'), Timestamp('2023-03-24 00:00:00'))}

There has been a clear positive concurrent correlation between FX volatility and forward carry across countries and periods.

xcatx = ["FXCRY_NSA", "FXXRxEASD_NSA"]
cidx = cids_exp

cr = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="M",
    lag=0,
    xcat_aggs=["mean", "mean"],
    start="2000-01-01",
    blacklist=fxblack,
    years=3,
)
cr.reg_scatter(
    title="Nominal FX forward carry and concurrent FX forward volatility, 3-year periods, global panel since 2000",
    labels=True,
    coef_box="lower right",
    xlab="Nominal 1-month FX forward carry",
    ylab="FX return volatility, exponential lookback window, 11-day half-life, % ar",
    reg_robust=True,
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/aae3115db290229cf308905c7e5247a8c2b7f544e3b67cf9aab72fabd27a5aa7.png

Historically, there has been a long-term negative correlation between FX volatility and basic external balances. Countries and periods with external deficits have been characterized by higher volatility.

xcatx = ["BXBGDPRATIO_NSA_12MMA", "FXXRxEASD_NSA"]
cidx = cids_exp

cr = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="M",
    lag=0,
    xcat_aggs=["mean", "mean"],
    start="2000-01-01",
    years=5,
    blacklist=fxblack,
)
cr.reg_scatter(
    title="Basic external balances and concurrent FX return volatility, 5-year periods, global panel since 2000",
    labels=True,
    coef_box="upper right",
    xlab="Basic external balance ratio, % of GDP",
    ylab="FX return volatility, exponential lookback window, 11-day half-life, % ar",
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/07b32f89032fe0f21e38a0bdaff50f3f44ed86b4d63d6a45ada04addd596a5fd.png

In the long run and across the full range of developed and EM countries there has been a positive relation between volatility and subsequent returns.

xcatx = ["FXXRxEASD_NSA", "FXXR_NSA"]
cidx = cids_exp

cr1 = msp.CategoryRelations(
    dfd,
    xcats=xcatx,
    cids=cidx,
    freq="Q",
    lag=1,
    xcat_aggs=["mean", "sum"],
    start="2000-01-01",
    blacklist=fxblack,
    years=None,
)
cr1.reg_scatter(
    title="FX volatility and subsequent quarterly returns, global panel since 2000",
    labels=False,
    coef_box="lower right",
    xlab="Average FX return volatility, % ar",
    ylab="Cumulative 1-month FX forward returns, next quarter",
    prob_est="map",
)
https://macrosynergy.com/notebooks.build/themes/shock-and-risk-measures/_images/1a4bc88bbca9d89f39f43a09ef1a50f1df720e3ea24d58f764343445862f5509.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).