Commit 1b897b37 by Dóra Kocsis

### Add daily frequency, closes Enterprise/dseries#1

parent 686a3840
 ... ... @@ -14,7 +14,7 @@ function q = colon(varargin) % --*-- Unitary tests --*-- % 1. p must be greater than o if d>0. % 2. p and q are dates objects with one element. % Copyright (C) 2013-2017 Dynare Team % Copyright (C) 2013-2020 Dynare Team % % This code is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by ... ... @@ -67,7 +67,7 @@ end q = dates(); % Compute the number of elements in the returned dates object. n = (p-o)+1; % The number of elements in q dates object if d==1. n = (p-o)+1; % The number of elements in q dates object if d==1. m = n; if d>1 % Correction of the number of elements (if d is not equal to one). m = length(1:d:n); ... ... @@ -81,8 +81,12 @@ if isequal(q.freq, 1) q.time = NaN(m,2); q.time(:,1) = o.time(1)+transpose(0:d:n-1); q.time(:,2) = 1; elseif isequal(q.freq, 365) q.time = NaN(n,3); initperiods = datenum(o.time):datenum(p.time); q.time = str2num(datestr(initperiods, 'yyyy mm dd')); else % Weekly, Monthly, Quaterly % Weekly, Monthly, Quaterly, Bi-Annual q.time = NaN(n,2); initperiods = min(q.freq-o.time(2)+1,n); q.time(1:initperiods,1) = o.time(1); ... ... @@ -190,3 +194,20 @@ end %\$ t(2) = dassert(d.freq,e.freq); %\$ T = all(t); %\$ @eof:4 %\$ @test:5 %\$ % Create an empty dates object for daily data %\$ dd = dates('D'); %\$ %\$ % Define expected results. %\$ e.freq = 365; %\$ e.time = [1950 1 28; 1950 1 29; 1950 1 30]; %\$ %\$ % Call the tested routine. %\$ d = dd(1950, 01, 28):dd(1950, 01, 30); %\$ %\$ % Check the results. %\$ t(1) = dassert(d.time,e.time); %\$ t(2) = dassert(d.freq,e.freq); %\$ T = all(t); %\$ @eof:5
 classdef dates=1) && all(varargin{3}<=12) && all(varargin{4}>=1) && all(varargin{3}<=31) o.time = [varargin{2}(:), varargin{3}(:), varargin{4}(:)]; else error('dates:ArgCheck','Third input must contain integers between 1 and %i.', o.freq) end else error('dates:ArgCheck','Fourth input must be a vector of integers.') end else error('dates:ArgCheck','Third input must be a vector of integers.') end else error('dates:ArgCheck','Second input must be a vector of integers.') end return end error('dates:ArgCheck','The input cannot be interpreted as a date. You should first read the manual!') end % dates constructor. % Other methods ... ... @@ -303,7 +334,7 @@ end % classdef %@test:10 %\$ try %\$ B = dates(4,[1950, 1950], [1, 2]); %\$ B = dates(365,[1956, 1956], [1, 1], [12, 13]); %\$ t = 1; %\$ catch %\$ t = 0; ... ...
 ... ... @@ -13,7 +13,7 @@ function B = subsref(A,S) % --*-- Unitary tests --*-- % 1. The type of the returned argument depends on the content of S. % 2. See the matlab's documentation about the subsref method. % Copyright (C) 2011-2017 Dynare Team % Copyright (C) 2011-2020 Dynare Team % % This code is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by ... ... @@ -57,10 +57,11 @@ switch S(1).type case '()' if isempty(A) if isempty(A.freq) % Populate an empty dates object with time member (freq is not specified). Needs two or three inputs. First input is an integer % Populate an empty dates object with time member (freq is not specified). Needs two, three or four inputs. First input is an integer % scalar specifying the frequency. Second input is either the time member (a n*2 array of integers) or a column vector with n % elements (the first column of the time member --> years). If the the second input is a row vector and if A.freq~=1 a third input % is necessary. The third input is n*1 vector of integers between 1 and A.freq (second column of the time member --> subperiods). % is necessary. The third input is n*1 vector of integers between 1 and A.freq (or 31 in case of daily data) (second column of the time member --> subperiods). % The fourth input is only necessary in case of daily data, it is n*1 vector of integers between 1 and 12. B = dates(); % First input is the frequency. if isfreq(S(1).subs{1}) ... ... @@ -72,7 +73,7 @@ switch S(1).type else error('dates::subsref: First input must be a frequency!') end if isequal(length(S(1).subs),2) if isequal(length(S(1).subs),2) && ~isequal(B.freq,365) % If two inputs are provided, the second input must be a n*2 array except if frequency is annual. [n, m] = size(S(1).subs{2}); if m>2 ... ... @@ -94,7 +95,7 @@ switch S(1).type else error('dates::subsref: This is a bug!') end elseif isequal(length(S(1).subs),3) elseif isequal(length(S(1).subs),3) && ~isequal(B.freq,365) % If three inputs are provided, the second and third inputs are column verctors of integers (years and subperiods). if ~iscolumn(S(1).subs{2}) && ~all(isint(S(1).subs{2})) error('dates::subsref: Second input argument must be a column vector of integers!') ... ... @@ -108,14 +109,32 @@ switch S(1).type error('dates::subsref: Second and third input arguments must have the same number of elements!') end B.time = [S(1).subs{2}, S(1).subs{3}]; elseif isequal(length(S(1).subs),4) && isequal(B.freq,365) % If four inputs are provided, the second, third and fourth inputs are column verctors of integers (years and subperiods (months and days when freq is 365)). if ~iscolumn(S(1).subs{2}) && ~all(isint(S(1).subs{2})) error('dates::subsref: Second input argument must be a column vector of integers!') end n1 = size(S(1).subs{2},1); if ~iscolumn(S(1).subs{3}) && ~all(S(1).subs{2}>=1) && ~all(S(1).subs{2}<=12) error('dates::subsref: Third input argument must be a column vector of subperiods (integers between 1 and 12)!') end n2 = size(S(1).subs{3},1); if ~iscolumn(S(1).subs{4}) && ~all(S(1).subs{2}>=1) && ~all(S(1).subs{2}<=31) error('dates::subsref: Fourth input argument must be a column vector of subperiods (integers between 1 and 31)!') end n3 = size(S(1).subs{4},1); if ~isequal(n1,n2,n3) error('dates::subsref: Second, third and fourth input arguments must have the same number of elements!') end B.time = [S(1).subs{2}, S(1).subs{3}, S(1).subs{4}]; else error('dates::subsref: Wrong calling sequence!') end else % Populate an empty dates object with time member (freq is already specified). % Needs one (time) or two (first and second columns of time for years and subperiods) inputs. % Needs one (time), two or three (first, second and third columns of time for years and subperiods (months and days when freq is 365)) inputs. B = copy(A); if isequal(length(S(1).subs),2) if isequal(length(S(1).subs),2) && ~isequal(B.freq,365) if ~iscolumn(S(1).subs{1}) && ~all(isint(S(1).subs{1})) error('dates::subsref: First argument has to be a column vector of integers!') end ... ... @@ -128,7 +147,7 @@ switch S(1).type error('dates::subsref: First and second argument must have the same number of rows!') end B.time = [S(1).subs{1}, S(1).subs{2}]; elseif isequal(length(S(1).subs),1) elseif isequal(length(S(1).subs),1) && ~isequal(B.freq,365) [n, m] = size(S(1).subs{1}); if ~isequal(m,2) && ~isequal(B.freq,1) error('dates::subsref: First argument has to be a n*2 array!') ... ... @@ -146,6 +165,23 @@ switch S(1).type else error('dates::subsref: This is a bug!') end elseif isequal(length(S(1).subs),3) && isequal(B.freq,365) if ~iscolumn(S(1).subs{1}) && ~all(isint(S(1).subs{1})) error('dates::subsref: First argument has to be a column vector of integers!') end n1 = size(S(1).subs{1},1); if ~iscolumn(S(1).subs{2}) && ~all(S(1).subs{2}>=1) && ~all(S(1).subs{2}<=12) error('dates::subsref: Second argument has to be a column vector of subperiods (integers between 1 and 12!') end n2 = size(S(1).subs{2},1); if ~iscolumn(S(1).subs{3}) && ~all(S(1).subs{2}>=1) && ~all(S(1).subs{2}<=31) error('dates::subsref: Third argument has to be a column vector of subperiods (integers between 1 and 31!') end n3 = size(S(1).subs{3},1); if ~isequal(n3,n2,n1) error('dates::subsref: All arguments must have the same number of rows!') end B.time = [S(1).subs{1}, S(1).subs{2}, S(1).subs{3}]; else error('dates::subsref: Wrong number of inputs!') end ... ... @@ -345,3 +381,43 @@ end %\$ end %\$ T = all(t); %@eof:7 %@test:8 %\$ % Define a dates object %\$ B = dates('1950-11-15','1950-11-16','1950-11-17','1950-11-18'); %\$ %\$ % Try to extract a sub-dates object. %\$ try %\$ d = B([]); %\$ t(1) = true; %\$ catch %\$ t(1) = false; %\$ end %\$ %\$ if t(1) %\$ t(2) = dassert(isa(d,'dates'), true); %\$ t(3) = dassert(isempty(d), true); %\$ end %\$ T = all(t); %@eof:8 %@test:9 %\$ % Define a dates object %\$ B = dates('1950-11-15','1950-11-16','1950-11-17','1950-11-18'); %\$ %\$ % Try to extract a sub-dates object. %\$ d = B(2); %\$ %\$ if isa(d,'dates') %\$ t(1) = 1; %\$ else %\$ t(1) = 0; %\$ end %\$ %\$ if t(1) %\$ t(2) = dassert(d.freq,B.freq); %\$ t(3) = dassert(d.time,[1950 11 16]); %\$ t(4) = dassert(d.ndat(),1); %\$ end %\$ T = all(t); %@eof:9 \ No newline at end of file
 function o = dgrowth(o) % --*-- Unitary tests --*-- % Computes daily growth rates. % % INPUTS % - o [dseries] % % OUTPUTS % - o [dseries] % Copyright (C) 2020 Dynare Team % % This file is part of Dynare. % % Dynare is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation, either version 3 of the License, or % (at your option) any later version. % % Dynare is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with Dynare. If not, see . o = copy(o); o.dgrowth_(); %@test:1 %\$ try %\$ data = (1+.01).^transpose(0:1:50); %\$ ts = dseries(data,'1950-01-01'); %\$ ds = ts.dgrowth(); %\$ t(1) = 1; %\$ catch %\$ t(1) = 0; %\$ end %\$ %\$ if t(1) %\$ DATA = NaN(1,ds.vobs); %\$ DATA = [DATA; .01*ones(ds.nobs-1,ds.vobs)]; %\$ t(2) = dassert(ds.data,DATA,1e-15); %\$ t(3) = dassert(ts.data,data,1e-15); %\$ end %\$ %\$ T = all(t); %@eof:1 \ No newline at end of file
 function o = dgrowth_(o) % --*-- Unitary tests --*-- % Computes daily growth rates. % % INPUTS % - o [dseries] % % OUTPUTS % - o [dseries] % Copyright (C) 2020 Dynare Team % % This file is part of Dynare. % % Dynare is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation, either version 3 of the License, or % (at your option) any later version. % % Dynare is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with Dynare. If not, see . switch frequency(o) case 1 error('dseries::dgrowth: I cannot compute daily growth rates from yearly data!') case 2 error('dseries::dgrowth: I cannot compute daily growth rates from bi-annual data!') case 4 error('dseries::dgrowth: I cannot compute daily growth rates from quaterly data!') case 12 error('dseries::dgrowth: I cannot compute daily growth rates from monthly data!') case 52 error('dseries::dgrowth: I cannot compute daily growth rates from weekly data!') case 365 o.data(2:end,:) = o.data(2:end,:)./o.data(1:end-1,:) - 1; o.data(1,:) = NaN; otherwise error(['dseries::dgrowth: object ' inputname(1) ' has unknown frequency']); end for i = 1:vobs(o) if isempty(o.ops{i}) o.ops(i) = {['dgrowth(' o.name{i} ')']}; else o.ops(i) = {['dgrowth(' o.ops{i} ')']}; end end %@test:1 %\$ try %\$ data = (1+.01).^transpose(0:1:50); %\$ ts = dseries(data,'1950Q1'); %\$ ts.dgrowth_; %\$ t(1) = 0; %\$ catch %\$ t(1) = 1; %\$ end %\$ %\$ T = all(t); %@eof:1 %@test:2 %\$ try %\$ data = (1+.01).^transpose(0:1:80); %\$ ts = dseries(data, '1950-01-01'); %\$ ts.dgrowth_; %\$ t(1) = 1; %\$ catch %\$ t(1) = 0; %\$ end %\$ %\$ if t(1) %\$ DATA = NaN(1,ts.vobs); %\$ DATA = [DATA; (1.01-1)*ones(ts.nobs-1, ts.vobs)]; %\$ t(2) = dassert(ts.data, DATA, 1e-15); %\$ end %\$ %\$ T = all(t); %@eof:2
 ... ... @@ -124,7 +124,7 @@ methods init = dates(1,1); elseif (isdates(b) && isequal(length(b),1)) init = b; elseif ischar(b) && isdate(b)% Weekly, Monthly, Quaterly, Bi-annual or Annual data (string). elseif ischar(b) && isdate(b)% Daily, Weekly, Monthly, Quaterly, Bi-annual or Annual data (string). init = dates(b); elseif (isnumeric(b) && isscalar(b) && isint(b)) % Yearly data. init = dates([num2str(b) 'Y']); ... ...
 ... ... @@ -39,6 +39,8 @@ switch frequency(o) o.data(1:6,:) = NaN; case 52 error('dseries::hdiff: I do not know yet how to compute bi-annual differences from weekly data!') case 365 error('dseries::hdiff: I do not know yet how to compute bi-annual differences from daily data!') otherwise error(['dseries::hdiff: object ' inputname(1) ' has unknown frequency']); end ... ...
 ... ... @@ -39,6 +39,8 @@ switch frequency(o) o.data(1:6,:) = NaN; case 52 error('dseries::hgrowth: I do not know yet how to compute bi-annual growth rates from weekly data!') case 365 error('dseries::hgrowth: I do not know yet how to compute bi-annual growth rates from daily data!') otherwise error(['dseries::hgrowth: object ' inputname(1) ' has unknown frequency']); end ... ...
 ... ... @@ -35,6 +35,10 @@ switch frequency(o) case 12 o.data(2:end,:) = o.data(2:end,:)-o.data(1:end-1,:); o.data(1,:) = NaN; case 52 error('dseries::mdiff: I do not know yet how to compute monthly differences from weekly data!') case 365 error('dseries::mdiff: I do not know yet how to compute monthly differences from daily data!') otherwise error(['dseries::mdiff: object ' inputname(1) ' has unknown frequency']); end ... ...
 ... ... @@ -35,6 +35,10 @@ switch frequency(o) case 12 o.data(2:end,:) = o.data(2:end,:)./o.data(1:end-1,:) - 1; o.data(1,:) = NaN; case 52 error('dseries::mgrowth: I do not know yet how to compute monthly growth rates from weekly data!') case 365 error('dseries::mgrowth: I do not know yet how to compute monthly growth rates from daily data!') otherwise error(['dseries::mgrowth: object ' inputname(1) ' has unknown frequency']); end ... ...
 ... ... @@ -38,6 +38,8 @@ switch frequency(o) o.data(1:3,:) = NaN; case 52 error('dseries::qdiff: I do not know yet how to compute quaterly differences from weekly data!') case 365 error('dseries::qdiff: I do not know yet how to compute quaterly differences from daily data!') otherwise error(['dseries::qdiff: object ' inputname(1) ' has unknown frequency']); end ... ...
 ... ... @@ -38,6 +38,8 @@ switch frequency(o) o.data(1:3,:) = NaN; case 52 error('dseries::qgrowth: I do not know yet how to compute quaterly growth rates from weekly data!') case 365 error('dseries::qgrowth: I do not know yet how to compute quaterly growth rates from daily data!') otherwise error(['dseries::qgrowth: object ' inputname(1) ' has unknown frequency']); end ... ...
 ... ... @@ -53,7 +53,7 @@ switch S(1).type % Returns a dates object (last date). r = o.dates(end); case 'freq' % Returns an integer characterizing the data frequency (1, 4, 12 or 52) % Returns an integer characterizing the data frequency (1, 2, 4, 12, 52 or 365) r = o.dates.freq; case 'length' error(['dseries::subsref: we do not support the length operator on ' ... ... ... @@ -112,6 +112,7 @@ switch S(1).type 'hgrowth','hgrowth_', ... 'qgrowth','qgrowth_', ... 'mgrowth','mgrowth_', ... 'dgrowth','dgrowth_', ... 'ydiff','ydiff_', ... 'hdiff','hdiff_', ... 'qdiff','qdiff_', ... ... ... @@ -743,4 +744,21 @@ return end T = all(t); %@eof:20 \ No newline at end of file %@eof:20 %@test:21 try tseries = dseries(dates('2000-01-01')); ts = tseries(ones(6,1)); t(1) = true; catch t(1) = false; end if t(1) t(2) = ts.dates(1)==dates('2000-01-01'); t(3) = ts.dates(6)==dates('2000-01-06'); end T = all(t); %@eof:21 \ No newline at end of file
 ... ... @@ -41,6 +41,9 @@ switch frequency(o) case 52 o.data(53:end,:) = o.data(53:end,:)-o.data(1:end-52,:); o.data(1:52,:) = NaN; case 365 o.data(366:end,:) = o.data(366:end,:)-o.data(1:end-365,:); o.data(1:365,:) = NaN; otherwise error(['dseries::ydiff: object ' inputname(1) ' has unknown frequency']); end ... ... @@ -155,3 +158,23 @@ end %\$ %\$ T = all(t); %@eof:5 %@test:6 %\$ try %\$ data = transpose(1:1095); %\$ ts = dseries(data,'1950-01-01',{'A1'},{'A_1'}); %\$ ts.ydiff_; %\$ t(1) = true; %\$ catch %\$ t(1) = false; %\$ end %\$ %\$ if t(1) %\$ DATA = NaN(365,ts.vobs); %\$ DATA = [DATA; 365*ones(ts.nobs-365,ts.vobs)]; %\$ t(2) = dassert(ts.data,DATA); %\$ t(3) = dassert(ts.ops{1},['ydiff(A1)']); %\$ end %\$ %\$ T = all(t); %@eof:6 \ No newline at end of file
 ... ... @@ -41,6 +41,9 @@ switch frequency(o) case 52 o.data(53:end,:) = o.data(53:end,:)./o.data(1:end-52,:) - 1; o.data(1:52,:) = NaN; case 365 o.data(366:end,:) = o.data(366:end,:)./o.data(1:end-365,:) - 1; o.data(1:365,:) = NaN; otherwise error(['dseries::ygrowth: object ' inputname(1) ' has unknown frequency']); end ... ... @@ -131,3 +134,23 @@ end %\$ %\$ T = all(t); %@eof:4 %@test:5 %\$ try %\$ data = repmat(transpose(1:365),100,1); %\$ ts = dseries(data,'1950-01-01'); %\$ ts.ygrowth_(); %\$ t(1) = true; %\$ catch %\$ t(1) = false; %\$ end %\$ %\$ %\$ if t(1) %\$ DATA = NaN(365,ts.vobs); %\$ DATA = [DATA; zeros(ts.nobs-365,ts.vobs)]; %\$ t(2) = dassert(ts.data,DATA); %\$ end %\$ %\$ T = all(t); %@eof:5
 ... ... @@ -4,8 +4,8 @@ function s = date2string(varargin) % --*-- Unitary tests --*-- % % INPUTS % o varargin{1} + dates object with one element, if nargin==1. % + 1*2 vector of integers (first element is the year, second element is the subperiod), if nargin==2. % o varargin{2} integer scalar equal to 1, 2, 4, 12 or 52 (frequency). % + 1*3 vector of integers (first element is the year, second and third elements are the subperiods), if nargin==3. % o varargin{2} integer scalar equal to 1, 2, 4, 12, 52 or 365 (frequency). % % OUTPUTS % o s string. ... ... @@ -37,8 +37,8 @@ if isequal(nargin,1) end if isequal(nargin,2) if ~(isvector(varargin{1}) && isequal(length(varargin{1}),2) && all(isint(varargin{1})) && isscalar(varargin{2} && ismember(varargin{2},[1 2 4 12 52]))) error(['dates::format: First input must be a 1*2 vector of integers and second input must be a scalar integer (1, 2, 4, 12 or 52)!']) if ~(isvector(varargin{1}) && (isequal(length(varargin{1}),2) || isequal(length(varargin{1}),3)) && all(isint(varargin{1})) && isscalar(varargin{2} && ismember(varargin{2},[1 2 4 12 52 365]))) error(['dates::format: First input must be a 1*2 or 1*3 vector of integers and second input must be a scalar integer (1, 2, 4, 12, 52 or 365)!']) else if varargin{1}(2)>varargin{2} || varargin{1}(2)<1 error('dates::format: Second element of the first input be between 1 and %s!',num2str(varargin{2})) ... ... @@ -48,9 +48,13 @@ if isequal(nargin,2) end end s = [num2str(time(1)) freq2string(freq)]; if freq>1 s = strcat(s, num2str(time(2)));