Today, we’ll revisit the relationship between the copper/gold price ratio and 10-year Treasury yields. Inflation and interest rates have been all the rage recently, along with the VIX (which we discussed several days ago here), and it feels like a good time to refresh on this concept.
Why do we care about the copper-gold price ratio and Treasury yields? First, both Jeff Gundlach and Adam Robinson say so, and that’s probably good enough. For good measure, the theory goes like this:
Copper is a useful industrial metal whose price tends to rise when the global economy expands. As firms produce more goods that require copper as an input, the increased demand for copper drives the price higher. Gold, on the other hand, is a somewhat less useful metal whose prices tends to rise when investors are fearful about a contracting global economy. Gold is a safe-haven investment, and a rising gold price signals either a contracting economy, investor fears of a contracting economy, or both. Gold prices tend to fall when the economy is humming along nicely. Thus, the copper-gold price ratio tends to be increasing when the economy is expanding.
The yield on 10-year Treasury Notes also tends to rise during economic expansion because investors’ inflation expectations are on the rise. When investors expect inflation to increase, they anticipate an uptick in interest rates (for those of you who are too young to remember what an interest rate is, take a look at rates in the mid-1980s) and start to seek higher yields today. That can drive down Treasury prices and increase yields.
Thus, we should observe a positive relationship between the copper-gold price ratio and 10-year yields. Both should be rising and falling based on the state of the world economy. There’s nothing too crazy here, but it’s an interesting relationship to think about and investigate. That’s what we’ll do today.
First, let’s import the time series data from Quandl. Note in particular our data sources: CME for copper and gold, and FRED for 10-year rates. But, we just need the Quandl codes, which are:
copper = CHRIS/CME_HG1 gold = CHRIS/CME_GC1 10-year = FRED/DGS10.1
Instead of using the Quandl()
function, we are going to use the tq_get()
function from tidyquant
and will specify the source with get = "quandl"
. Have a quick peek at the result because we have some wrangling ahead of us.
library(tidyquant)
library(tidyverse)
library(timetk)
library(highcharter)
library(Quandl)
# Quandl.api_key("your api key")
datasets <- c("CHRIS/CME_HG1", "CHRIS/CME_GC1", "FRED/DGS10.1")
commodities <-
datasets %>%
tq_get(get = "quandl",
from = "2000-01-01",
collapse = "daily") %>%
select(date, symbol, value, everything())
head(commodities)
## # A tibble: 6 x 11
## date symbol value open high low last change settle volume
## <date> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2000-01-04 CHRIS/CME… NA 0.844 0.846 0.836 NA NA 0.838 407
## 2 2000-01-05 CHRIS/CME… NA 0.835 0.848 0.832 NA NA 0.848 254
## 3 2000-01-06 CHRIS/CME… NA 0.840 0.845 0.840 NA NA 0.845 480
## 4 2000-01-07 CHRIS/CME… NA 0.843 0.850 0.843 NA NA 0.846 223
## 5 2000-01-10 CHRIS/CME… NA 0.844 0.844 0.838 NA NA 0.840 240
## 6 2000-01-11 CHRIS/CME… NA 0.839 0.841 0.838 NA NA 0.838 216
## # ... with 1 more variable: previous.day.open.interest <dbl>
Note that the data is long formatted in that there is one column for the symbol
variable but it’s pushed wide because gold and copper have an open, high, low, last, change, settle and volume column, and 10-years have a value column.
Let’s keep just the settle price for gold and copper, and just the value column for 10-years, along with date and symbol. We will call select(symbol, date, settle, value)
.
commodities %>%
select(symbol, date, settle, value)
## # A tibble: 13,840 x 4
## symbol date settle value
## <chr> <date> <dbl> <dbl>
## 1 CHRIS/CME_HG1 2000-01-04 0.838 NA
## 2 CHRIS/CME_HG1 2000-01-05 0.848 NA
## 3 CHRIS/CME_HG1 2000-01-06 0.845 NA
## 4 CHRIS/CME_HG1 2000-01-07 0.846 NA
## 5 CHRIS/CME_HG1 2000-01-10 0.840 NA
## 6 CHRIS/CME_HG1 2000-01-11 0.838 NA
## 7 CHRIS/CME_HG1 2000-01-12 0.859 NA
## 8 CHRIS/CME_HG1 2000-01-13 0.849 NA
## 9 CHRIS/CME_HG1 2000-01-14 0.854 NA
## 10 CHRIS/CME_HG1 2000-01-18 0.860 NA
## # ... with 13,830 more rows
Looking better, but it bothers me that we have two columns, settle
and value
for what should be one column called data
. To solve this, let’s create one new column to hold the settle price of gold and copper, and the value of of the ten-year. The logic here is to create a new column and populate with the number from settle
when there is an observation and with the number from value
when there is an observation. We will code that logic with mutate(data = case_when(value > 0 ~ value, settle > 0 ~ settle))
. That case_when()
is saying to set the news data
column equal to the observation from value
when value
is greater than 0 and equal to settle
when settle
is greater than 0.
commodities %>%
select(symbol, date, settle, value) %>%
mutate(data = case_when(value > 0 ~ value,
settle > 0 ~ settle)) %>%
select(symbol, date, data) %>%
head()
## # A tibble: 6 x 3
## symbol date data
## <chr> <date> <dbl>
## 1 CHRIS/CME_HG1 2000-01-04 0.838
## 2 CHRIS/CME_HG1 2000-01-05 0.848
## 3 CHRIS/CME_HG1 2000-01-06 0.845
## 4 CHRIS/CME_HG1 2000-01-07 0.846
## 5 CHRIS/CME_HG1 2000-01-10 0.840
## 6 CHRIS/CME_HG1 2000-01-11 0.838
I would like to clean up the symbol
column and give it better names instead of Quandl codes. I also want to shift this data to wide format so I can more easily create a ratio column. This means we can first spread()
the data back to wide format, then change the column names. We call spread(symbol, data)
and then colnames<-(c("date","gold", "copper", "ten_year"))
.
commodities %>%
select(symbol, date, settle, value) %>%
mutate(data = case_when(value > 0 ~ value,
settle > 0 ~ settle)) %>%
select(symbol, date, data) %>%
spread(symbol, data) %>%
`colnames<-`(c("date","gold", "copper", "ten_year")) %>%
head()
## # A tibble: 6 x 4
## date gold copper ten_year
## <date> <dbl> <dbl> <dbl>
## 1 2000-01-03 NA NA 6.58
## 2 2000-01-04 284 0.838 6.49
## 3 2000-01-05 282 0.848 6.62
## 4 2000-01-06 282 0.845 6.57
## 5 2000-01-07 283 0.846 6.52
## 6 2000-01-10 283 0.840 6.57
OK, that was quite a bit of work, and it was just wrangling our data into a shape where we can look at it, with nice column names. We even made it non-tidy, violating the rules of the tidyverse, but we’ll fix that later. For now, let’s add a column to hold the copper/gold ratio with mutate(cpr_gold_ratio = (copper*100)/gold)
.
commodities_df <-
commodities %>%
select(symbol, date, settle, value) %>%
mutate(data = case_when(value > 0 ~ value,
settle > 0 ~ settle)) %>%
select(symbol, date, data) %>%
spread(symbol, data) %>%
`colnames<-`(c("date","gold", "copper", "ten_year")) %>%
mutate(cpr_gold_ratio = (copper*100)/gold)
head(commodities_df)
## # A tibble: 6 x 5
## date gold copper ten_year cpr_gold_ratio
## <date> <dbl> <dbl> <dbl> <dbl>
## 1 2000-01-03 NA NA 6.58 NA
## 2 2000-01-04 284 0.838 6.49 0.295
## 3 2000-01-05 282 0.848 6.62 0.300
## 4 2000-01-06 282 0.845 6.57 0.299
## 5 2000-01-07 283 0.846 6.52 0.299
## 6 2000-01-10 283 0.840 6.57 0.297
We now have a new object called commodities_df
to hold our data and have a decision to make about how to visualize this data. We could put it back to long format and go with ggplot()
or leave it in wide format, change to xts
and use highcharter. Let’s go the highcharter route. We first convert to xts
with tk_xts(date_var = date)
.
commodities_xts <-
commodities_df %>%
tk_xts(date_var = date)
Our commodities_xts
object is ready to be passed to highcharter. Let’s chart the copper/gold ratio on the left hand y-axis and 10-year rates on the right hand y-axis.
highchart(type = "stock") %>%
hc_subtitle(text = "Ratio") %>%
hc_subtitle(text = "Copper-Gold and 10-year yields") %>%
hc_tooltip(crosshairs = TRUE, backgroundColor = c("#F8F8FF"),
shared = TRUE, borderWidth = 1) %>%
hc_yAxis_multiples(
list(
title = list(text = "copper-gold ratio"),
align = "left",
labels = list(format = "${value}"),
showFirstLabel = FALSE,
showLastLabel = FALSE, opposite = FALSE),
list(
title = list(text = "10-year rates"),
align = "right",
labels = list(format = "{value}%"),
showFirstLabel = FALSE, opposite = TRUE,
showLastLabel = FALSE)) %>%
hc_add_series(commodities_xts$cpr_gold_ratio,
name = "copper-gold ratio",
yAxis = 0) %>%
hc_add_series(commodities_xts$ten_year,
name = "10-year",
type = "spline",
yAxis = 1) %>%
hc_exporting(enabled = TRUE) %>%
hc_navigator(enabled = FALSE) %>%
hc_scrollbar(enabled = FALSE) %>%
hc_legend(enabled = TRUE)
It looks like the relationship has been positive and strong for most of the period 2000-Present and if this were our last snapshot, we might not notice much. Have a look, though, when we isolate just 2017 and 2018.
commodities_2017_18 <-
commodities_df %>%
filter(date >= "2017-01-01") %>%
tk_xts(date_var = date)
highchart(type = "stock") %>%
hc_subtitle(text = "Ratio") %>%
hc_subtitle(text = "Copper-Gold and 10-year yields") %>%
hc_tooltip(crosshairs = TRUE, backgroundColor = c("#F8F8FF"),
shared = TRUE, borderWidth = 1) %>%
hc_yAxis_multiples(
list(
title = list(text = "copper-gold ratio"),
align = "left",
labels = list(format = "${value}"),
showFirstLabel = FALSE,
showLastLabel = FALSE, opposite = FALSE),
list(
title = list(text = "10-year rates"),
align = "right",
labels = list(format = "{value}%"),
showFirstLabel = FALSE, opposite = TRUE,
showLastLabel = FALSE)) %>%
hc_add_series(commodities_2017_18$cpr_gold_ratio,
name = "copper-gold ratio",
yAxis = 0) %>%
hc_add_series(commodities_2017_18$ten_year,
name = "10-year",
type = "spline",
yAxis = 1) %>%
hc_exporting(enabled = TRUE) %>%
hc_navigator(enabled = FALSE) %>%
hc_scrollbar(enabled = FALSE) %>%
hc_legend(enabled = TRUE)
Now we see an interesting development at the beginning of 2018 (or maybe September 2017). 10-year rates started to increase rapidly and are now near 2.9%, whilst the copper/gold ratio remained flattish/declined a bit.
For fun, some possible explanations:
- 10-years are anticipating inflation but it hasn’t arrived yet.
- Copper/gold isn’t a good leading or present indicator of economic growth/inflation (Gundlach is wrong! I wouldn’t bet on that notion long term).
- One of these indicators is mispriced.
- A weaker dollar is keeping gold prices artificially high, depressing the copper/gold ratio, and that should start to change.
- The bond market isn’t worrying about inflation qua inflation, it’s worrying about central bank tightening, which seems to be coming our way regardless of the inflationary environment.
Before we close, let’s head to ggplot()
and use facet_wrap(~asset, scales = "free")
to create a separate chart for each of our assets. We will go back to the commodities_df
object, and convert to long-format with gather(asset, price, -date)
. Then make the call to ggplot()
.
commodities_df %>%
gather(asset, price, -date) %>%
ggplot(aes(x = date, y = price, color = asset)) +
geom_line() +
facet_wrap(~asset, scales = "free")
We can see that 10-year rates are still quite low, gold has come off its peak and Dr. Copper, well, it’s been a choppy ride.
It should be an interesting 2018, indeed! Thanks for reading and see you next time.