R – Multi Day Hold Trading Logic – Replacing a for loop to back test multi hold day trading rules

I wanted to expand on some trading logic written over at FOSS trading blog. Joshua demonstrates how to back test 1 day hold strategies. Here is an example of one of his back test scripts.

RSI2 Back Test Script


We can look at one of the trading rules from the above back test script:

# Create the long (up) and short (dn) signals
sigup <- ifelse(rsi < 10, 1, 0)
sigdn <- ifelse(rsi > 90, -1, 0)

This is basically saying if rsi is below 10 go long, any time its not over 10 get out (it means you cant hold from 10 all way up to 90 for example). Then for going short, we short over 90 and any time rsi is not over 90 we are not short ( this means we cant short over 90 and hold all way to 10 for example)

The above long and short rules are essentially designed mostly for short term trading or 1 day trading hold times.

Lets expand on the above example and create a multi day trading rule.

We will use R and use a dummy data set to simulate an indicator:

# Random Indicator
any.indicator <- c(runif(1500, min=0, max=100))   #create random numbers between 0 and 100, create 1500 data points between that range
df <- data.frame(any.indicator)   # place the vector above into a data frame

# Create Entry and Exit Rule
# Ifelse statement (print 1 else 0)
# We want to buy when any.indicator is below 10, when below 10 we want to buy so signal.enter will = 1
# We want to exit our trade when any.indicator is over 90, when over  90 we want to sell so signal.exit will = 1
# This sets the boundary for our multi day hold
df$signal.enter <- ifelse(any.indicator < 10, 1,0)  # Buy when indicator is over 0
df$signal.exit <- ifelse(any.indicator > 90, 1,0)   # Sell when indicator is less than 0.  

# Generate Multi Day Hold Trading logic # Use this for loop
# This will find the first 1, in df$signal.enter, it will continue to loop until # we meet a df$signal.exit = 1. During our entry / exit, the loop will create a # df$signal == 1 on each row of the data frame so that we can back test multi
# day hold trades. Once we exit, the we will print 0's until we meet another
# df$signal.enter == 1.

df$signal[[1]] = ifelse(df$signal.enter[[1]] == (1), 1, 0)

for (i in 2:nrow(df)){
  df$signal[i] = ifelse(df$signal.enter[i] == (1), 1,
                              ifelse(df$signal.exit[i] == (1), 0,

The code above uses a for loop to create entry and exits for multi day hold trades. In this example we are buying any.indicator when its below 10 and selling when its over 90 . Or we can short when its above 90 and close the short when it reaches 10. The for loop above will become quite slow during large data sets. We can keep the ‘vectorized theme’ of R and we can use dplyr to replace the loop. This will speed up the code.

# Dplyr solution
library(dplyr) df %>%
  dplyr::mutate(signal = ifelse(signal.enter == 1, 1,
                    ifelse(signal.exit ==1, 0, 0)))

The code is more compact and produces the exact same result as the for loop above. It also runs much faster on larger data sets.

Full code with the dplyr solution replacing the for loop for multi day trading rules:

# Create random indicator
any.indicator <- c(runif(1500, min=0, max=100))
df <- data.frame(any.indicator)

# Ifelse statement (print 1 else 0)
# Create entry and exit signals
df$signal.enter <- ifelse(any.indicator < 10, 1,0)  # create enter signal
df$signal.exit <- ifelse(any.indicator > 90, 1,0) # create exit signal

# Multi day hold trading rules

df %>%
  dplyr::mutate(signal = ifelse(signal.enter == 1, 1,
                    ifelse(signal.exit ==1, 0, 0)))