function acceleration = tsaccel(varargin)
%TSACCEL Acceleration between N periods.
%
% Syntax: 
%
%   acceleration = tsaccel(Data)
%   acceleration = tsaccel(Data,Param1,Val1, ...)
%
% Description:
%
%   TSACCEL calculates the acceleration of a data series with time distance of n
%   periods.  It is essentially the difference of the current momentum with the
%   momentum n periods ago. By default, Acceleration is based on 12-period difference.
%
%   Acceleration is defined as the difference of two momentum series separated 
%   by N periods.
%
% Input Argument:
%
%   Data    - A vector, matrix, table, or timetable. For vector input, Data
%             is column vector. For matrix input, Data is an M-by-N column-oriented
%             matrix.
%
% Optional Input Parameter Name/Value Pairs:
%
%  NAME                 VALUE
%
%  'NumPeriods'         - Positive integer scalar indicating the period
%                         difference for acceleration. The default is 12.
%
%  'Datatype'           - Integer scalar indicating whether Data contains
%                         the data itself or the momentum of the data. Valid
%                         choices are: 0 (Data contains the data itself),
%                         1 (Data contains the momentum of the data). The
%                         default is 0 (Data contains the data itself).
%
% Output Argument:
%
%   acceleration - Acceleration series with the same number of rows (M), 
%                  columns (N), and type as the input data.
%
%   Example:   load SimulatedStock.mat
%              acceleration = tsaccel(TMW.CLOSE);
%              plot(acceleration);
%
%   See also TSMOM.
%
%   Reference: Kaufman, P. J., The New Commodity Trading Systems 
%              and Methods, New York: John Wiley & Sons, 1987. 

%   Copyright 1995-2018 The MathWorks, Inc.

%--------------------- Parse/Validation ----------------------------------%
numPeriodsValidate = @(x) validateattributes(x,{'numeric'},{'scalar','integer','positive'},'','time distance');
datatypeValidate = @(x) validateattributes(x,{'numeric'},{'integer','scalar','>=',0,'<=',1},'', 'datatype of data');
optionalValidate = {numPeriodsValidate,datatypeValidate};

try
    narginchk(1,Inf);
    output = internal.finance.ftseriesInputParser(varargin,{},{},{},{}, ...
        {'NumPeriods','Datatype'},{12,0},optionalValidate,0);
catch ME
    throwAsCaller(ME)
end

[data,optional,dates,datatypeFlag] = output{:};
numPeriods = optional.NumPeriods;
datatype = optional.Datatype;
[numObs,numVar] = size(data);

% Check for data sufficiency.
validateattributes(numPeriods,{'numeric'},{'<=',numObs,'scalar'},'','number of periods');

%--------------------- Calculation ---------------------------------------%
% Calculate the Momentum.
momentum = data(numPeriods:end,:) - data(1:(end-numPeriods+1),:);
momentum = [NaN(numPeriods-1,numVar);momentum]; % Fill in NaNs in front.
switch datatype
case 0
    acceleration = momentum(numPeriods:end,:) - momentum(1:(end-numPeriods+1),:);
    acceleration = [NaN(numPeriods-1,numVar);acceleration]; % Fill in NaNs in front.
case 1
    acceleration = momentum;
end

%--------------------- Output Preparation --------------------------------%
switch datatypeFlag
    case 0 % double
        if ~isempty(dates)
            acceleration = [dates,acceleration];
        end
    case 1 % table
        acceleration = array2table(acceleration,'VariableNames',varargin{1}.Properties.VariableNames);
        acceleration.Properties.Description = ...
            ['Acceleration: ',varargin{1}.Properties.Description];
    case 2 % timetable
        acceleration = array2timetable(acceleration,'RowTimes',dates,'VariableNames',varargin{1}.Properties.VariableNames);
        acceleration.Properties.Description = ...
            ['Acceleration: ',varargin{1}.Properties.Description];
end

end