Skip to content
All library documents

Calculating Log Returns from Price Data in R

Article Quant Q&A · Author: Homunculus Reticulli

Summary

The document explains why an attempted R calculation returned zeros: it subtracts the logarithm of each price from the logarithm of that same price. Log returns instead compare prices at different observations, commonly by taking the difference between consecutive log prices. Equivalent approaches shown include differencing the logged price series, taking the log of adjacent price ratios, and using return functions from R packages.

The examples also distinguish daily returns from returns over longer intervals by changing the lag. Since differencing leaves the first observation without a preceding price, the resulting series typically has a missing first value; the document shows either keeping that value as missing or removing the row. One reply suggests setting it to zero, but that is a convention rather than an observed return. The examples address calculation mechanics, not data adjustments, missing prices, or downstream return analysis.

Key ideas

  • A log return compares prices from different observations rather than subtracting a log price from itself.
  • The difference between consecutive log prices equals the log of their price ratio.
  • Changing the lag produces returns over different observation intervals.
  • Differencing generally leaves the first return undefined because no earlier price is available.
  • R offers several ways to calculate log returns, including base functions and package helpers.

Tags

Full text
# Calculating log returns using R


# Calculating log returns using R












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?

## Answer by Nemis (score 17, accepted)

https://quant.stackexchange.com/a/2910

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.

## Answer by aajajim (score 10)

https://quant.stackexchange.com/a/9671

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.

## Answer by vonjd (score 8)

https://quant.stackexchange.com/a/2911

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

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

https://CRAN.R-project.org/package=TTR

## Answer by coderwannabe (score 2)

https://quant.stackexchange.com/a/38963

just to add another method:

```
>lrtn=diff(log(prices))
```

for daily log returns, if you have daily prices.

## Answer by Dave Harris (score 1)

https://quant.stackexchange.com/a/71399

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

```
prices<-c(1108.1,1095.4,1095.4,1102.2,1096.3,1096.7)
n<-length(prices)
lrets<-log(prices[2:n])-log(prices[1:(n-1)])
print(lrets)
summary(lrets)
```

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.

## Answer by Peter (score 0)

https://quant.stackexchange.com/a/55928

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

```
require(quantmod)
getSymbols("MSFT")
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.

## Answer by Mick (score 0)

https://quant.stackexchange.com/a/71396

It is simplest with tidyverse:

```
library(tidyverse)

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

Regards.

## Answer by Con Fluentsy (score 0)

https://quant.stackexchange.com/a/85498

If you download prices from quantmod, just use `dailyReturns(x,type = log)`

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.