user5552631
user5552631

Reputation:

Can someone help me clean up my r function?

This is my first ever post in regards to programming, so I apologize if am not using the proper terminology or posting in the right spot. I am extremely new to using r, and new to programming in general(except for a little VBA). I wrote a basic function that calculates the daily price return of a list of stock prices that are listed from newest price to oldest price. I think my code is a little sloppy and I could use some help cleaning it up. My purpose of creating "returnarray" was so that I could have the loop results stored to a variable instead of just printing.

One thing I would really like to do here is eliminate the need for "returnarray" and would instead like to have the results saved to whatever the user inputs. For example myreturns <- price.return(mydata) would yield a variable named myreturns, containing all of the returns, instead of creating returnarray. Find my code below, and thank you in advance.

    price.return <- function(mydata)
{
  returnarray <- c()
  tmp <- c()
  for (i in 1:length(mydata)-1)

  {
   tmp <- (((mydata[i]/mydata[i+1])-1))
   returnarray <- c(returnarray,tmp)
   returnarray <<- returnarray
  }

}

Upvotes: 2

Views: 109

Answers (3)

G. Grothendieck
G. Grothendieck

Reputation: 269774

Transferred from comments.

1) The function shown in the question does this:

price.return1 <- function(x) x[-length(x)] / x[-1] - 1  # similar to question

2) Index increasing in time It seems that the question is assuming that x[1] is the most recent point and x[length(x)] is the oldest point whereas the normal convention is that x[1] is the oldest point and x[length(n)] is the most recent, i.e. normally it is assumed that the index is increasing in time, so using this more usual convention it would be written like this:

price.return2 <- function(x) x[-1] / x[-length(x)] - 1 # assume index increasing in time

Example: To illustrate price.return2 with an example, suppose the prices are increasing 1, 2, 3, 4, 5 over time. Then we can write:

price.return2(1:5)
## [1] 1.0000000 0.5000000 0.3333333 0.2500000

so the return from 1 to 2 is 1 or 100%, the return from 2 to 3 is .5 or 50% and so on.

3) Same An alternate way to write it that is equivalent to price.return2 is:

price.return3 <- function(x) exp(diff(log(x))) - 1  # similar to price.return2

We can verify that price.return2 and price.return3 give similar answers for the input 1:5 like this:

all.equal(price.return2(1:5), price.return3(1:5))
## [1] TRUE

Note: that you might be interested in some of the functions in the zoo, xts, PerformanceAnalytics and quantmod packages. For even more see the Empirical Finance Task View .

Upvotes: 6

road_to_quantdom
road_to_quantdom

Reputation: 1361

One thing you should start getting used to is vectorization. The essence of R programming is using already built functions that are vectorized to help you out. For-looping in R isn't always the best choice especially if you can use vectors.

Also, you generally should provide data that can be easily replicated so that others can compare their results with you.

Well, welcome to R and here is a more efficient solution:

### always have replicable data at the beginning of your question
### this allows answers to verify that they are indeed doing what you want them to do
data <- data.frame(c(120.663499,122.047573,121.480003,
                     120.919998,121.059998,120.57,116.769997))
rownames(data) <- rev(seq(as.Date("2015/11/05"),as.Date("2015/11/11"),"days"))
colnames(data) <- "AAPL"

> data
               AAPL
2015-11-11 120.6635
2015-11-10 122.0476
2015-11-09 121.4800
2015-11-08 120.9200
2015-11-07 121.0600
2015-11-06 120.5700
2015-11-05 116.7700

### since your data is from newest to oldest, I have to switch them to oldest to newest
### this is the common convention used in finance. Also, packages like quantmod do this
### you can collect price data very quickly using quantmod

### its important to use rownames(data) that way the associated date stays with the price
data <- data[rev(rownames(data)),,drop=F]

> data
               AAPL
2015-11-05 116.7700
2015-11-06 120.5700
2015-11-07 121.0600
2015-11-08 120.9200
2015-11-09 121.4800
2015-11-10 122.0476
2015-11-11 120.6635

### we use the vectorized diff() function to calculate the difference between
### each consecutive price (Pt - Pt-1)
### we then divide that difference by the previous period's price
### in notation: (Pt-Pt-1)/Pt-1
res <- diff(data$AAPL)/data$AAPL[-length(data$AAPL)]

### Now I am just putting this in the data frame to show you how it might look
### in something in excel
res <- data.frame(data,"Returns"=c(NA,res))

I hope this helps. And if you are looking to continue to do this kind of work in R with financial prices, I strongly suggest learning to code in a fashion similar to this. Vectorization is super important. For-loops are generally the last thing you want to use. As data sets get bigger, your code gets exponentially slower.

Upvotes: 0

hodgenovice
hodgenovice

Reputation: 624

Someone may provide a cleaner solution, but hopefully this is at least a bit useful:

price.return <- function(mydata) {
  for (i in 1:length(mydata)-1) {
    mydata[i] <- mydata[i] / mydata[i+1] - 1
  }
  return(mydata[1:(length(mydata) - 1)])
}
  1. The main thing is use return() to return a value at the end of a function - this will stop you needing to create returnarray().
  2. I don't think you need to initialise your variables, although there's certainly no harm, and it may be good practice.

Upvotes: 1

Related Questions