Site icon Trading Analytics and Machine Learning

Understanding Returns of an Asset using Bitcoin

What are returns of an asset?

Returns are a method of measuring the change of value over time for an asset. While there are different calculations for computing the returns of an investment, in technical analysis, the most common calculations of a stocks return is the daily simple return, log-returns, and holding period returns (which incorporates dividends within the formula or a simple return).

This article will briefly cover the calculations and for the nominal returns, simple returns, and log returns since a multitude of other comparative calculations and indicators are calculated using these returns and form a foundation to understanding technical analysis.

Nominal, Simple, and Log Returns and their formulas

Norminal Returns

The nominal return is simply the difference between the ending value and the beginning value of an asset for any time period which can be seen in the formula presented below:

Nominal Returni=PiPi1Nominal Returni=Pi−Pi−1

Where:

  • P=Price of the assetP=Price of theasset

  • i=Current periodi=Currentperiod

  • i1=Previous periodi−1=Previousperiod

Simple Returns

This method of calculating returns is one of the most common as it is often presented as the daily returns for financial networks and websites. The formula is as follows:

Simple Returnsi=PiPi1Pi1Simple Returnsi=Pi−Pi−1Pi−1

Where:

  • P=Price of the assetP=Price of theasset

  • i=Current periodi=Currentperiod

  • i1=Previous periodi−1=Previousperiod

Log Returns

Log Returns is another common method of calculating returns since it has many mathematical advantages which will be discussed later. The formula to calculate the log returns is presented below:

Log Returnsi=lnPiPi1=lnPilnPi1Log Returnsi=ln⁡PiPi−1=ln⁡Pi−ln⁡Pi−1

Where:

  • P=Price of the assetP=Price of theasset
  • i=Current periodi=Current period
  • i1=Previous periodi−1=Previousperiod

Pros and Cons of the presented methods to calculate returns

In regards to the simple returns and the log returns, there are benefits and drawbacks for each of the methods.

For simple returns, they are easier to understand since the calculation is more intuitive and easy to calculate by hand. Moreover, simple returns are a direct calculation of the change of price of an asset as opposed to the log returns which has a similar result but is slightly different. However, there are still mathematical benefits to log returns as it is more normally distributed–an important attribute for a large amount of statistical models, and is additive, meaning that the summation of all of the returns is equivalent to the cumulative log return.

# Libraries and Preprocessing
library(quantmod)
library(tidyverse)
library(kableExtra)
library(gridExtra)
library(moments)

data <- getSymbols("BTC-USD", auto.assign = FALSE)
colnames(data) <- colnames(data) |> str_remove("BTC-USD.") |> tolower()
data <- data |> 
  as.data.frame() |> 
  select(close) |>
  mutate(log_ret = c(NA,diff(log(close))),
         simple_ret = c((close - lag(close))/lag(close)))
data |> format(scientific = FALSE) |> tail(n = 8) |> knitr::kable() |> kable_styling(bootstrap_options = c("striped", "hover"))
close log_ret simple_ret
2023-05-30 27702.350 -0.001570299422 -0.001569067147
2023-05-31 27219.658 -0.017577792723 -0.017424204555
2023-06-01 26819.973 -0.014792581991 -0.014683709248
2023-06-02 27249.590 0.015891611066 0.016018554269
2023-06-03 27075.129 -0.006422915434 -0.006402332604
2023-06-04 27119.066 0.001621483975 0.001622799291
2023-06-05 25760.098 -0.051410345699 -0.050111192238
2023-06-06 26987.117 0.046532918700 0.047632565203

A table is presented above to demonstrate the slight differences in the calculations between the two different methods of returns as well as the closing price. The difference between the simple return and log return can easily be compared accross the table.

Visualization of Returns

Returns over time

ret_o_t <- data |>
  mutate(date = as.Date(row.names(data))) |>
  na.omit() |>
ggplot(aes(x = date, y = log_ret)) +
  geom_point(size = .5) +
  geom_line(linewidth = .25) +
  theme_minimal() + 
  scale_x_date() +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(y = "Log Ret (%)") +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_text(size = 8))

ret_o_sr <- data |>
  mutate(date = as.Date(row.names(data))) |>
  na.omit() |>
ggplot(aes(x = date, y = simple_ret)) +
  geom_point(size = .5) +
  geom_line(linewidth = .25) +
  theme_minimal() + 
  scale_x_date() +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(y = "Simple Ret (%)") +
  theme(axis.title.x  = element_blank(),
        axis.title.y = element_text(size = 8))

price <- data |>
  mutate(date = as.Date(row.names(data))) |>
  na.omit() |>
ggplot(aes(x = date, y = close)) +
  geom_line() +
  theme_minimal() + 
  labs(x = "Date", y = "Price", title = "Price and Returns Over Time")

grid.arrange(price, ret_o_t, ret_o_sr, nrow = 3, heights = c(6, 3, 3))

When presenting the log returns, simple returns, and the asset price over time, there are a few observations that can be made. For instance, in some of the more extreme price movements, the simple returns have more extreme values when compared against the log returns.

Histogram of Log-Returns

hist_log_ret <- data |>
  na.omit() |>
ggplot() +
  geom_histogram(aes(x = log_ret, y = ..density..), bins = 400) +
  geom_density(aes(x = log_ret)) +
  theme_minimal() + 
  scale_x_continuous(labels = scales::percent_format(), limits = c(-.15, .15)) +
  labs(x = "Returns %", y = "Density", title = "Histogram of Log Returns")

hist_simp_ret <- data |>
  na.omit() |>
ggplot() +
  geom_histogram(aes(x = simple_ret, y = ..density..), bins = 400) +
  geom_density(aes(x = simple_ret)) +
  theme_minimal() + 
  scale_x_continuous(labels = scales::percent_format(), limits = c(-.15, .15)) +
  labs(x = "Returns %", y = "Density", title = "Histogram of Simple Returns")


grid.arrange(hist_log_ret, hist_simp_ret, ncol = 1)

Comparing the log and the simple returns of the overall historical price of Bitcoin, there is a visual similarity in the distribution of returns. Moreover, there one can observed that the returns for Bitcoin is centered around 0.0015795 for the log return and 0.0015807 for simple returns using a median calculation (the reason a median calculation is used is due to its robustness against outliers or extreme values). In addition, we can see the skewness is -0.7617865 and -0.1448892 for log and simple returns, respectively, with both negative skewness, and considering that the market is in a current down turn, there is a large presence of negative outliers so traders should expect to see small positive returns and large negative returns. But, since the skewness is relatively small depending on the calculation of returns used it the distributions can be considered relatively symmetric with a popular threshold of 0.5 and -0.5 for a distribution to be considered skewed.

Conclusion

There are different methods for calculating returns, in this article, the formulas for the nominal, simple, and log returns were covered as well as some of their drawbacks and their advantages. In most situations, the use of the returns will be based on the context of the analysts objectives. Moreover, returns will be further analyzed in a later article, including their distributions.

Code

library(quantmod)
library(tidyverse)
library(kableExtra)
library(gridExtra)

data <- getSymbols("BTC-USD", auto.assign = FALSE)
colnames(data) <- colnames(data) |> str_remove("BTC-USD.") |> tolower()
data <- data |> 
  as.data.frame() |> 
  select(close) |>
  mutate(log_ret = c(NA,diff(log(close))),
         simple_ret = c((close - lag(close))/lag(close)))
data |> format(scientific = FALSE) |> tail(n = 8) |> knitr::kable() |> kable_styling(bootstrap_options = c("striped", "hover"))


ret_o_t <- data |>
  mutate(date = as.Date(row.names(data))) |>
  na.omit() |>
ggplot(aes(x = date, y = log_ret)) +
  geom_point(size = .5) +
  geom_line(linewidth = .25) +
  theme_minimal() + 
  scale_x_date() +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(y = "Log Ret (%)") +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_text(size = 8))

ret_o_sr <- data |>
  mutate(date = as.Date(row.names(data))) |>
  na.omit() |>
ggplot(aes(x = date, y = simple_ret)) +
  geom_point(size = .5) +
  geom_line(linewidth = .25) +
  theme_minimal() + 
  scale_x_date() +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(y = "Simple Ret (%)") +
  theme(axis.title.x  = element_blank(),
        axis.title.y = element_text(size = 8))

price <- data |>
  mutate(date = as.Date(row.names(data))) |>
  na.omit() |>
ggplot(aes(x = date, y = close)) +
  geom_line() +
  theme_minimal() + 
  labs(x = "Date", y = "Price", title = "Price and Returns Over Time")

grid.arrange(price, ret_o_t, ret_o_sr, nrow = 3, heights = c(6, 3, 3))
Exit mobile version