Main Content

rollingreturns

Period-over-period rolling returns or differences from prices

Description

example

returns = rollingreturns(TT) calculates period-over-period (PoP) returns or differences from corresponding prices. For each date in timetable TT, the return represents the PoP return of the corresponding price compared to the price one Period earlier.

example

returns = rollingreturns(___,Name,Value) specifies options using one or more optional name-value pair arguments in addition to the input arguments in the previous syntax.

Examples

collapse all

This example shows how to compute year-over-year rolling returns for five years of simulated daily prices and also includes business calendar awareness.

Simulate five years of daily prices and store the result in the timetable TT. Then, use isbusday to retain only data for New York Stock Exchange (NYSE) business dates.

rng(200,'twister')
time = (datetime(2014,1,1):caldays:datetime(2018,12,31))';
price = 100 + 0.1*(0:numel(time) - 1)'.*cumsum(randn(numel(time),1)/100); 
price = round(price*100)/100;                 % Round prices to the nearest penny
TT = timetable(price,'RowTimes',time,'VariableNames',{'Prices'});
TT = TT(isbusday(TT.Properties.RowTimes),:);  % Retain only NYSE business days
head(TT,10)
ans=10×1 timetable
       Time        Prices
    ___________    ______

    02-Jan-2014       100
    03-Jan-2014       100
    06-Jan-2014    100.01
    07-Jan-2014    100.02
    08-Jan-2014    100.02
    09-Jan-2014    100.04
    10-Jan-2014    100.06
    13-Jan-2014    100.11
    14-Jan-2014    100.12
    15-Jan-2014    100.12

Use addBusinessCalendar to add NYSE business calendar awareness. The business calendar logic determines if the date of the previous period is a business date, and if it is not, then the most recent business day preceding that date is found. For example, since 21-May-2016 is a Saturday and 22-May-2016 is a Sunday, year-over-year prices for Monday 22-May-2017 are compared to Friday 20-May-2016.

TT = addBusinessCalendar(TT);  % Add NYSE business calendar

Compute the year-over-year returns and display the last few prices and corresponding returns.

returns = rollingreturns(TT, 'Period', calyears);
tail([TT returns])
ans=8×2 timetable
       Time        Prices    Prices_Return_1y
    ___________    ______    ________________

    19-Dec-2018    212.68        0.16941     
    20-Dec-2018    215.54        0.19024     
    21-Dec-2018    217.66        0.18648     
    24-Dec-2018    221.42        0.20882     
    26-Dec-2018    224.81        0.21473     
    27-Dec-2018    222.17        0.19897     
    28-Dec-2018    224.63        0.19142     
    31-Dec-2018    224.37        0.19206     

Economic data is often reported on the last day of each month or quarter. So end-of-month ambiguities can arise when computing period-over-period returns for periods that exceed the periodicity at which data is reported.

Simulate five years of daily prices and store the result in the timetable TT.

rng(200,'twister')
time = (datetime(2014,1,1):caldays:datetime(2018,12,31))';
price = 100 + 0.1*(0:numel(time) - 1)'.*cumsum(randn(numel(time),1)/100); 
price = round(price*100)/100;         % Round prices to the nearest penny
TT = timetable(price,'RowTimes',time,'VariableNames',{'Prices'});
head(TT,10)
ans=10×1 timetable
       Time        Prices
    ___________    ______

    01-Jan-2014       100
    02-Jan-2014       100
    03-Jan-2014       100
    04-Jan-2014       100
    05-Jan-2014    100.01
    06-Jan-2014    100.01
    07-Jan-2014    100.02
    08-Jan-2014    100.02
    09-Jan-2014    100.04
    10-Jan-2014    100.06

Create a new timetable by sampling TT on the last day of each month to mimic monthly reporting.

monthEndDates = dateshift(TT.Time(1):calmonths:TT.Time(end),'end','month'); 
TT = TT(monthEndDates,:);   % Sample TT at end-of-month dates
head(TT,10)
ans=10×1 timetable
       Time        Prices
    ___________    ______

    31-Jan-2014    100.47
    28-Feb-2014    100.93
    31-Mar-2014       102
    30-Apr-2014    102.28
    31-May-2014    103.22
    30-Jun-2014    103.92
    31-Jul-2014     102.2
    31-Aug-2014    104.79
    30-Sep-2014    103.11
    31-Oct-2014    105.29

Display a subset of the dates and compare a direct calculation of the dates in previous months to those shifted to the end of the month in which the previous period occurs.

dates = timerange(datetime(2016,2,29),datetime(2017,2,28),'month');
[TT.Time(dates) (TT.Time(dates) - calyears) dateshift(TT.Time(dates) - calyears,'end','month')]
ans = 13x3 datetime
   29-Feb-2016   28-Feb-2015   28-Feb-2015
   31-Mar-2016   31-Mar-2015   31-Mar-2015
   30-Apr-2016   30-Apr-2015   30-Apr-2015
   31-May-2016   31-May-2015   31-May-2015
   30-Jun-2016   30-Jun-2015   30-Jun-2015
   31-Jul-2016   31-Jul-2015   31-Jul-2015
   31-Aug-2016   31-Aug-2015   31-Aug-2015
   30-Sep-2016   30-Sep-2015   30-Sep-2015
   31-Oct-2016   31-Oct-2015   31-Oct-2015
   30-Nov-2016   30-Nov-2015   30-Nov-2015
   31-Dec-2016   31-Dec-2015   31-Dec-2015
   31-Jan-2017   31-Jan-2016   31-Jan-2016
   28-Feb-2017   28-Feb-2016   29-Feb-2016

Examine these results and notice that the dates in the second and third columns of the last row differ. Specifically, when the current date in the first column is 28-Feb-2017 the dates in the second and third columns differ because 2016 is a leap year. More generally, the dates differ whenever the month of the previous period has more days than the current month for which returns are computed. In this example, end-of-months dates present the following ambiguity. When the current date of interest is 28-Feb-2017, should subtracting one calendar year produce 28-Feb-2016 or 29-Feb-2016?

The correct answer depends on the application, and both approaches are valid use cases. This problem is exacerbated, for example, when working with end-of-monthly price data and computing month-over-month returns. To address the end-of-month ambiguity, the rollingreturns function supports an EndOfMonth flag.

returns = rollingreturns(TT, 'Period', calyears, 'EndOfMonth', true);

The EndOfMonth flag ensures that the rollingreturns function uses the correct end-of-month date of each calendar month. In this example, the return on 28-Feb-2017 is correctly computed from the price reported 29-Feb-2016 rather than 28-Feb-2016.

[TT(dates,:) returns(dates,:)]
ans=13×2 timetable
       Time        Prices    Prices_Return_1y
    ___________    ______    ________________

    29-Feb-2016    135.59         0.21671    
    31-Mar-2016    138.47         0.25052    
    30-Apr-2016    131.44         0.11598    
    31-May-2016    129.34        0.083068    
    30-Jun-2016    133.86        0.077865    
    31-Jul-2016    132.78        0.046253    
    31-Aug-2016    140.32         0.11871    
    30-Sep-2016    136.52        0.087549    
    31-Oct-2016    141.27         0.10652    
    30-Nov-2016    140.76          0.1053    
    31-Dec-2016    135.96        0.057643    
    31-Jan-2017    129.52       0.0099025    
    28-Feb-2017    136.36       0.0056789    

Input Arguments

collapse all

Input timetable of prices, specified as a timetable. The timetable TT must satisfy the following conditions:

  • All observations in TT must be associated with whole dates specified as datetimes with no HH:MM:SS time component (no time-of-day component).

  • TT dates must be sorted in ascending order.

  • TT must have no duplicate dates.

  • Each variable in TT must contain either a single numeric vector or a numeric matrix of prices. For example, suppose TT contains three variables of daily prices.

             Time        Price1    Price2         Prices     
          ___________    ______    ______    ________________
          24-Dec-2018    221.42    442.84    221.42    442.84
          25-Dec-2018    220.62    441.24    220.62    441.24
          26-Dec-2018    224.81    449.62    224.81    449.62
          27-Dec-2018    222.17    444.34    222.17    444.34
          28-Dec-2018    224.63    449.26    224.63    449.26
          29-Dec-2018    225.36    450.72    225.36    450.72
          30-Dec-2018    226.73    453.46    226.73    453.46
          31-Dec-2018    224.37    448.74    224.37    448.74
    The corresponding daily returns are formatted as three returns for the three price variables.
            Time        Price1_Return    Price2_Return       Prices_Return    
          ___________    _____________    _____________   _____________________
          24-Dec-2018           NaN              NaN            NaN         NaN
          25-Dec-2018     -0.003613        -0.003613      -0.003613   -0.003613
          26-Dec-2018      0.018992         0.018992       0.018992    0.018992
          27-Dec-2018     -0.011743        -0.011743      -0.011743   -0.011743
          28-Dec-2018      0.011073         0.011073       0.011073    0.011073
          29-Dec-2018      0.003249         0.003249       0.003249    0.003249
          30-Dec-2018      0.006079         0.006079       0.006079    0.006079
          31-Dec-2018     -0.010409        -0.010409      -0.010409   -0.010409

Note

To include business-calendar-awareness and account for nonbusiness days (for example, weekends, holidays, market closures), you must first use the addBusinessCalendar function to populate a custom property for the input TT. For example, to add business calendar logic to include only NYSE business days, you can use TT = addBusinessCalendar(TT).

Data Types: timetable

Name-Value Pair Arguments

Specify optional comma-separated pairs of Name,Value arguments. Name is the argument name and Value is the corresponding value. Name must appear inside quotes. You can specify several name and value pair arguments in any order as Name1,Value1,...,NameN,ValueN.

Example: returns = rollingreturns(TT,'Period',calweeks(1),'EndOfMonth',true,'Method','continuous')

Period to compute period-over-period returns, specified as the comma-separated pair consisting of 'EndMonthRule' and a scalar calendar duration (for example, caldays, calweeks, or calmonths).

The default is the time step defined in TT (TT.Properties.TimeStep), but only when TT.Properties.TimeStep is not NaN. If TT.Properties.TimeStep is NaN, then Period is required.

Data Types: double

End-of-month flag indicates whether the prices at the current date are compared to last date of month for the previous Period, specified as the comma-separated pair consisting of 'EndOfMonth' and a scalar logical value of true or false.

  • If you set EndOfMonth to true (logical 1), meaning that the current prices are compared to end-of-month prices of the previous Period.

  • If you set EndOfMonth to false (logical 0), meaning that the current prices are compared to prices recorded on the actual date of the previous Period.

Note

The EndOfMonth flag is intended to address end-of-month date calculations when computing the dates of a previous Period one or more months in the past.

For example, suppose you have monthly prices reported at the end of each month and want to compute year-over-year returns (that is, Period = calyears(1)). When the current date of interest is 28-Feb-2017, setting EndOfMonth = true (logical 1) ensures that returns computed for 28-Feb-2017 compare the prices on 28-Feb-2017 to those on 29-Feb-2016 rather than 28-Feb-2016.

Similarly, suppose you have monthly prices reported at the end of each month and want to compute month-over-month returns (that is, Period = calmonths(1)). When the current date of interest is 30-Apr-2020, setting EndOfMonth = true (logical 1) ensures that returns computed for 30-Apr-2020 compare the prices on 30-Apr-2020 to those on 31-Mar-2020 rather than 30-Mar-2020.

Data Types: logical

Method for computing returns from prices, specified as the comma-separated pair consisting of 'Method' and a scalar character vector.

  • 'simple' — Compute simple (proportional) returns: R(t) = P(t)/P(t-period) - 1.

  • 'continuous' — Compute continuous (logarithmic) returns: R(t) = log(P(t)/P(t-period)).

  • 'difference' — Compute differences (period-over-period changes): R(t) = P(t) - P(t-period)

Data Types: char

Output Arguments

collapse all

Period-over-period decimal returns or differences, returned as a timetable of the same size and format as the input argument TT. The returns or differences in row t are associated with the tth date in TT and represent the return or difference of the tth price P(t) relative to the price in the previous period P(t-period). If the date in the previous period is not found in TT, then the result is NaN to indicate a missing value.

Variable names in the output append _Return or _Difference to the variable names in TT for returns and differences, respectively, followed by the period used in the period-over-period results. For example, if TT has a variable named ABC and week-over-week returns are computed for a Period of calweeks(1), the corresponding output variable is named ABC_Returns_1w.

rollingreturns is an aggregation function in which the frequency at which prices are recorded must equal or exceed that at which returns or differences are computed. For example, daily prices can be used to compute daily, weekly, or monthly returns, but computing daily returns from weekly or monthly prices generally makes no sense.

Algorithms

Period-over-period results are computed for every date in TT as follows:

  1. For each date t in TT, the date t-period is computed.

    • If date t-period is a business date, then this date is the date "one period ago"

    • If date t-period is not a business date, then each calendar day preceding t-period is examined repeatedly until a business date is found, at which point this date is the date "one period ago," or the preceding date occurs prior to the first date in TT, at which point no previous business date exists in TT.

  2. If the date "one period ago" is found in TT, then the corresponding price P(t-period) is recorded and the return R(t) is computed. However, if the date "one period ago" is not found in TT, then the previous price P(t-period) is assumed missing (that is, an implicit NaN), and the return R(t) = NaN.

  3. The previous steps are repeated until the date t-period precedes the first date found in TT, at which point the algorithm terminates.

Introduced in R2020b