Rolling your own

In the previous post I discussed my attempts at replicating a trend following algorithm. This post takes a short step back to discuss a prerequisite of running a futures trading strategy, joining the individual series together to create a continuous one.

Future instruments have an expiry date, so to trade trends that run longer than a single series you need to roll from one series to another. To simulate this in a backtest you first need to stitch them together in a fashion that replicates how you would roll when actually trading.

Rolling algorithm

The basic idea is that you roll from one future to the next at the point that the later expiring future is more liquid. There are a number of ways to determine this point, but I employed the one presented in Following the Trend, rolling when the open interest in the later future exceeds the earlier one.

In a textbook about this you will see a graph that looks something like below. The open interest in a future steadily builds before dropping off near expiry.

test_open_interest

The reality might not be too far off this ideal. For example, here’s a plot of the AUD/USD open interest. There’s a very clear cut-off when the market rolls from one contract to the next.

aud_open_interest

However it’s not always so clean. Here’s EuroSwiss across the same period.

euro_swiss_open_interest

As you can see it’s far less obvious. Rather than one series clearly taking over from another at one point, there are periods where the relative open interest in two series is quite closely matched. This has created situations where the rolling algorithm in the backtest doesn’t do what you would do in reality. For example, on the same EuroSwiss series there is an occasion where a series is rolled into on one day, and the very next day it is rolled out of. Each roll entails significant costs in terms of transaction fees and bid-ask spreads, so it would make no sense to do this. A more refined algorithm would be required to give a more accurate reflection of reality.

Backwardation and contango

A set of future series can either be in backwardation or contango, a description of the relative pricing levels for series on the same underlying but with different expiry dates. In the former case, futures with more distant expiry dates trade at a discount to closer expiries.

When stitching together future series the gap in prices at the roll needs to be removed to make them continuous. This has the effect of shifting historical prices either up or down, depending on whether the series is generally in backwardation or contango. A good example is natural gas.

ng = full_series_set$`Natural gas`
plot_series(window(ng$full_series, start=as.Date('2003-10-06'), end=as.Date('2014-05-23')), "Natural gas")

natural_gas

Plotting the natural gas series between 6th Oct 2003 and 23rd May 2014 gives the graph above, showing a strong downward trend.  So you might expect then that the underlying spot price would have followed the same downward trajectory during this period.  In fact I picked these dates because the spot price was identical at $4.40.  The reason for the trend is due the roll, natural gas being in a near permanent state of contango (at least partly due to the effect of storage costs on the underlying).

I mentioned in the previous post that R can be very useful for interactive analysis of data once you’re on top of the language and the data model. Here’s a good example. What this is doing is going through all the roll details for each future series. It returns the percentage of rolls in which the more distant future, to which we are rolling, is priced lower than the current future. So a high percentage here would indicate normal backwardation, a low percentage a tendency towards contango.

data.frame(percent_backwardation = sort(round(100 * sapply(full_series_set, function (x) {
    return (nrow(x$roll_details[x$roll_details$crossover_gap < 0,]) / nrow(x$roll_details))
}), 1)))

It gives the following results.

               percent_backwardation
Gold                             0.6
DAX                              1.5
Silver                           1.7
JPY/USD                          6.9
Rough rice                      11.0
CHF/USD                         11.7
Wheat                           13.4
Natural gas                     15.5
Corn                            17.2
Nikkei 225                      23.7
Cotton                          26.4
Soybeans                        26.4
Platinum                        26.4
Palladium                       27.1
S&P 500                         27.1
Nasdaq 100                      29.0
Oats                            30.6
Lumber                          31.2
FTSE 100                        31.4
Copper                          32.3
Heating oil                     34.7
Gasoil                          36.5
CAC Index                       40.4
Live cattle                     40.6
EUR/USD                         42.0
CrudeOil                        47.2
Euribor                         49.2
Lean hogs                       50.6
Short sterling                  52.9
EuroSwiss                       57.0
Hang Seng                       58.3
EuroDollar                      66.7
CAD/USD                         68.1
Schatz                          70.8
Long gilt                       74.3
Bund                            78.5
US 2-year                       81.1
GBP/USD                         81.9
AUD/USD                         85.5
US 10-year                      88.0
NZD/USD                         98.0

This is sort of as you’d expect for the most part. The storage costs associated with commodities mean they veer towards contango. In my series there was only one backwardation roll for gold, in August 2015, which ties in with reports in the press. DAX is an interesting one. This is quoted as a performance equity index, differing from other widely used equity indexes in that dividends are included. This removes the ex-dividend effect that would otherwise affect future spot price expectations.

However I was expecting natural gas to be nearer the top of this list. One reason it isn’t is probably due to the seasonal behaviour. So although on average it is heavily in contango, the seasonal effect on demand for the underlying affects the forward curve and hence creates periods of backwardation in the first two futures. If I plot the gaps between adjoining futures over time you can see how gold follows a relatively smooth path, but gas does exhibit a seasonal quality.

gold_gaps gas_gaps

Data quality

By chance I happened plot the Hang Seng series that I had just constructed from the corresponding sequence of futures. The graph is as below.

hang_seng

This looked very odd, surely volatility hadn’t increased that much since 2008? Indeed it had not. What had happened is that the scaling of the price changed in 2008, so that prices after that are reported as being 10 times those before. Since I was stitching them together, and removing any gaps at the roll, it gave the impression of being a continuous price series with a jump in volatility. The fix was a rather unsatisfying hack of selective rescaling, giving a more plausible looking graph below.

hs_rescaled

Conclusion

Before a backtest can be performed the basic future pricing data needs to be prepared. I was doing this by taking the free data from Quandl and stitching it together myself, but they also have a paid-for option where the data is cleaned and the roll performed in a variety of ways. I can now see the value in this. There will certainly be issues with my pricing data that I’ve not uncovered, and cases where my rolling algorithm doesn’t do the sensible thing.

This entry was posted in Finance, R. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *