Commodity future returns #
This category group contains daily USD-denominated commodity future returns. These returns are based on positions in the front contract of the most liquid available future of each type of commodity.
Commodity future returns in % of notional #
Ticker : COXR_NSA
Label : Commodity future returns, % of notional.
Definition : Return on front future of selected global commodity, % of notional of the contract
Notes :
-
The return is the % change in the futures price. The return calculation assumes the future position is rolled (from front to second) on the first day of the month when the contract is deliverable.
-
For futures return calculations, the following groups of commodity contracts have been used: energy, base metals, precious metals, agricultural commodities and livestock.
-
For information on the components comprising each commodity group, see Appendix 1 .
Vol-targeted commodity future return #
Ticker : COXR_VT10
Label : Commodity future return for 10% vol target.
Definition : Return on front future of selected commodity contract, % of risk capital on position scaled to 10% (annualized) volatility target.
Notes :
-
Positions are scaled to a 10% volatility target based on the 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 further the related notes above on “Commodity return in % of notional” (
COXR_NSA
). -
For information on the components comprising each commodity group, see Appendix 1 .
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_nfm = ["GLD", "SIV", "PAL", "PLT"]
cids_fme = ["ALM", "CPR", "LED", "NIC", "TIN", "ZNC"]
cids_ene = ["BRT", "WTI", "NGS", "GSO", "HOL"]
cids_sta = ["COR", "WHT", "SOY", "CTN"]
cids_liv = ["CAT", "HOG"]
cids_mis = ["CFE", "SGR", "NJO", "CLB"]
cids = cids_nfm + cids_fme + cids_ene + cids_sta + cids_liv + cids_mis
# Define quantamental indicators (category tickers)
main = ["COXR_NSA", "COXR_VT10"]
econ = []
mark = []
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 50
Downloading data from JPMaQS.
Timestamp UTC: 2023-09-06 12:51:56
Connection successful!
Number of expressions requested: 200
Requesting data: 100%|█████████████████████████████████████████████████████████████████| 10/10 [00:03<00:00, 3.21it/s]
Downloading data: 100%|████████████████████████████████████████████████████████████████| 10/10 [00:15<00:00, 1.52s/it]
Download time from DQ: 0:00:23.108052
Availability #
cids_exp = cids
msm.missing_in_df(dfd, xcats=main, cids=cids_exp)
Missing xcats across df: []
Missing cids for COXR_NSA: []
Missing cids for COXR_VT10: []
The vast majority of commodity futures return series’ are available by 2000. Heating oil is the notable late-starter, only available from 2007 onwards.
For the explanation of commodity symbols, 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, 2))
print("Last updated:", date.today())
Last updated: 2023-09-06
xcatx = main
cidx = cids_exp
plot = msm.check_availability(
dfd, xcats=xcatx, cids=cidx, start_size=(18, 2), start_years=False
)
xcatx = main
cidx = cids_exp
plot = msp.heatmap_grades(
dfd,
xcats=xcatx,
cids=cidx,
size=(18, 2),
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 #
Commodity future returns in % of notional #
Daily returns have displayed modest differences in variations across commodities and a general proclivity to occasional outliers on both the negative and positive side. Natural gas has seen the greatest daily volatility, whilst aluminium, gold and cattle have been subject to the least.
Note: On April 20th 2020, during the COVID pandemic-related market turmoil, the front future price for WTI crude collapsed to a recorded -37 dollars from over 18 dollars, marking a loss of almost 300%. Since negative prices are not valid for standard return calculations, we have replaced the value by the average of the two surrounding days.
xcatx = ["COXR_NSA"]
cidx = cids_exp
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cidx,
sort_cids_by="std",
start=start_date,
kind="box",
title="Boxplots of commodity future returns, % of notional, since 2000",
xcat_labels=["Commodity future returns"],
size=(16, 8),
)
Long-term performance (since 2000) has been vastly different across commodities. Crude, Nickel, Palladium, Silver and Soy produced near 300% cumulative return, while aluminum, coffee and wheat recorded small negative returns.
xcatx = ["COXR_NSA"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start="2000-01-01",
title="Cumulative returns on USD-denominated commodity futures",
title_fontsize=27,
legend_fontsize=17,
cumsum=True,
title_adj=1.03,
title_xadj=0.52,
ncol=4,
same_y=True,
size=(12, 7),
aspect=1.7,
all_xticks=True,
)
Despite the vast long-term return differences, short-term commodity returns have been mostly positively correlated. Cattle, hogs, lumber, natural gas, and orange juice have been the most idiosyncratic contracts.
xcatx = "COXR_NSA"
cidx = cids_exp
msp.correl_matrix(
dfd,
xcats=xcatx,
cids=cidx,
title="Cross-sectional correlations for commodity future returns, since 2000",
size=(20, 14),
)
Vol-targeted commodity future returns #
Volatility targeting (on a monthly basis) can be perilous in the commodity space and produced some spectacular daily return outliers for targeted posititions, particularly in nickel, cotton, live cattle, gold and silver.
xcatx = ["COXR_VT10"]
cidx = cids_exp
msp.view_ranges(
dfd,
xcats=xcatx,
cids=cidx,
sort_cids_by="std",
start=start_date,
kind="box",
title="Boxplots of commodity future returns, 10% vol-target, since 2000",
xcat_labels=["Commodity future returns"],
size=(16, 8),
)
Volatility targeting makes a big difference in the long-term return performance. On a notional basis, the return differential between Brent and aluminum has been close to 200%, whilst on a vol-targeted basis, it was less than 30%.
xcatx = ["COXR_NSA", "COXR_VT10"]
cidx = cids_exp
msp.view_timelines(
dfd,
xcats=xcatx,
cids=cidx,
start=start_date,
title="Cumulative outright and vol-targeted returns on commodities future",
xcat_labels=["Standard", "Vol-targeted"],
title_fontsize=27,
legend_fontsize=17,
title_adj=1.03,
title_xadj=0.47,
cumsum=True,
ncol=4,
same_y=False,
size=(12, 7),
aspect=1.7,
all_xticks=True,
)
Importance #
Research links #
“Herding Behaviour in Commodity Markets…Broad basket commodities and energy-based ETFs are generally susceptible to herding across most frequencies…Agricultural and metal-based ETFs are least prone to herding in general.” Mand, Sifat, Ang and Choo
“We estimate the skewness of the unconditional distribution of energy returns (over past decades) and test its statistical significance…Our results show that crude oil (Brent and WTI) and Gasoline returns are negatively skewed while other energy returns such as Heating oil, Kerosene and Natural gas seem to be symmetrically distributed. This indicates that the returns of the former are likely to encapsulate more largely the effect of negative shocks and so present higher tail risk than those of the latter.” Carnero, Leon, and Niguez
“We estimate the skewness of the unconditional distribution of energy returns (over past decades) and test its statistical significance…Our results show that crude oil (Brent and WTI) and Gasoline returns are negatively skewed while other energy returns such as Heating oil, Kerosene and Natural gas seem to be symmetrically distributed. This indicates that the returns of the former are likely to encapsulate more largely the effect of negative shocks and so present higher tail risk than those of the latter.” Carnero, Leon, and Niguez
Appendices #
Appendix 1: Commodity group definitions and symbols #
The commodity groups considered are: energy, base metals, precious metals, agricultural commodities and livestock.
-
The energy commodity group contains:
-
BRT : ICE Brent crude
-
WTI : NYMEX WTI light crude
-
NGS : NYMEX natural gas, Henry Hub
-
GSO : NYMEX RBOB Gasoline
-
HOL : NYMEX Heating oil, New York Harbor ULSD
-
-
The base metals group contains:
-
ALM : London Metal Exchange aluminium
-
CPR : Comex copper
-
LED : London Metal Exchange Lead
-
NIC : London Metal Exchange Nickel
-
TIN : London Metal Exchange Tin
-
ZNC : London Metal Exchange Zinc
-
-
The precious metals group contains:
-
GLD : COMEX gold 100 Ounce
-
SIV : COMEX silver 5000 Ounce
-
PAL : NYMEX palladium
-
PLT : NYMEX platinum
-
-
The agricultural commodity group contains:
-
COR : Chicago Board of Trade corn composite
-
WHT : Chicago Board of Trade wheat composite
-
SOY : Chicago Board of Trade soybeans composite
-
CTN : NYBOT / ICE cotton #2
-
CFE : NYBOT / ICE coffee ‘C’ Arabica
-
SGR : NYBOT / ICE raw cane sugar #11
-
NJO : NYBOT / NYCE FCOJ frozen orange juice concentrate
-
CLB : Chicago Mercantile Exchange random length lumber
-
-
The (U.S.) livestock commodity group contains:
-
CAT : Chicago Mercantile Exchange live cattle composite
-
HOG : Chicago Mercantile Exchange lean hogs composite
-