Copper/Gold and Ten-Year Treasuries

by Jonathan Regenstein

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:

  1. 10-years are anticipating inflation but it hasn’t arrived yet.
  2. 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).
  3. One of these indicators is mispriced.
  4. A weaker dollar is keeping gold prices artificially high, depressing the copper/gold ratio, and that should start to change.
  5. 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.

Share Comments ·