Fundamentals of Return Calculations¶
Here we discuss a lot of the essential functionality for asset return calculations. We first cover simple return calculations, which are typically reported in practice but are often not convenient for statistical modeling purposes. We then describe continuously compounded return calculations, which are more convenient for statistical modeling purposes.
Customarily, we import as follows:
In [1]: import quantopy as qp
To begin, let’s create some example stock prices like we did in the 10 minutes to quantopy section:
In [2]: stock1_price = [10, 12, 15]
In [3]: stock2_price = [30, 20, 35]
Simple Returns¶
Consider purchasing an asset (e.g., stock, bond, ETF, option, etc.) at time t-1 for the price Pt-1, and then selling the asset at time t for the price Pt. If there are no intermediate cash flows (e.g., dividends) between t-1 and t, the simple net return on an investment in the asset between t−1 and t is defined as:
And we can define the simple gross return as:
ReturnSeries.from_price() gives a ReturnSeries with simple returns calculated from
a given price for a single asset, letting quantopy create a default integer index:
In [4]: stock1_rs = qp.ReturnSeries.from_price(stock1_price)
In [5]: stock1_rs
Out[5]:
1 0.20
2 0.25
dtype: float64
To generate the simple returns from a list of multiple asset prices, we use ReturnDataFrame.from_price():
In [6]: stocks_rdf = qp.ReturnDataFrame.from_price(
...: {
...: 'stock_1': stock1_price,
...: 'stock_2': stock2_price,
...: }
...: )
...:
In [7]: stocks_rdf
Out[7]:
stock_1 stock_2
1 0.20 -0.333333
2 0.25 0.750000
Multi-period returns¶
The simple two-month return on an investment in an asset between months t−2 and t is defined as:
Then the simple two-month gross return becomes:
In general, the k-month gross return is defined as the product of k one-month gross returns:
The method cumulated() computes the cumulated indexed values from simple
returns.
In [8]: stock1_rs.cumulated()
Out[8]:
1 1.2
2 1.5
dtype: float64
In [9]: stocks_rdf.cumulated()
Out[9]:
stock_1 stock_2
1 1.2 0.666667
2 1.5 1.166667
Average returns¶
For investments over a given horizon, it is often of interest to compute a measure of the average rate of return over the horizon. To illustrate, consider a sequence of monthly investments over T months with monthly returns R1, R2, … , RT. The T−month return is
What is the average monthly return? There are two possibilities. The first is the arithmetic average return
The second is the geometric average return
Notice that the geometric average return is the monthly return which compounded monthly for T months gives the gross T−month return
Note
The geometric mean is always less than or equal to the arithmetic mean, and the difference increases as the dispersion of the observations increases. The only time the arithmetic and geometric means are equal is when there is no variability in the observations (i.e., all observations are equal).
Since past returns are compounded each period, the geometric mean of past returns is the appropriate measure of past performance. The arithmetic mean is, however, the statistically best estimator of the next year’s returns given only the past returns, athough to estimate multi-year returns (e.g. expected return over the next five years), the geometric mean is the appropriate measure.
The method mean() computes the arithmetic mean of pasts returns.
In [10]: stock1_rs.mean()
Out[10]: 0.22499999999999998
In [11]: stocks_rdf.mean()
Out[11]:
stock_1 0.225000
stock_2 0.208333
dtype: float64
As we have seen, for the evaluation of the average investment performance, the geometric average
return is preferred to the arithmetic average return. The method gmean()
computes the geometric mean of pasts returns.
In [12]: stock1_rs.gmean()
Out[12]: 0.22474487139158894
In [13]: stocks_rdf.gmean()
Out[13]:
stock_1 0.224745
stock_2 0.080123
dtype: float64
Annualizing returns¶
Very often returns over different horizons are annualized, i.e., converted to an annual return, to facilitate comparisons with other investments. The annualization process depends on the holding period of the investment and an implicit assumption about compounding.
The method annualized() calculates the annualized rate of return, given the
compounding period assumption. For monthly returns, we can calculate the annualized return with:
In [14]: stock1_rs.annualized(period=qp.stats.period.MONTHLY)
Out[14]: 10.390624999999988
In [15]: stocks_rdf.annualized(period=qp.stats.period.MONTHLY)
Out[15]:
stock_1 10.390625
stock_2 1.521626
dtype: float64
We can also compute annualized rate for different periods, like daily, weekly and yearly.
Continuously compounded returns¶
In this section we define continuously compounded returns from simple returns, and describe their properties.
Let Rtdenote the simple periodic return on an investment. The continuously compounded periodic return, rt, is defined as:
where pt= ln(Pt). Hence, the continuously compounded return, rt, can be computed simply by taking the first difference of the natural logarithms of the prices.
Using the price and return data from the Simple Return Example, the continuously compounded return of the stocks can be computed as:
In [16]: stock1_rs.log()
Out[16]:
1 0.182322
2 0.223144
dtype: float64
In [17]: stocks_rdf.log()
Out[17]:
stock_1 stock_2
1 0.182322 -0.405465
2 0.223144 0.559616
References¶
Zivot, E. (2016). Introduction to Computational Finance and Financial Econometrics with R. Springer.