2
$\begingroup$

I've been getting very confused on the topic of calculating returns. To get cumulative returns in time, log-returns are used, but apparently log-returns aren't used across different securities at a fixed time?

I would like to get cumulative returns as a function of time over my portfolio.

I have two securities, A and B. I buy one share of both A and B when the market opens and sell when it closes.

Suppose these are the prices for a specific day:

    open    close
A   9       10
B   10      8

My overall return for that day is (10+8)/(10+9) - 1 = -5.2%. I store that -5.2% for that day. I repeat this for many days. How do I then calculate my cumulative sum? If it helps, I'm doing this in python.

Side note: I can use a cumsum() function very easily in python, but that assumes log-returns. I have no issue working with log-returns, but I'm not sure how to go about doing that.

I will add that I always purchase 1 share of whatever security is in my portfolio for that day. The securities in my portfolio change over the course of time.

$\endgroup$

3 Answers 3

6
$\begingroup$

In Python, simple geometric returns:

    import numpy as np
    import pandas as pd
    sp500 = pd.io.data.DataReader('^GSPC', 'yahoo')['Close']
    simple_ret = sp500.pct_change()
    (1+simple_ret).cumprod()[-1] -1

    0.74751768460019963

Log-returns:

    log_ret = np.log(1+simple_ret)
    np.exp(log_ret.cumsum()[-1]) -1

    0.74751768460020074

In Quantitative Finance, doing your math in log-returns considered good manners, however for many practical applications (backtesting trading strategies e.g.), simple geometric returns suffice.

$\endgroup$
1
  • $\begingroup$ Those pieces of code are great -- thank you for that. I can very clearly see how to go back-and-forth between simple geometric returns and log-returns $\endgroup$
    – David
    Oct 8, 2015 at 14:32
1
$\begingroup$

When doing series like this in Python, I usually just add 1 to each return, then multiply across these sums for cumulative returns. Such as, if my returns over three days were -5.2%, 2.1% & 4.8%, then the values I would store would be:

1 + (-0.052) = 0.948

1 + (0.021) = 1.021

1 + (0.048) = 1.048

Then, to calculate my cumulative returns, I would just multiply (0.948)(1.021)(1.048) - 1 = 0.0144 or 1.44%.

This works especially well with arrays in Python, where you can store each return as an array in a larger array, allowing you to date index each part of the series then slice it however you want. Happy to work through the code for this if you provide me more detail on your data set.

$\endgroup$
4
  • $\begingroup$ Awesome, thank you. Just a follow up on your question. The cumulative return for 3 days is 1.44%. If I wanted cumulative return for 2 days, it would be (0.948)(1.021) - 1 = -3.2%. So when I'm running my cumprod() function over my entire DataFrame, I shouldn't include the minus one in my previous calculations, only at the end. In this sense, I can run cumprod() over the DataFrame and then applymap() to subtract 1 from every element -- is that correct? $\endgroup$
    – David
    Oct 7, 2015 at 14:58
  • $\begingroup$ So you're pulling the entire return series straight into a Dataframe and then calculating returns from there I'm assuming? Is it just one column of returns, or do you have a date index as well? $\endgroup$
    – Brumder
    Oct 7, 2015 at 15:04
  • $\begingroup$ I have a DataFrame where columns are dates and rows are users. For each user I calculate a return for that day. Each user has a different portfolio over time. According to your answer, I will then applymap() to add 1 to each return, and then make a new DataFrame from that which will calculate cumprod(). $\endgroup$
    – David
    Oct 7, 2015 at 15:08
  • $\begingroup$ You're correct- .applymap() will do the trick for the return series. You don't necessarily have to make a new Dataframe if you're series is large and you're trying to save memory, too; just overwrite the values when using .applymap(). Then, like you said, .cumprod() - 1 at the end should do it for you. $\endgroup$
    – Brumder
    Oct 7, 2015 at 15:20
0
$\begingroup$

A simple example of use of simple geometric returns vs log returns:

import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt

# Load the S&P 500 stock index data
sp500 = yf.download('^GSPC')

# Calculate the daily simple returns
simple_ret = sp500['Adj Close'].pct_change()

# Calculate the total return using simple returns
total_ret_simple = (1 + simple_ret).cumprod()

# Calculate the daily log returns
log_ret = np.log(1 + simple_ret)

# Calculate the total return using log returns
total_ret_log = np.exp(log_ret.cumsum())

# Plot the daily simple returns and daily log returns
fig, ax = plt.subplots(figsize=(10, 5))
simple_ret.plot(ax=ax, label='Simple Returns')
log_ret.plot(ax=ax, label='Log Returns')
ax.legend()
ax.set(title='Daily Returns of S&P 500', ylabel='Return')
plt.show()

# Plot the cumulative simple returns and cumulative log returns
fig, ax = plt.subplots(figsize=(10, 5))
total_ret_simple.plot(ax=ax, label='Simple Returns')
total_ret_log.plot(ax=ax, label='Log Returns')
ax.legend()
ax.set(title='Cumulative Returns of S&P 500', ylabel='Return')
plt.show()

# Print the difference between the two total returns
print('Difference between total returns:', total_ret_simple[-1] - total_ret_log[-1])
$\endgroup$

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.