%% Year-over-Year Returns from Monthly Prices with End-of-Month Dates
% 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)

% 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)

% 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')]

% 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,:)]

% Copyright 2020 The MathWorks, Inc.