Testing Cryptocurrency Coin Price Series for Momentum, Mean Reversion, Random Walk

In this post we will test a modified version of the relative strength index to test for the presence of persistent momentum, mean reversion and random walk properties of coin price series.

The Relative Strength Indicator (RSI) was developed by J. Welles Wilder and published in a 1978 book, New Concepts in Technical Trading Systems, and in Commodities magazine (now Futures magazine) in the June 1978 issue (wikipedia).

The RSI can be calculated by:
U = close − close (Upward Change)
D = close − close (Downward Change)

If U is higher, then D = 0. If D is lower, then U = 0.

An (n) period exponential moving average is calculated over the U and D values.

The ratio of these averages is the relative strength or relative strength factor:
RS = EMA(U,n) / EMA(D,n)
n denoting the look back period.

The final RS ratio is converted into an index which oscillates between 0 and 100:

RS = 100 – (100/ 1+100)

In its classic form Wilder recommended a smoothing period of 14. Furthermore, a period of 14 days has been tested on the S&P500, (Adrian Ţăran-Moroşan(2011). The author of the paper selects RSI extreme signal levels of 30 and 70. Sell short the market over 70 and buy the market below 30. The test yielded poor results, however, there may be room for improvement in the look back period that has been selected. There is no consideration for the S&P500 half life of mean reversion. For example. If the S&P500 typically mean reverts on a period of less that 14 days, the classic 14 period would mask most signals. An optimal look back period equal to the half life of mean reversion may have yielded better results.

In this post we will examine a short term RSI set at an arbitrarily chosen look back period of 2 days. We select RSI extreme signal levels of 20 and 70 respectively. The strategy will buy the market when RSI2 is over 70 and will exit the trade when RSI2 drops below 85. Conversely, the strategy will buy the market when RSI2 is below 20 and will sell when RSI2 is over 70.

In essence, the two RSI models above test for momentum (buy high and sell higher) and test for mean reversion (buy low and sell high). Those series where both momentum and mean reversion models do not yield good results, those series may be considered random walks, where random walk series may be attributed to being difficult to predict.

Persistent price anomalies may exist in price series. If this holds true then the models above may show medium / long term stability of predictable returns.

Next, we download 1568 daily coin price series to .csv format using the crypto compare API. Using R we achieve this with the following code:

# Crypto Compare Coin Data
# Download using R
# Andrew Bannerman 11.29.2017


# Obtain coin list
response = fromJSON("https://www.cryptocompare.com/api/data/coinlist")
df = as.data.frame(data.table::rbindlist(response$Data, fill=TRUE))
# Write coin list to .csv
write.csv(df,file="D:/R Projects/Final Scripts/BitCoin Scripts/coin_list.csv")

# Load Tickets From Coin List
read.data <- read.csv("D:/R Projects/Final Scripts/BitCoin Scripts/coin_list.csv", header=TRUE, stringsAsFactors = FALSE)
tickers <- c(read.data$Symbol)
# Remove all * at end of file names
tickers <- gsub("[*]", "", tickers)

# Obtain API (information only)
#cc <- fromJSON("https://min-api.cryptocompare.com/")

# Download Daily Data
# Loop for downloading all .csvs
# Save each coin close plot
# Add error catching to loop
# Add completion time of each iteration
for (i in 1:length(tickers)) {
  next.coin <- tickers[i] # next coin in ticker vector
coin_daily <- fromJSON(paste0("https://min-api.cryptocompare.com/data/histoday?fsym=",next.coin,"&tsym=USD&allData=true&e=CCCAGG"))
df <- data.frame("time" = coin_daily$Data$time, "close" = coin_daily$Data$close,"open" = coin_daily$Data$open,"high" = coin_daily$Data$high,"low" = coin_daily$Data$low,"volumefrom" = coin_daily$Data$volumefrom,"volumeto" = coin_daily$Data$volumeto)
# Save plot out put to folder
# Set path, set png plot size
# ggplot 2 to create line plot
mytitle = paste0(next.coin)
graphics.off() # Close graphic device before next plot
p <- ggplot(df, aes(time)) +
  geom_line(aes(y=close), colour="red") +
  ggtitle(mytitle, subtitle = "") +
  theme(plot.title = element_text(hjust=0.5),plot.subtitle =element_text(hjust=0.5))
ggsave(path="D:/R Projects/Final Scripts/BitCoin Scripts/daily_plot",paste(next.coin,".png"))
# Save each file to .csv
write.csv(df,paste0(file="D:/R Projects/Final Scripts/BitCoin Scripts/data/",next.coin,".csv"))
ptm0 <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span><- proc.time()
ptm1=proc.time() - ptm0
cat('\n','Iteration',i,'took', time, "seconds to complete")
  }, error = function(e) { print(paste("i =", i, "failed:")) })

This coin universe will be used to test for mean reversion, momentum and random walk using RSI2.

An R script was setup to run the RSI2 momentum and mean reversion model on each coin series. No effort was made to restrict the starting date of each series, rather the entire price series was tested in each instance.

The end of day closing prices were used for testing. To avoid look ahead bias. When an RSI2 signal was triggered. The entry was placed on the exchange at the next days market open. Subsequently, a sell signal was closed out on the same day of the signal. In real life, the script would run 15 minutes before the close and any conditions met would close out prior to end of the day. In this back test, due to my absence of higher frequency coin data, this has not been included. The results would be for guidance only not for exact specifics. However, despite the 15 minute discrepancy, it should still serve as a basis for revealing mean reversion, momentum and random walk series.

No effort has been made to optimize parameters, optimize model parameters in and out of sample data, no statistical testing for mean reversion, momentum and no half life of mean reversion calibrations. These tests may aid in selecting optimal look back periods post initial RSI2 mean reversion, momentum screening and also avoid effects of look ahead bias and over optimization.

First, the top 50 momentum price series results are provided in table 1.0. To refresh, a momentum buy signal was generated when RSI2 closed over 70 and a sell signal generated when RSI2 crossed below 85. Note these parameters have been arbitrarily chosen. Data is sorted by top momentum cumulative returns.

Table 1.0 – Table sorted by highest momentum cumulative return

Lastly, the top 50 mean reversion price series results are provided in table 1.1. To refresh, a mean reversion buy signal was generated when RSI2 closed below 20 and a sell signal generated when RSI2 crossed above 70. Data is sorted by top mean reversion cumulative returns.

Table 1.1 – Table sorted by highest mean reversion cumulative return

The RSI2 momentum, mean reversion and random walk screening reveled a total of 202 momentum series, where momentum out performed buy and hold. A total of 1086 mean reversion series, where mean reversion out performed buy and hold. A total of 340 random walk series, where buy and hold out performed both momentum and mean reversion RSI2 models. Based on this test, it would appear that mean reversion is the dominating anomaly within the coin price series.


The series obtained from the above RSI2 screening should be further selected for in-sample optimization and out of sample testing. The below figure shows an example of how this process may be conducted and typically is referred to as the hold out method:

Example of hold out method for conducting in-sample optimization and out-of-sample testing

For each in-sample period (orange), the model parameters are optimized and subsequently selected for forward out of sample testing (green). At the end of the first out of sample test, the in-sample period is then re-set by the fixed in-sample look back period. The model parameters are once again optimized and used for subsequent out of sample testing. This process is repeated for the entire sample period.

To conclude, the RSI2 may be a simple method to test for momentum, buy high and sell higher and mean reversion, buy low and sell high. These attributes may provide an under lying anomaly which can be exploited using simple models. The RSI look back period of 2 was arbitrarily chosen. This may serve as a purpose for revealing momentum or mean reversion series.

Furthermore, the RSI 2 may not be the correct look back to use for the the specific series under examination. This would be true because each and every series display different rates of diffusion from the mean. Those with momentum properties move away from the mean at a higher rate than mean reversion series or a slower rate than random walk. Mean reversion series exhibit different variances from the mean and also different speeds of reversion to the mean. The former relating directly to how much profit can be achieved from the mean reverting series. The latter relating to the how long it takes for a series to revert to the mean. A mean reversion speed of 9 months may not be suitable for a shorter term trader, not to mention, may not be the best deployment of capital.

For further research, the speed of mean reversion may be calculated using the Ornstein-Uhlenbeck Formula which is presented in a previous post. An optimal look back period for a mean reversion series would be considered equal to the half life of mean reversion (Ernest P. Chan,2013).

In closing, it should also be noted that there is a large benefit to using statistical testing to confirm the presence of momentum, mean reversion and random walk. This is due to the fact that statistical tests cover all data points in a sample. Where a model that is pre-selected like the above RSI2, only considers days when the RSI2 trigger was active, thus eliminating many days from the sample (Ernest P. Chan,2013).

A statistical test for confirming momentum, mean reversion and random walk is the hurst exponent. This is presented in two previous posts:
Hurst exponent in R
Modelling the Hurst exponent in R

The augmented dickey fuller test may be used to confirm the presence of mean reversion. Where one may reject the null hypothesis.

Good trading!

Author: Andrew Bannerman

Integrity Inspector. Quantitative Analysis is a favorite past time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s