Streaks in equity prices and bond yields

This note updates a previous example on streaks in the US equity markets.

Streaks are defined as periods of increases and decreases in a quantity (such as a price) without a large interruption. An interruption occurs when there is a countermove greater than a given threshold. A well-known example of such streaks is the definition of equity bull and bear markets. The threshold is then typically set to 20%.

In fact, let us start with equity markets. We use data from Kenneth French's website at https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/: daily total-return data of the total market.

library("NMOF")
library("zoo")
P <- French(dest.dir = tempdir(),
            dataset = "market",
            frequency = "daily",
            price.series = TRUE,            
            na.rm = TRUE)

P <- zoo(P, as.Date(row.names(P)))
str(P)
‘zoo’ series from 1926-06-30 to 2022-08-31
  Data: num [1:25316, 1] 1 1 1.01 1.01 1.01 ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:25316] "1926-06-30" "1926-07-01" ...
  ..$ : chr "Market"
  Index:  Date[1:25316], format: "1926-06-30" "1926-07-01" ...

Function 'streaks' in package PMwR computes such streaks, i.e. series of uninterrupted up and down movements in a price series. The default threshold is set to 20%, since the function was originally written with equity returns in mind.

library("PMwR")
up.down <- streaks(P)
str(up.down)
head(up.down)
       start        end state     return
1 1926-06-30 1929-09-03    up  1.5589963
2 1929-09-03 1929-11-13  down -0.4358672
3 1929-11-13 1930-04-10    up  0.4359933
4 1930-04-10 1930-12-16  down -0.4384423
5 1930-12-16 1931-02-24    up  0.2661625
6 1931-02-24 1931-06-02  down -0.3172973
## ....

The plotseries package allows to plot such streaks.

library("plotseries")
par(cex.axis = 2)
plotseries(P, log.scale = TRUE)
equity-and-yield-streaks1.png
par(cex.axis = 2)
plotseries(window(P, start = as.Date("1990-1-1")),
           series.type = "streaks",
           streaks.up.labels.cex = 1)
equity-and-yield-streaks2.png

The small numbers at each up or down streaks shows the total return over the streak.

In the equity example above, function 'streaks' used returns, i.e. relative changes, to determine when up and down movements started and ended. For bond yields, it can be more appropriate to use differences, i.e. absolute changes.

Let's first get a series of yields: those of German 10-years government bonds.

library("bundesbank")

Y <- getSeries("BBSIS.D.I.ZAR.ZI.EUR.S1311.B.A604.R10XX.R.A.A._Z._Z.A",
               dest.dir = "~/Downloads/bundesbank", return.class = "zoo")
str(Y)
‘zoo’ series from 1997-08-07 to 2022-10-12
  Data: num [1:6390] 5.76 5.76 5.75 5.72 5.77 5.74 5.72 ...
 - attr(*, "info")= chr [1:4] "Yields, derived from the term structure ..."
  Index:  Date[1:6390], format: "1997-08-07" "1997-08-08" ...
par(cex.axis = 2)
plotseries(Y)

The plot shows the decline of interest rates during the previous decades, but also the spike that happened in 2021-22.

equity-and-yield-streaks3.png

We define a streak as an increase or decrease of yields by at least 100 basis points.

par(cex.axis = 2)
plotseries(window(Y, start = as.Date("1990-1-1")),
           series.type = "streaks",
           streaks.up = 1,
           streaks.relative = FALSE,
           streaks.up.labels.cex = 1)
equity-and-yield-streaks4.png