I am trying to calculate the log returns of a dataset in R using the usual log differencing method. However, the calculated data is simply a vector of zeroes. I can't see what I'm doing wrong.

Here is the snippet showing what I'm doing

> prices <- data$cl
> head(prices)
[1] 1108.1 1095.4 1095.4 1102.2 1096.3 1096.7
> lrets <- log(lag(prices)) - log(prices)
> head(lrets)
[1] 0 0 0 0 0 0
> summary(lrets)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0       0       0       0       0       0 

What am I doing wrong?

  • 3
    $\begingroup$ lrets <- diff(log(prices)) $\endgroup$ Feb 6, 2012 at 11:55
  • 1
    $\begingroup$ @VishalBelsare you should add that as an answer. $\endgroup$ Nov 23, 2012 at 15:42
  • $\begingroup$ @Patrick Burns, vonjd, aajajim thanks to all of you for answering. I learned new information. $\endgroup$
    – thelearner
    Sep 21, 2016 at 12:39

7 Answers 7


You are simply doing $log(S_t) - log(S_t) = 0$ for all $t$. Instead, try

> n <- length(prices);
> lrest <- log(prices[-1]/prices[-n])

Should do the trick.

  • 13
    $\begingroup$ Or the more traditional, fewer characters: diff(log(prices)) which also works when 'prices' is a matrix with times in the rows and assets in the columns. The other lesson is that 'lag' doesn't do what we naively expect it to do. $\endgroup$ Feb 6, 2012 at 10:54
  • $\begingroup$ To be sure that lag works as you expect, it is much safer to store your time series as zoo or xts objects: if you use vectors (or even ts objects), many operations will discard or ignore the timestamps. $\endgroup$ Feb 6, 2012 at 11:48
  • $\begingroup$ hadnt noticed the "diff" function yet. A handy one, indeed. $\endgroup$
    – Nemis
    Feb 6, 2012 at 12:39
  • $\begingroup$ @PatrickBurns: +1 for your input. I preferred your more succinct syntax. Would have accepted that as an answer. $\endgroup$ Feb 6, 2012 at 13:06
  • $\begingroup$ i have been using diff(log(prices)) for a while, but was starting to doubt as it seems almost noone use it. thanks :) $\endgroup$
    – tagoma
    Jul 26, 2012 at 17:35

An easy way to perform what you need is do it this way:

if your data are daily then :

> prices <- data$cl
> log_returns <- diff(log(prices), lag=1)

would provide you with daily log returns, if you change the $lag=1$ to $lag=5$ then you will get weekly moving log returns.

  • $\begingroup$ While I have some experience in finance, I'm new to R (and this site). Question on this post, @aajajim: your suggestion looks very appealing, but another commenter suggests working in zoo, with which I am familiar. Since zoo allows for an irregular times series, how does your answer change if using zoo? $\endgroup$
    – W Barker
    Apr 15, 2014 at 18:28
  • $\begingroup$ Doesn't change at all, it's still the same code. At least for my zoo object the function he posted worked without any flaws. $\endgroup$
    – Olorun
    May 31, 2014 at 4:09

I think the simplest method for calculating log returns is ROC from the TTR package:

> data(ttrc)
> roc <- ROC(ttrc[,"Close"])



just to add another method:


for daily log returns, if you have daily prices.


This is inelegant, but is effective and will do the job.


Please note that it is possible to compress this even further, but with a loss of readability.

Also note, that you can sometimes get zeros because the number of significant digits you have set as your default is too few.

The argument against using this happens when you want to control an arbitrary number of lags. Manually slicing data as in the above could cause you to reinvent the wheel.


if you want to get rid of the first NA produced you can either start at 0 or omit the first row like this:

MSFT$Log_Returns <- diff(log(MSFT$Adjusted)); MSFT$Log_Returns[1] <- 0 # this will make the first row of your returns series equal 0, which arguably is correct for any starting date.

MSFT$Log_Returns <- diff(log(MSFT$Adjusted))
MSFT <- MSFT[2:nrow(MSFT),] # this option will remove the first row which is a NA and therefore not introduce a 0.

Both options work fine, hope it helps.


It is simplest with tidyverse:


data %>% 
mutate(across(stock_1:stock_n, ~ log(.x))) %>% 



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.