Code covered by the BSD License

# GARCH Tool

### Phil Goddard (view profile)

User Interface for fitting and evaluating a generic GARCH model using the Econometrics Toolbox.

GARCHTool
function GARCHTool
% Function to create a user interface that may be used to fit and evaluate
% a generic GARCH model (AR, MA, ARMA, GARCH) to a given set of loaded
% data.
%
% The data may be loaded from,
% - an Excel file that contains a time series, with dates down the first
%   column and data down the second column.  The first row of the
% - a MATLAB Workspace variable.  The variable must have a field called
%   dates that is a vector of date numbers such as those generated by the
%   datenum function, and a field called data which must be a numeric
%   vector the same length as the dates.  Any other fields in the structure
%   are ignored.
%
% Once data is loaded the UI allows the user to,
% - process the raw input data by selecting (sub-)ranges, convert to
%   returns, and differencing the data upto twice.
% - view the Auto Correlation and Partial Auto Correlation of the selected
%   data.
% - View the Box-Jenkins Stationarity test for 0-12 lags
% - Specify and fit an ARCH/GARCH model.
%
% Once a model is specified and fit to the data the UI allows the user to,
% - view the fitted model parameters
% - view the Ljung-Box Q test on the standardized innovations and
%   the standardized innovations squared
% - view the autocorrelation of the standardized innovations and
%   the standardized innovations squared
% - plot predictions out into the future
% - plot simulations out into the future
%
% At any stage the raw data, processed data, the model, the prediction and
% the simulation data may be exported to the MATLAB Workspace.  (If a model
% has not yet been fitted and/or a forecast not generated then those fields
% will be empty in the exported data set.)
%
% Those unfamiliar with GARCH modeling should refer to some of the examples
% within the Econometrics Toolbox documentation.
%
% Requirements: The Econometrics Toolbox.

% Author: Phil Goddard (phil@goddardconsulting.ca)
% Date: Q4, 2011

% The code uses the econometrics toolbox
localInitUI;
else
error('The %s requires an Econometrics Toolbox license to run.',mfilename);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to initialize the user interface and create a structure that may
% be used to update all the uicontrols (enable, position, strings, etc);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localInitUI

% Create a figure window that is centred on the screen, 90% of it's height
% and 80% of its width
wFactor = 0.9;
hFactor = 0.8;
screenSize = get(0,'screensize');
figSize = [(screenSize(3)*(1-wFactor))/2 (screenSize(4)*(1-hFactor))/2 ...
screenSize(3)*wFactor screenSize(4)*hFactor];

% Create the figure window
hf = figure(...,
'Units','pixels',...
'Position', figSize,...
'Toolbar','none',...
'HandleVisibility','callback',...
'IntegerHandle','off',...
'NumberTitle','off',...
'Name', mfilename,...
'Tag',mfilename,...
'Visible','off');

% Create and initialize all of the uicontrols

% Assign default strings for various controls
ad.InputFileName = 'Use button at right to select a data file...';
ad.ViewIdx = 1; % Which axes to be showing

% save the app data

% Update the UI (at this point nothing should really change)
localUpdateUI(hf);

% call the resize function to correctly position the panels/controls
localResizeUI(hf);

% Finally make the figure visible and set a resize function
set(hf,...
'Visible','on',...
'ResizeFcn',@localResizeUI);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to create all of the widgets on the UI.
% Their position is set near the end of the function.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% The figure color is needed multiple times so get it here
figColor = get(hf,'Color');

'Label','File',...
'Label','From File',...
'Callback',@localInputFileBrowsed,...
'Label','From Workspace',...
'Label','Export...',...
'Enable','off',...
'Label','To Workspace',...
'Callback',@localExportToWorkspace,...
'Label','Help',...
'Label',sprintf('%s Help',mfilename),...
'Callback',@(src,evt)feval(@doc,mfilename),...
'Label','Econometrics Toolbox Help',...
'Callback',@(src,evt)feval(@doc,'econ'),...
'Separator','on',...

% Create the data panel and its contained widgets
hpd = uipanel('Parent',hf,...
'Units','pixels',...
'Title','Data',...
'BackgroundColor',figColor,...
'Tag','DataPanel');
uicontrol('Parent',hpd,...
'Style','text',...
'Units','pixels',...
'String','Source:',...
'BackgroundColor',figColor,...
'Tag','DataSourceText');
uicontrol('Parent',hpd,...
'Style','edit',...
'Units','pixels',...
'String','Specify a file to load by using the button at the right...',...
'BackgroundColor',[1 1 1],...
'HorizontalAlignment','left',...
'Enable','Inactive',...
'Tag','DataFileNameEdit');
uicontrol('Parent',hpd,...
'Style','pushbutton',...
'Units','pixels',...
'String','...',...
'Callback',@localInputFileBrowsed,...
'BackgroundColor',figColor,...
'Tag','DataPushbutton');

% Create the View panel and its contained widgets
hpv = uipanel('Parent',hf,...
'Units','pixels',...
'Title','Visualization',...
'BackgroundColor',figColor,...
'Tag','ViewPanel');
uicontrol('Parent',hpv,...
'Style','text',...
'Units','pixels',...
'String','View:',...
'BackgroundColor',figColor,...
'Tag','VizViewText');
'Original (Raw) Time Series',...
'Preprocessed Time Series',...
'Aug. Dickey-Fuller Tests',...
'Auto Correlation',...
'Partial Auto Correlation',...
'Fitted Model Parameters',...
'Auto Corr (Innovations)',...
'Auto Corr (Innovations^2)',...
'Forecast'};
uicontrol('Parent',hpv,...
'Units','pixels',...
'Enable','off',...
'Callback',@localViewChanged,...
'BackgroundColor',[1 1 1],...

% Create the preprocessing panel and its contained widgets
hpp = uipanel('Parent',hf,...
'Units','pixels',...
'Title','Preprocessing',...
'BackgroundColor',figColor,...
'Tag','PreprocessingPanel');
textString = {'Start Date:','End Date:',...
'Transform:','First Difference:','Second Difference:'};
textTag = {'PPSDateText','PPEDateText','PPTText','PPFDText','PPSDText'};
for idx = 1:length(textString)
uicontrol('Parent',hpp,...
'Style','text',...
'Units','pixels',...
'String',textString{idx},...
'BackgroundColor',figColor,...
'Tag',textTag{idx});
end
popupStr = {'22/22/2222','22/22/2222',...
{'None',...
'Natural Logarithm',...
'Convert to Returns (Cont.)',...
'Convert to Returns (Disc.)'},...
cellstr(num2str((0:24)')),...
cellstr(num2str((0:24)'))};
for idx = 1:length(popupStr)
uicontrol('Parent',hpp,...
'Units','pixels',...
'String',popupStr{idx},...
'Callback',@localPreprocessingChanged,...
'Enable','off',...
'BackgroundColor',[1 1 1],...
end
% specify functions for the transforms (and their inverse) here too
@(x)log(x),...
@(x)log(x(2:end)./x(1:end-1)),...
@(x)diff(x)./x(1:end-1)};
% d0 is assumed to be scalar - the last element of the measured data
% data is assume to be a multicolumn martrix of forecast/simulation data
@(d0,data)[repmat(d0,1,size(data,2));exp(data)],...
@(d0,data)d0*cumprod(exp([zeros(1,size(data,2));data])),...
@(d0,data)d0*cumprod([ones(1,size(data,2));(1+data)])};

% Create the Process Model panel and its contained widgets
hppm = uipanel('Parent',hf,...
'Units','pixels',...
'Title','Process Model (ARMA)',...
'BackgroundColor',figColor,...
'Tag','ProcessModelPanel');
uicontrol('Parent',hppm,...
'Style','checkbox',...
'Units','pixels',...
'String','Force C = 0',...
'Callback',@localModelInfoChanged,...
'Enable','off',...
'BackgroundColor',figColor,...
'Tag','PMForceCCheckbox');
textString = {'Distribution:','AR Terms:','MA Terms:'};
textTag = {'PMDText','PMARText','PMMAText'};
for idx = 1:length(textString)
uicontrol('Parent',hppm,...
'Style','text',...
'Units','pixels',...
'String',textString{idx},...
'BackgroundColor',figColor,...
'Tag',textTag{idx});
end
popupStr = {...
{'Gaussian','T'},...
cellstr(num2str((0:10)')),...
cellstr(num2str((0:10)'))};
popupTag = {'PMDPopup','PMARPopup','PMMAPopup'};
for idx = 1:length(textString)
uicontrol('Parent',hppm,...
'Units','pixels',...
'String',popupStr{idx},...
'Callback',@localModelInfoChanged,...
'Enable','off',...
'BackgroundColor',[1 1 1],...
'Tag',popupTag{idx});
end

% Create the Innovations Model panel and its contained widgets
hpim = uipanel('Parent',hf,...
'Units','pixels',...
'Title','Innovations Model (GARCH)',...
'BackgroundColor',figColor,...
'Tag','InnovationsModelPanel');
textString = {'P Terms (GARCH):','Q Terms (ARCH):'};
textTag = {'IMPText','IMQText'};
for idx = 1:length(textString)
uicontrol('Parent',hpim,...
'Style','text',...
'Units','pixels',...
'String',textString{idx},...
'BackgroundColor',figColor,...
'Tag',textTag{idx});
end
popupStr = {...
cellstr(num2str((0:10)')),...
cellstr(num2str((0:10)'))};
popupTag = {'IMPPopup','IMQPopup'};
for idx = 1:length(textString)
uicontrol('Parent',hpim,...
'Units','pixels',...
'String',popupStr{idx},...
'Callback',@localModelInfoChanged,...
'Enable','off',...
'BackgroundColor',[1 1 1],...
'Tag',popupTag{idx});
end

% Create the Forecasting panel and its contained widgets
hpf = uipanel('Parent',hf,...
'Units','pixels',...
'Title','Forecasting',...
'BackgroundColor',figColor,...
'Tag','ForecastingPanel');
textString = {'Out of Sample Points:','Simulation Paths:'};
textTag = {'FSampleText','FPathsText'};
for idx = 1:length(textString)
uicontrol('Parent',hpf,...
'Style','text',...
'Units','pixels',...
'String',textString{idx},...
'BackgroundColor',figColor,...
'Tag',textTag{idx});
end
popupStr = {...
{'1';'2';'5';'10';'20';'30';'60';'90'},...
{'0';'10';'100';'1000';'10000';'50000'}};
popupTag = {'FSamplePopup','FPathsPopup'};
for idx = 1:length(textString)
uicontrol('Parent',hpf,...
'Units','pixels',...
'String',popupStr{idx},...
'Callback',@localForecastInfoChanged,...
'Enable','off',...
'BackgroundColor',[1 1 1],...
'Tag',popupTag{idx});
end

% Create the Regenerate Model button
uicontrol('Parent',hf,...
'Style','pushbutton',...
'Units','pixels',...
'String','<html><center>Regenerate<br/>Model</center></html>',...
'BackgroundColor',[1 1 1],...
'Callback',@localRegenerateModel,...
'Enable','off',...
'Tag','RegenerateModelPushbutton');
% Create the Regenerate Forecast button
uicontrol('Parent',hf,...
'Style','pushbutton',...
'Units','pixels',...
'String','<html><center>Regenerate<br/>Forecast</center></html>',...
'BackgroundColor',[1 1 1],...
'Callback',@localRegenerateForecast,...
'Enable','off',...
'Tag','RegenerateForecastPushbutton');

% determine default sizes for the controls (based on their strings)
localSetUIControlSize(findall(hf,'Type','uicontrol'));

% create the various axes required (and that can be visualized from
% the Visualization panel).
'FittedModelAxis','FittedAutoCorrAxis',...
'FittedAutoCorr2Axis','ForecastAxis'};
axes('Parent',hf,...
'Units','pixels',...
'Visible','off');
end

% Create the table that will be seen on the ADFTestAxis
uitable('Parent',hf,...
'Units','pixels',...
'ColumnName',[{'Lags'};cellstr(num2str((0:12)'))],...
'RowName',[],...
'ColumnEditable',false(1,14),...
'RowStriping','on',...
'FontSize',12,...
'FontWeight','bold',...
'Visible','off');

% Create the table that will be seen on the FittedModelAxis
uitable('Parent',hf,...
'Units','pixels',...
'ColumnName',{'Parameter','Value','Standard Error','T Statistic'},...
'RowName',[],...
'ColumnEditable',false(1,4),...
'RowStriping','on',...
'FontSize',12,...
'FontWeight','bold',...
'Tag','FittedModelTable',...
'Visible','off');

% Create a handles structure

% Now set the sizes of the panels
% This couldn't be done earlier as it required the controls to be sized
% first

% The equations axis can have some special treatment as it doesn't change
% at any point
'XTick',[],'YTick',[],...
'Color',figColor,...
'XColor',figColor,...
'YColor',figColor);
% get the equation to be displayed (as a string)
eqnString = localGetEquationString;
% Create a text object to display the string
'Interpreter','latex',...
'HorizontalAlignment','center',...
'Position',[0.5 0.5],...
'String',eqnString,...
'Visible','on',...
'Tag','EquationsText',...
'FontWeight','bold',...
'FontSize',20);

% The ADF Test axis needs some setup
'XTick',[],'YTick',[],...
'Color',figColor,...
'XColor',figColor,...
'YColor',figColor);
% The fitted model axis needs some setup
'XTick',[],'YTick',[],...
'Color',figColor,...
'XColor',figColor,...
'YColor',figColor);
% Create a text object to display the string
'HorizontalAlignment','center',...
'Position',[0.5 0.9],...
'String','',...
'Visible','off',...
'Tag','FittedModelText',...
'FontWeight','bold',...
'FontSize',12);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to set (an initial) desired size for all uicontrols
% Note: the x and y position aren't important for this function, only the
% width and height of the control.
% This function adds space around the end of the control so that it's
% display looks OK
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localSetUIControlSize(uicontrolHandles)
% Put a different amount of space around a control depending on its type

for idx = 1:length(uicontrolHandles)
thisControl = uicontrolHandles(idx);
position = get(thisControl,'Position');
extent = get(thisControl,'Extent');
switch get(thisControl,'Style')
case {'text','edit'}
set(thisControl,'Position',[position(1:2) extent(3) extent(4)]);
case 'checkbox'
% The extend does not allow for the check box itself, only the
% string, so the control needs to be a little larger to fit
% both.  Make it larger by the height of the control
set(thisControl,'Position',[position(1:2) sum(extent(3:4)) extent(4)]);
% These need more work as the longest string needs to be used
% to determine the largest extent.
% So loop over all strings, putting them into a temporary text
% control and getting the extent, and from it the maximum
% width.
strings =  get(thisControl,'String');
hTemp = uicontrol(...
'Parent',get(thisControl,'Parent'),...
'Style','text');
maxWidth = -Inf;
if iscell(strings)
% Generally a multi-element pulldown menu
for jdx = 1:length(strings)
set(hTemp,'String',strings{jdx});
extent = get(hTemp,'Extent');
maxWidth = max(maxWidth,extent(3));
end
else
% generally a single line char array
for jdx = 1:size(strings,1)
set(hTemp,'String',strings(jdx,:));
extent = get(hTemp,'Extent');
maxWidth = max(maxWidth,extent(3));
end
end
% Delete the temporary control
delete(hTemp);
% The width allows for the "selection array" which is about,
% but slightly smaller that the height, so just use height
set(thisControl,...
'Position',...
[position(1:2) maxWidth+extent(4) extent(4)]);
case 'pushbutton'
% Need to check if it has a multiline string in it (which is
% achieved my using <html> and the tag <br/>
fullStr = get(thisControl,'String');
% find any <br/> tags
[subStrings,loc] = regexp(fullStr,'<br/>','split');
if isempty(loc)
% There are no <br/> tags
set(thisControl,...
'Position',...
[position(1:2) extent(3)+2*extent(4) 2*extent(4)]);
else
% Create a temp text control
hTemp = uicontrol(...
'Parent',get(thisControl,'Parent'),...
'Style','text');
maxWidth = -Inf;
height = 0;
% Loop over the substrings removing any additional html
% tags and putting the rsulting string on a temporary
% uicontrols and getting their extent.
for jdx = 1:length(subStrings)
% get location of additional tags
loc = regexp(subStrings{jdx},'[<>]');
% then remove the tags
for kdx = round(length(loc)/2):-1:1
subStrings{jdx}(loc(2*kdx-1):loc(2*kdx))='';
end
% Now use the resulting (subsub)string to get the extent
set(hTemp,'String',subStrings{jdx});
extent = get(hTemp,'Extent');
maxWidth = max(maxWidth,extent(3));
height = height + extent(4);
end
% Delete the temporary control
delete(hTemp);
% Set the control width and height (and put in some
% margins)
set(thisControl,...
'Position',...
[position(1:2) maxWidth+extent(4) height+extent(4)]);
end
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to initialize all uipanels, including all of the controls inside
% each panel.
% This should be called after the UIControls sizes have been set.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localInitializeUIPanels(handles)

% Get margins
[margins,spacing] = localGetMargins;

% get the figure size
fPos = get(handles.(mfilename),'Position');
width = fPos(3);
height = fPos(4);

% Process the Data Panel -- only its height is important here as its width
% and position will be set in the resize function.
editPos = get(handles.DataFileNameEdit,'Position');
panelPos = [margins(1), ...
height-margins(4)-2*spacing-editPos(4), ...
width-sum(margins(1:2)), ...
3*spacing+editPos(4)];
set(handles.DataPanel,'Position',panelPos);

% To size the other panels requires knowing their width which isn't an easy
% calculation as they must be the width of the largest width of several
% controls that are positioned next to each other horizontally.
% Create the visualization panel and its contained widgets
panelWidth = nan(5,1);
% max width for Visualization Panel
vpPos = get(handles.VizViewText,'Position') + ...
panelWidth(1) = vpPos(3);
% max width for Preprocessing Panel
textTag = {'PPSDateText','PPEDateText','PPTText','PPFDText','PPSDText'};
popupTag = {'PPSDatePopup','PPEDatePopup','PPTPopup','PPFDPopup','PPSDPopup'};
ppPos = nan(length(textTag),4);
for idx = 1:size(ppPos,1)
ppPos(idx,:) = get(handles.(textTag{idx}),'Position') + ...
get(handles.(popupTag{idx}),'Position');
end
panelWidth(2) = max(ppPos(:,3));
% max width for Process Model Panel
textTag = {'PMDText','PMARText','PMMAText'};
popupTag = {'PMDPopup','PMARPopup','PMMAPopup'};
pmPos = nan(length(textTag)+1,4);
pmPos(1,:) = get(handles.PMForceCCheckbox,'Position');
for idx = 2:size(pmPos,1)
pmPos(idx,:) = get(handles.(textTag{idx-1}),'Position') + ...
get(handles.(popupTag{idx-1}),'Position');
end
panelWidth(3) = max(pmPos(:,3));
% max width for Innovations Model Panel
textTag = {'IMPText','IMQText'};
popupTag = {'IMPPopup','IMQPopup'};
imPos = nan(length(textTag),4);
for idx = 1:size(imPos,1)
imPos(idx,:) = get(handles.(textTag{idx}),'Position') + ...
get(handles.(popupTag{idx}),'Position');
end
panelWidth(4) = max(imPos(:,3));
% max width for Forecasting Panel
textTag = {'FSampleText','FPathsText'};
popupTag = {'FSamplePopup','FPathsPopup'};
fpPos = nan(length(textTag),4);
for idx = 1:size(fpPos,1)
fpPos(idx,:) = get(handles.(textTag{idx}),'Position') + ...
get(handles.(popupTag{idx}),'Position');
end
panelWidth(5) = max(fpPos(:,3));

% Hence the required width of the panels (except the Data Panel) is
panelWidth = max(panelWidth) + 2*spacing;

% Position the Visualization Panel
% The controls on the panel can also be positioned as they don't change
% when the figure is resized
vvtPos = get(handles.VizViewText,'Position');
panelPos = [margins(1), ...
panelPos(2)-2*spacing-2*spacing-vvpuPos(4), ...
panelWidth, ...
2*spacing+vvpuPos(4)+spacing];
set(handles.ViewPanel,'Position',panelPos);
set(handles.VizViewText,...
'Position',[spacing spacing vvtPos(3:4)]);
'Position',[panelWidth-spacing-vvpuPos(3) spacing vvpuPos(3:4)]);

% Position the Preprocessing Panel
% The controls on the panel can also be positioned as they don't change
% when the figure is resized
panelPos = [margins(1), ...
panelPos(2)-2*spacing-6*spacing-5*editPos(4), ...
panelWidth, ...
7*spacing+5*editPos(4)];
set(handles.PreprocessingPanel,'Position',panelPos);
% Position the text and popupmenus
textTag = {'PPSDateText','PPEDateText','PPTText','PPFDText','PPSDText'};
popupTag = {'PPSDatePopup','PPEDatePopup','PPTPopup','PPFDPopup','PPSDPopup'};
heightOffset = 0;
for idx = length(textTag):-1:1
tPosNow = get(handles.(textTag{idx}),'Position');
pPosNow = get(handles.(popupTag{idx}),'Position');
tNewPos = [spacing spacing+heightOffset tPosNow(3:4)];
pNewPos = [panelPos(3)-spacing-pPosNow(3),...
spacing+heightOffset pPosNow(3:4)];
set(handles.(textTag{idx}),'Position',tNewPos);
set(handles.(popupTag{idx}),'Position',pNewPos);
heightOffset = spacing+heightOffset+tPosNow(4);
end

% Position the Process Model Panel
% The controls on the panel can also be positioned as they don't change
% when the figure is resized
panelPos = [margins(1), ...
panelPos(2)-2*spacing-4*spacing-3*editPos(4), ...
panelWidth, ...
6*spacing+4*editPos(4)];
set(handles.ProcessModelPanel,'Position',panelPos);
% Position the text and popupmenus
textTag = {'PMDText','PMARText','PMMAText'};
popupTag = {'PMDPopup','PMARPopup','PMMAPopup'};
heightOffset = 0;
for idx = length(textTag):-1:1
tPosNow = get(handles.(textTag{idx}),'Position');
pPosNow = get(handles.(popupTag{idx}),'Position');
tNewPos = [spacing spacing+heightOffset tPosNow(3:4)];
pNewPos = [panelPos(3)-spacing-pPosNow(3),...
spacing+heightOffset pPosNow(3:4)];
set(handles.(textTag{idx}),'Position',tNewPos);
set(handles.(popupTag{idx}),'Position',pNewPos);
heightOffset = spacing+heightOffset+tPosNow(4);
end
% Finally do the check box
ppPosNow = get(handles.PMForceCCheckbox,'Position');
ppNewPos = [spacing spacing+heightOffset ppPosNow(3:4)];
set(handles.PMForceCCheckbox,'Position',ppNewPos);

% Position the Innovations Model Panel
% The controls on the panel can also be positioned as they don't change
% when the figure is resized
panelPos = [margins(1), ...
panelPos(2)-2*spacing-4*spacing-3*editPos(4), ...
panelWidth, ...
4*spacing+2*editPos(4)];
set(handles.InnovationsModelPanel,'Position',panelPos);
% Position the text and popupmenus
textTag = {'IMPText','IMQText'};
popupTag = {'IMPPopup','IMQPopup'};
heightOffset = 0;
for idx = length(textTag):-1:1
tPosNow = get(handles.(textTag{idx}),'Position');
pPosNow = get(handles.(popupTag{idx}),'Position');
tNewPos = [spacing spacing+heightOffset tPosNow(3:4)];
pNewPos = [panelPos(3)-spacing-pPosNow(3),...
spacing+heightOffset pPosNow(3:4)];
set(handles.(textTag{idx}),'Position',tNewPos);
set(handles.(popupTag{idx}),'Position',pNewPos);
heightOffset = spacing+heightOffset+tPosNow(4);
end

% Position the Forecasting Model Panel
% The controls on the panel can also be positioned as they don't change
% when the figure is resized
panelPos = [margins(1), ...
panelPos(2)-2*spacing-2*spacing-editPos(4), ...
panelWidth, ...
4*spacing+2*editPos(4)];
set(handles.ForecastingPanel,'Position',panelPos);
textTag = {'FSampleText','FPathsText'};
popupTag = {'FSamplePopup','FPathsPopup'};
heightOffset = 0;
for idx = length(textTag):-1:1
tPosNow = get(handles.(textTag{idx}),'Position');
pPosNow = get(handles.(popupTag{idx}),'Position');
tNewPos = [spacing spacing+heightOffset tPosNow(3:4)];
pNewPos = [panelPos(3)-spacing-pPosNow(3),...
spacing+heightOffset pPosNow(3:4)];
set(handles.(textTag{idx}),'Position',tNewPos);
set(handles.(popupTag{idx}),'Position',pNewPos);
heightOffset = spacing+heightOffset+tPosNow(4);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to move required uicontrols when figure is resized
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localResizeUI(src,evt) %#ok

% get the app data

% Get margins
[margins,spacing] = localGetMargins;

% get the figure size
width = fPos(3);
height = fPos(4);

% all the widgets are anchored to the top left of the figure
% Start at the top and work down.
% Do the Data Panel - repositioning the controls in the panel could be done
% in a resizefcn for the panel, but since there are only 3 of them we'll do
% it here for convenient
newPos = [margins(1),...
height-margins(4)-oldPos(4),...
width-sum(margins([1 2])),...
oldPos(4)];
% need to know the y-position of the Data Panel later so store it here
yPosDataPanel = newPos(2);

% Now do its widgets
newTextPos = [spacing spacing oldTextPos(3:4)];
newEditPos = [sum(newTextPos([1 3])),...
spacing,...
newPos(3)-sum(newTextPos([1 3]))-spacing-oldEditPos(4),...
oldEditPos(4)];
newButtonPos = [sum(newEditPos([1 3])),spacing,oldEditPos([4 4])];

% Loop over the other panels
panelTags = {'ViewPanel','PreprocessingPanel',...
'ProcessModelPanel','InnovationsModelPanel','ForecastingPanel'};
for idx = 1:length(panelTags)
newPos = [margins(1) newPos(2)-spacing-oldPos(4) oldPos(3:4)];
end
% Need to know the panel width later so stor it here
panelWidth = newPos(3);

% Now do the Regenerate pushbuttons, which need to be centred under the
% Forecasting Panel
% Need to know the width of both buttons
% TODO: The following assumes the buttons are narrower than the panel,
% which is true in this case but not generically
pbSpace = (panelWidth-(rgmOldPos(3)+rgfOldPos(3)))/3;
% Position the Regenerate Model pushbutton
newPos = [margins(1)+pbSpace,...
newPos(2)-spacing-rgmOldPos(4) rgmOldPos(3:4)];
% Position the Regenerate Forecast pushbutton
newPos = [margins(1)+2*pbSpace+rgmOldPos(3),...
newPos(2) rgmOldPos(3:4)];

% Now reposition all the axes
set(hAllAxes,'OuterPosition',...
[margins(1)+panelWidth,...
margins(3),...
max(1,width-panelWidth-spacing),...
max(1,yPosDataPanel-margins(3))]);

% Reposition the table that's on the ADFTestAxis
% Make the 6 of the 14 columns span the viewable table
'Position',[axisPos(1:3) 0.95*axisPos(4)],...
'ColumnWidth',{axisPos(3)/6});

% Reposition the table that's on the FittedModelAxis
% Make the (4) columns span the entire table
'Position',[axisPos(1:3) 0.8*axisPos(4)],...
'ColumnWidth',{axisPos(3)/4});

% Flush the graphics buffer
drawnow

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to specify standard margins and spacing for the controls
% TODO: This is inefficient as it creates and destroys a figure more than
% once.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [margins,spacing] = localGetMargins

% % Create a temporary figure and text control to get its position and use
% % that for the margins
% hfTemp = figure(...
%     'Units','pixels',...
%     'Visible','off',...
%     'HandleVisibility','callback',...
%     'IntegerHandle','off');
% htemp = uicontrol(...
%     'Parent', hfTemp,...
%     'Style','text',...
%     'String','Remove this control');
% htempPos = get(htemp,'Position');
% delete(hfTemp);
% % margins will be [left right bottom top]
% margins = [htempPos(1) htempPos(1) htempPos(2) htempPos(2)];
%
% % define spacing between controls as the same as the bottom margin
% spacing = margins(1)/2;
margins = [20 20 20 20];
spacing = 12;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to create a string containing the ARMA/GARCH Equations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function eqnFullString = localGetEquationString
% Create the equations
eqnARMA = sprintf('$$%s%s%s$$',...
'y_{t} = C + ',...
'\sum_{i=1}^{R}\phi_{i}y_{t-i} + \epsilon_{t} + ',...
'\sum_{j=1}^{M}\theta_{j}\epsilon_{t-j}');
eqnGARCH = sprintf('$$%s%s%s$$',...
'\sigma_{t}^{2} = K + ',...
'\sum_{i=1}^{P}G_{i}\sigma_{t-i}^{2} + ',...
'\sum_{j=1}^{Q}A_{j}\epsilon_{t-j}^{2}');
eqnConst1 = sprintf('$$%s$$',...
'\sum_{i=1}^{P}G_{i} + \sum_{j=1}^{Q}A_{j} < 1');
eqnConst2 = '$$K > 0$$';
eqnConst3 = '$$G_i \ge 0$$';
eqnConst4 = '$$A_j \ge 0$$';
eqnFullString = sprintf('%s\n%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n%s',...
eqnARMA,eqnGARCH,...
' subject to the constraints ',...
eqnConst1,eqnConst2,eqnConst3,eqnConst4);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to get initial values for popupmenus
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ad.StartDateIdx = 1;  % Index into DateVec that is currenlt showing
% The date vector is a litle harder to handle
% Index into DateVec that is currently showing
else
end
ad.PPTPopupIdx = 1; % Index of the tranformation
ad.PPFDPopupIdx = 1; % Index of the first difference term
ad.PPSDPopupIdx = 1; % Index of the second difference term
ad.modelinfo.PMForceCCheckboxIdx = 1; % Value of the force C = 0 term
ad.modelinfo.PMDPopupIdx = 1; % Index of the selected distribution
ad.modelinfo.PMARPopupIdx = 1; % Index of the AR term
ad.modelinfo.PMMAPopupIdx = 1; % Index of the MA term
ad.modelinfo.IMPPopupIdx = 1; % Index of the P term
ad.modelinfo.IMQPopupIdx = 1; % Index of the Q term
ad.forecast.FSamplePopupIdx = 1; % Index of the forecast samples
ad.forecast.FPathsPopupIdx = 1; % Index of the forecast paths
% Reset the forecast info based on the above Idx being reset
% Store the requested simulation paths

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to update the UI
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localUpdateUI(src)
% get the app data

% Set the strings into the appropriate uicontrols
% visualization panel
% preprocessing panel
% Process model panel
% Innovations panel
end
% The Fitted Model Table and Text
% Firstly correctly size the data to be displayed
tableData = ...
cell(2,4);
% Now populate the table
'Data',tableData,...
end

% Set the view axis and its children's visibilities
else
end
end

% Handle the Fitted Model Table

% flush the graphics buffer
drawnow

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Callback function for when the input file browser is used
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localInputFileBrowsed(src,evt) %#ok

%Get the app data
% open a file browser in the directory currently showing (if there is one)
FilterSpec = '*.xls;*.xlsx;*.xlsm';
if ~isempty(pathstr)
FilterSpec = sprintf('%s%s%s',pathstr,filesep,FilterSpec);
end
% Create the selector dialog
DialogTitle = 'Select an input data file...';
[FileName,PathName] = uigetfile(FilterSpec,DialogTitle);

% Process the selection
if FileName == 0
% Cancel was selected so just stop now
return
end

% Save the file name

% Let the user know something is going on by using waitbar and
% changing the cursor
% Change the pointer so it looks like something is happending
drawnow
% Make the waitbar non-closable
'Pointer','watch',...
'CloseRequestFcn',@(src,evt)error(''));

% Check that the file is of the correct format and reset the UI if it is
try

% Update the waitbar
waitbar(2/3,hwb,'Data in file is being validated.');

% Preprocess the data

% Reinitialize the local UI structure with the new data

%save the updated app data

% Update the waitbar
waitbar(1,hwb,'Updating the User Interface.');

% update the UI
localUpdateUI(src);

% destroy the waitbar
if exist('hwb','var') && ishandle(hwb)
delete(hwb);
end
% reset the pointer
drawnow
catch ME
% destroy the waitbar
if exist('hwb','var') && ishandle(hwb)
delete(hwb);
end
% reset the pointer
drawnow
% throw an error
errordlg(sprintf('%s %s\n\n%s\n%s\n\n%s\n',...
'There was an error reading the file',...
FileName,...
'The specific error was:',...
ME.message,...
'Check the file and try again.'),'Error','modal');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Callback function for when the input file browser is used
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%Get the app data

% Get the name of the variable in the MATLAB Workspace
allVars = evalin('base','whos');
allNames = {allVars.name};
% IF there are any variables then ask the use to select one
if ~isempty(allNames)
[nameIdx,ok] = listdlg(...
'PromptString','Select a Workspace Variable:',...
'SelectionMode','single',...
'ListString',allNames);
else
% There are no variables to select so tell the user and return
wStr = sprintf('%s\n\n%s',...
'There are no variables in the Workspace.',...
'Create an appropriate variable and try again.');
uiwait(warndlg(wStr,sprintf('%s Warning',mfilename),'modal'));
return
end

% Do nothing if cancel was pressed
if ~ok
return;
else
varName = allNames{nameIdx};
varData = evalin('base',varName);
end

% Specify a file name even though the data came from a variable

% Let the user know something is going on by using waitbar and
% changing the cursor
% Change the pointer so it looks like something is happending
drawnow
% Make the waitbar non-closable
'Pointer','watch',...
'CloseRequestFcn',@(src,evt)error(''));

% Check that the data is of the correct format and reset the UI if it is
try
% validate the data

% Reinitialize the local UI structure with the new data

% save the updated app data

% Update the waitbar
waitbar(1,hwb,'Updating the User Interface.');

% update the UI
localUpdateUI(src);

% destroy the waitbar
if exist('hwb','var') && ishandle(hwb)
delete(hwb);
end
% reset the pointer
drawnow
catch ME
% destroy the waitbar
if exist('hwb','var') && ishandle(hwb)
delete(hwb);
end
% reset the pointer
drawnow
% throw an error
errordlg(sprintf('%s %s\n\n%s\n%s\n\n%s\n',...
'There is a problem with the data in the workspace variable ',...
varName,...
'The specific error was:',...
ME.message,...
'Check the variable and try again.'),'Error','modal');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to reset the UI after new data has been read
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Set the view to show the raw data plot

% Get the initial values for the preprocessing panel

set([hm(:);hpu(:);hcb(:);hpb(:)],'Enable','on');

% Update the axes

% Indicate that the model is now dirty

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to read the specified input file
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% update the app data
% Validate the data that was read
% Initially show all data

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to validate a variable read from the workspace
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% It must be a structure
if isempty(varData) || ~isstruct(varData)
error('The variable must be a structure.');
end
% It must contain fields called 'data' and 'dates' and they must be numeric
% vector of data
requiredFields = {'data','dates'};
for idx = 1:length(requiredFields)
if ~isfield(varData,requiredFields{idx});
error('The variable must have a field called %s.',...
requiredFields{idx});
elseif isempty(requiredFields{idx}) ...
|| ~isnumeric(varData.(requiredFields{idx})) ...
|| numel(varData.(requiredFields{idx})) ...
~= length(varData.(requiredFields{idx}))
error('The field %s.%s must be a numeric vector.',...
varName, requiredFields{idx});
end
end
% The dates and data must be the same length
if length(varData.data) ~= length(varData.dates)
error('The dates and data vectors must be the same length.');
end

% check if the dates seem sequential
if ~all(diff(varData.dates) > 0) && ~all(diff(varData.dates) < 0)
wStr = sprintf('%s\n\n%s %s',...
'The dates appear to be non sequential or duplicated.',...
mfilename,...
'will still work, however the results may be unexpected.');
uiwait(warndlg(wStr,sprintf('%s Warning',mfilename),'modal'));
end

% Everything seems Ok so populate the appdata

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to check the format of the spreadsheet
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [dates,data,ListOfDates] = ...

% The first row must be strings
if ~all(cellfun(@ischar,ListOfTickers))
error('%s%s\n%s',...
'The first row of the input spreadsheet must contain only ',...
'names (i.e. words, not numbers).');
end
% The dates must be able to be converted to datenums
try
% Firstly remove any elements that correspond to NaN in the dates
nanIdx = cellfun(@(x)isnumeric(x)&&isnan(x),ListOfDates);
if any(nanIdx)
ListOfDates(nanIdx)=[];
Data(nanIdx)=[];
end
% Tru to convert the dates
dates = datenum(ListOfDates,'mm/dd/yyyy');
% Sometimes that's the wrong format.
% The following is not bullet proof but provides some instances where
% the date format is likely _NOT_ 'mm/dd/yyyy'
diffDates = diff(dates);
if ~all(diffDates>0) ...
|| ~all(diffDates<0) ...
|| max(diffDates) > 180 ...
|| min(diffDates) < -180
% the date format may be wrong so try another format
dates = datenum(ListOfDates,'dd/mm/yyyy');
end
catch ME
error('%s%s\n%s',...
'The first column of the input spreadsheet must contain only ',...
'dates.');
end
% The data must be numeric
try
data = cell2mat(Data);
catch ME
error('%s%s\n%s',...
'The data in the input spreadsheet must contain only ',...
'numeric returns (or be empty).');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to convert the raw data according to the pre-process
% specifications dialogs
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [dates,data] = ...
localPreprocessInputs(dates,data,sdidx,edidx,transFcn,fDiff,sDiff)

%TODO: this function needs error checking
% select the subregion for the data
data = data(sdidx:edidx);
dates = dates(sdidx:edidx);

% perform the transformation
data = feval(transFcn,data);

% Perform the differences
dVal = [fDiff,sDiff];
for idx = 1:length(dVal)
if length(data) < (dVal(idx)+1)
error('%s %d%s',...
'There are not enough points in the dataset to take the',...
dVal(idx),'-th difference');
else
if dVal(idx) > 0
% create a filter to do the difference
num = [1 zeros(1,dVal(idx)-1) -1];
data = filter(num,1,data);
% The first few points aren't "good" so drop them
data(1:dVal(idx)) = [];
end
end
end

% the dates may need to be reduced due the transformation, i.e. if
% converted to returns then there will be one fewer point.
dates = dates((end-length(data)+1):end);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to change which View axis is currently visible
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localViewChanged(src,evt) %#ok

% get the app data

% get the index of the View to be displayed
newViewIdx = get(src,'Value');

% Process differently depending on which View has been selected
case {'Fitted Model Parameters',...
'Auto Corr (Innovations)',...
'Auto Corr (Innovations^2)'}
% If the view changed to the Fitted Model Axis or one of the
% autocorrelations related to the fitted model then update the
% fitted model if the displayed model is currently dirty
% Save the new view
% save the changed app data
% The model needs regenerating
localRegenerateModel(src);
% The fitted model is no longer dirty
end
% update the ui accordingly
localUpdateUI(src);
case 'Forecast'
% If the view changed to the Forecast Axis then update the
% forecast if it is currently dirty
% Save the new view
% save the changed app data
% The model needs regenerating
localRegenerateForecast(src);
% The fitted model is no longer dirty
end
% update the ui accordingly
localUpdateUI(src);
otherwise
% Only do something if the selection has actually changed
% Save the new view
% save the changed app data
% update the ui accordingly
localUpdateUI(src);
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to change the data when the preprocessing popupmenus change
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localPreprocessingChanged(src,evt) %#ok

% get the app data

% Get the current state of the preprocessing panel

% Preprocess the data

% Update the axes

% Indicate that the model is now out of data

% Save the updated app data

% update the ui accordingly
localUpdateUI(src);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to update all the axes that can be plotted to
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%    'AutoCorrAxis','ParCorrAxis','FittedModelAxis','ForecastAxis'};

% The Raw Data Axis and the PreprocessedData axis are similar so can
% be done in an appropriately initialized loop.
lineTags = {'RawDataLine','PreprocessedLine'};
axisTags = {'RawDataAxis','PreprocessedDataAxis'};
titleStr = {'Raw Data','Preprocessed Data'};

for idx = 1:length(lineTags)
% Update the raw data axes
% create a line on the axis for future use
line(...
'Color',[0 0 1],...
'Tag',lineTags{idx},...
'Visible','off');
end
'XData',xData{idx},'YData',yData{idx});
end

% The autocorr and parcorr axes are a little harder to handle as they
% need to be copied from a temporary figure (since there is no mechanism
% to pass the autocorr and parcorr functions a specific axis handle and get
% them to plot to that axis.
% nPoints is the number of lags to include in the plot, and is based on the
% lags that have been specified (to account for seasonality)
localUpdateAutoParCorrAxis(...
localUpdateAutoParCorrAxis(...

% Finally do the Augmented Dickey Fuller Tests

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to update either the autocorr or the partial auto correlation
% axes.
% The whichFcn input should be a either @autocorr or @parcorr.
% The update is achieved by creating the required plot on a temporary
% invisible figure and then copying it to GARCHTool figure.  As part of
% doing this the axis handle needs to be updated.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function haNew = localUpdateAutoParCorrAxis(haOld,whichFcn,data,nLags)

% Create an invisible temporary figure the same size at the viewer
hf = get(haOld,'Parent');
hfTemp = figure(...
'Units',get(hf,'Units'),...
'Position',get(hf,'Position'),...
'Visible','off');
% perform the autocorr which will plot to the invisible figure
try
feval(whichFcn,data,nLags);
% set the position of the axis to the same as for the viewer
set(gca,...
'Units',get(haOld,'Units'),...
'OuterPosition',get(haOld,'OuterPosition'),...
'Visible','off');
% copy the autocorr into the viewer
haNew = copyobj(gca,hf);
set(haNew,'Tag',get(haOld,'Tag'));
set(get(haNew,'Children'),'Visible','off');
% delete the temporary figure
delete(hfTemp);
% delete the old axis
delete(haOld);
catch ME
% clean-up handles
if exist('hfTemp','var') && ~isempty(hfTemp) && ishandle(hfTemp)
delete(hfTemp);
end
if exist('haNew','var') && ~isempty(haNew) && ishandle(haNew)
delete(haNew);
end
if exist('haOld','var') && ~isempty(haOld) && ishandle(haOld)
haNew = haOld;
else
eStr = sprintf('%s%s%s\n\n%s\n',...
'A fatal error has occured and ',...
mfilename,...
' is being closed.',...
'The specific error was:',...
ME.message);
errordlg(eStr,'Fatal Error','modal');
if exist('hf','var') && ~isempty(hf) && ishandle(hf)
delete(hf);
end
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to perform the required augmented Dickey-Fuller tests.
% The results must be returned in a cell array that has 14 columns
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% The result will have 17 rows

% There are 3 models to try
mTypes = {'AR','AR With Drift','Trend Stationary'};
mNames = {'AR','ARD','TS'};
statNames = {'Decision Variable';'P-Value';'Test Statistic';'Critical Value'};

% The adftest can throw some warnings so turn them off
wState = cell(2);

% loop over the 3 models
for idx = 1:length(mNames)
% The result to be displayed needs to be changed if a
% econ:adftest:InvalidStatistic warning is thrown so reset the
% warning message so that lastwarn is empty
lastwarn('');
% Create an index specifying the location in the table to write the
% results for the current test
jdx = 5*(idx-1)+idx;
% Put the headers into the table
% Run the test
try
% check the state of the warning
[~,wID] = lastwarn;
switch wID
% The test is invalid so report the fact
otherwise
% The test is fine so populate the table
end
catch ME
% fill this part of the table with an error message
end
end
% turn the warnings back to their original state
for idx = 1:length(wState)
warning(wState{idx});
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to update the forecast axis
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Delete all children of the axis (so that we can start fresh)
delete(get(ha,'Children'));

% Define some data

% Need to get the data that would result from the transformation and
% first difference
[fdDates,fdData] = ...
localPreprocessInputs(dates,data,sdidx,edidx,transFcn,fDiff,0);
% Get the forecast based on the (non-random) forecast data
% Reverse the second difference
[~,forecastTemp] = ...

% Need to get the data that would result from just the transformation
[tDates,tData] = ...
localPreprocessInputs(dates,data,sdidx,edidx,transFcn,0,0);
% Reverse the first difference
[forecastDates,forecastData] = ...
localReverseDiff(tDates,tData,fDiff,forecastTemp);
% Now undo the transformation

% Get the forecast based on the (random) simulation data
% Reverse the second difference
[~,simulationTemp] = ...
% Reverse the first difference
[simulationDates,simulationData] = ...
localReverseDiff(tDates,tData,fDiff,simulationTemp);
% Now undo the transformation
end

% Plot the raw data
% Get the data to plot
dataToPlot = data(sdidx:edidx);
datesToPlot = dates(sdidx:edidx);
% Determine how many in-sample points to plot based on the requested number
% of out of sample points
%nInSample = round(length(dates/4));
%nInSample = length(dataToPlot);

% ensure too many points haven't been selected
nInSample = min(length(dataToPlot),nInSample);

line('Parent',ha,...
'XData',datesToPlot((end-nInSample+1):end),...
'YData',dataToPlot((end-nInSample+1):end),...
'Color',[0 0 1],...
'Visible','off');
% Plot the simulation
'Parent',ha,...
'Visible','off');
end
% Plot the forecast (Do this last so it's on top)
line('Parent',ha,...
'Color',[0 0 1],...
'LineWidth',2,...
'Visible','off');

% Format the axis
axis(ha,'tight');
title(ha,'Forecast and Simulation');
xlabel(ha,'Dates');
ylabel(ha,'Data');
datetick(ha,'x');
grid(ha,'on');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to "un"-difference the a time series
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [dates,forecast] = localReverseDiff(dates,data,nDiff,forecast)

% reverse the preprocessing differencing
if length(data) < (nDiff+1)
error('%s %d%s',...
'There are not enough points in the dataset to undo the',...
nDiff,'-th difference');
else
if nDiff > 0
% Form the columns of data required to "undo" the differencing
unDiff = [repmat(data((end-nDiff+1):end),1,size(forecast,2));forecast];
% Do the "un"-differencing
for jdx = (nDiff+1):size(unDiff,1)
unDiff(jdx,:) = unDiff(jdx,:) + unDiff(jdx-nDiff,:);
end
% The first few points aren't part of the forecast so drop them
forecast = unDiff((nDiff+1):end,:);
end
end

% Guestimate dates for the forecast period
dates = cumsum([dates(end);diff(dates((end-size(forecast,1)):end))]);
dates(1) = [];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Callback function to process a change in the model info popup menus
% and check boxes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localModelInfoChanged(src,evt) %#ok

% get the app data

% The app data property that changes is related to the tag of the uicontrol
% that has changed
% The model is now dirty

% save the change

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Callback function to process a change in the forecast info popup menus
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localForecastInfoChanged(src,evt) %#ok

% get the app data

% The app data property that changes is related to the tag of the uicontrol
% that has changed

% Store the requested horizon
% Store the requested simulation paths

% The forecast is now dirty

% save the change

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Callback function to generate the ARMA/GARCH model parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localRegenerateModel(src,evt) %#ok

% get the app data

% Try to do the optimization but if something goes wrong then
% create an error dialog

% Let the user know something is going on by using a non-closeable waitbar
% and changing the cursor
% This can take a while so put up a non-closable waitbar
hwb = waitbar(1/2,'Please wait while the model parameters are estimated.',...
'Pointer','watch',...
'CloseRequestFcn',@(src,evt)error(''));
drawnow

try
% If there's no data then throw an appropriate error
end

% Create a GARCH specification set
spec = garchset(...
'Display','off');
% The C value needs special processing
spec = garchset(spec,'C',nan,'FixC',true);
end
% and so does the distribution
spec = garchset(spec,'Distribution','T');
end

% Fit the GARCH (ARMA) model
~,...
% Create the string to update the Fitted Model Table
LocalGarchdispForTable(...
% Perform the Ljung-Box Q test on the standardized innovations and
% the standardized innovations squared
[lbq(1).h,lbq(1).p,lbq(1).stat,lbq(1).CV] = lbqtest(sResiduals);
[lbq(2).h,lbq(2).p,lbq(2).stat,lbq(2).CV] = lbqtest(sResiduals.^2);
% Create a cell array of lbq test results to display in the
% Fitted Model Table
localCreateLBQTableInfo(lbq);

% Update the autocorr of the innovations and innovations squared.
% nPoints is the number of lags to include in the plot, and is based on the
% lags that have been specified (to account for seasonality)
localUpdateAutoParCorrAxis(...
'Auto Correlation of the Standardized Innovations');
localUpdateAutoParCorrAxis(...
'Auto Correlation of the Standardized Innovations Squared');

% If it was the Regenerate Model pushbutton that got us here then
% change the view
if strcmp(get(src,'Type'),'uicontrol') ...
&& strcmp(get(src,'Style'),'pushbutton')
end

% save the app data

% update the UI
localUpdateUI(src);

% The model is now clean

% save the app data

% destroy the waitbar
if exist('hwb','var') && ishandle(hwb)
delete(hwb);
end
% reset the pointer
drawnow

catch ME
% destroy the waitbar
if exist('hwb','var') && ishandle(hwb)
delete(hwb);
end
% reset the pointer
drawnow
% Throw up an error dialog and stop
errordlg(ME.message,sprintf('%s Error',mfilename),'modal');
return
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Callback function to generate the forecast and simulation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localRegenerateForecast(src,evt) %#ok

% get the app data

% Try to do the forecast but if something goes wrong then
% create an error dialog

% Let the user know something is going on by using a non-closeable waitbar
% and changing the cursor
% This can take a while so put up a non-closable waitbar
hwb = waitbar(1/2,'Please wait while the forecast is recalculated.',...
'Pointer','watch',...
'CloseRequestFcn',@(src,evt)error(''));
drawnow

try
% Error if there is no model to forecast or it is potentially out of
% date
error('%s\n%s',...
'A model has not yet been created or is potentially out of date.',...
'(Re)generate a model then try again.');
end

% Get the requested horizon
% Get the requested simulation paths

% Perform a prediction
% Perform a simulation
[],[],[], ...
end

% Update the forecast axis

% Change the view

% save the app data

% update the UI
localUpdateUI(src);

% The forecast is now clean

% save the app data

% destroy the waitbar
if exist('hwb','var') && ishandle(hwb)
delete(hwb);
end
% reset the pointer
drawnow

catch ME
% destroy the waitbar
if exist('hwb','var') && ishandle(hwb)
delete(hwb);
end
% reset the pointer
drawnow
% Throw up an error dialog and stop
errordlg(ME.message,sprintf('%s Error',mfilename),'modal');
return
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to create a cell array for displaying the LBQ test info on the
% Fitted Model Table
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function lbqTestCell = localCreateLBQTableInfo(lbqTestStruct)

lbqTestCell = cell(5,4);
lbqTestCell(1,1:3) = {'LBQ Test Stats','Innovations','Innovations^2'};
lbqTestCell(2:end,1) = ...
{'Decision Variable';'P-Value';'Test Statistic';'Critical Value'};
for idx = 1:length(lbqTestStruct)
lbqTestCell(2:end,idx+1) = ...
{double(lbqTestStruct(idx).h);
lbqTestStruct(idx).p;
lbqTestStruct(idx).stat;
lbqTestStruct(idx).CV};
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to create cell arrays suitable for displaying the fitted model
% data on the Fitted Model Table
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
LocalGarchdispForTable(EstSpec,EstSE)
%
% This is a copy of the standard garchdisp function from the Econometrics
% Toolbox, but rather than printing to the Command Window the display is
% placed into a cell array suitable for displaying in a uitable.
%
if nargin < 2

error('econ:garchdisp:UnspecifiedInput',...
'Coefficient and standard error \nspecification structures required.')

end

if ~isstruct(EstSpec)

error('econ:garchdisp:NonStructureSpec',...
'Coefficient estimates must be \ngiven in a specification structure.')

end

if ~isstruct(EstSE)

error('econ:garchdisp:NonStructureErrors',...
'Standard errors must be \ngiven in a specification structure.')

end

% Extract model orders:

R = garchget(EstSpec,'R'); % Conditional mean AR order
M = garchget(EstSpec,'M'); % Conditional mean MA order
P = garchget(EstSpec,'P'); % Conditional variance order for lagged variances
Q = garchget(EstSpec,'Q'); % Conditional variance order for lagged residuals
nX = length(garchget(EstSpec,'Regress')); % Number of regressors

% Set flags:

if isnan(garchget(EstSpec,'C'))
isConstantInMean = false; % Mean equation constant is not included
else
isConstantInMean = true; % Mean equation includes a constant
end

varianceModel = garchget(EstSpec,'VarianceModel');
[varianceModel,InMeanString] = strtok(varianceModel,'-');
isVarianceInMean = ~isempty(InMeanString);

distribution = lower(garchget(EstSpec,'Distribution'));
distribution = distribution(~isspace(distribution));
distribution(1) = upper(distribution(1)); % Capitalize the first letter
isDistributionT = strcmpi(distribution,'T'); % Flag t distribution

% Extract parameter estimates:

C       = garchget(EstSpec,'C'); % Conditional mean constant
AR      = garchget(EstSpec,'AR');% Conditional mean AR coefficients
MA      = garchget(EstSpec,'MA'); % Conditional mean MA coefficients
regress = garchget(EstSpec,'Regress'); % Regression coefficients
InMean  = garchget(EstSpec,'InMean'); % Variance-in-mean coefficient

K        = garchget(EstSpec,'K'); % Conditional variance constant
GARCH    = garchget(EstSpec,'GARCH'); % Conditional variance coefficients for lagged variances
ARCH     = garchget(EstSpec,'ARCH'); % Conditional variance coefficients for lagged residuals
Leverage = garchget(EstSpec,'Leverage'); % Conditional variance Leverage coefficients

DoF = garchget(EstSpec,'DoF');

parameters = [repmat(C,isConstantInMean,1);AR(:);MA(:);regress(:);...
repmat(InMean,isVarianceInMean,1);K;GARCH(:);ARCH(:);Leverage(:);...
repmat(DoF,isDistributionT,1)];

% Extract equality constraint information for coefficients

FixC        = garchget(EstSpec,'FixC');
FixAR       = garchget(EstSpec,'FixAR');
FixMA       = garchget(EstSpec,'FixMA');
FixRegress  = garchget(EstSpec,'FixRegress');
FixInMean   = garchget(EstSpec,'FixInMean');
FixK        = garchget(EstSpec,'FixK');
FixGARCH    = garchget(EstSpec,'FixGARCH');
FixARCH     = garchget(EstSpec,'FixARCH');
FixLeverage = garchget(EstSpec,'FixLeverage');
FixDoF      = garchget(EstSpec,'FixDoF');

if isempty(FixC)       , FixC        = zeros(isConstantInMean,1); end
if isempty(FixAR)      , FixAR       = zeros(R,1);  end
if isempty(FixMA)      , FixMA       = zeros(M,1);  end
if isempty(FixRegress) , FixRegress  = zeros(nX,1); end
if isempty(FixInMean)  , FixInMean   = zeros(isVarianceInMean,1); end

if isempty(FixK)       , FixK        = 0;                         end
if isempty(FixGARCH)   , FixGARCH    = zeros(P,1);                end
if isempty(FixARCH)    , FixARCH     = zeros(Q,1);                end
if isempty(FixLeverage), FixLeverage = zeros(length(Leverage),1); end
if isempty(FixDoF)     , FixDoF      = zeros(isDistributionT,1);  end

Fix = logical([FixC;FixAR(:);FixMA(:);FixRegress(:);FixInMean;...
FixK;FixGARCH(:);FixARCH(:);FixLeverage(:);FixDoF]);

% Extract standard errors of the parameter estimates:

eC       =  garchget(EstSE,'C');
eAR      =  garchget(EstSE,'AR');
eMA      =  garchget(EstSE,'MA');
eRegress =  garchget(EstSE,'Regress');
eInMean  =  garchget(EstSE,'InMean');

eK        =  garchget(EstSE,'K');
eGARCH    =  garchget(EstSE,'GARCH');
eARCH     =  garchget(EstSE,'ARCH');
eLeverage =  garchget(EstSE,'Leverage');
eDoF      =  garchget(EstSE,'DoF');

errors = [repmat(eC,isConstantInMean,1);eAR(:);eMA(:);eRegress(:);...
repmat(eInMean,isVarianceInMean,1);eK;eGARCH(:);eARCH(:);eLeverage(:);...
repmat(eDoF,isDistributionT,1)];

% The presence of NaNs in the EstSE structure will propagate into the
% errors vector above, indicating that an error occurred in the calculation
% of the parameter estimation covariance matrix. The following flag
% indicates the presence or absence of such an error condition:

errorFlag = any(isnan(errors)); % If true, an error occurred

% Compute the total number of parameters estimated in the composite
% conditional mean and variance models, excluding any held fixed as user-
% specified equality constraints:

nTotalParameters = isConstantInMean + R + M + nX + isVarianceInMean + 1 + P + Q + isDistributionT;

if any(strcmpi(varianceModel,{'EGARCH' 'GJR'}))
nTotalParameters = nTotalParameters + Q; % Allow for leverage terms
end

nEstimatedParameters = nTotalParameters - sum(Fix); % Subtract equality constraints

% Display summary information:
headerStr{2} = sprintf('Conditional Probability Distribution: %s',distribution);
headerStr{3} = sprintf('Number of Model Parameters Estimated: %d' ,nEstimatedParameters);

% Format annotation strings and display the information. Standard errors
% and t-statistics held fixed by equality constraints during estimation
% have zero estimation error, and are designated 'Fixed'.

n = [ones(isConstantInMean,1) 1:R 1:M 1:nX ones(isVarianceInMean,1) 1 1:P 1:Q]' ;

if any(strcmpi(varianceModel,{'EGARCH' 'GJR'}))
n = [n;(1:Q)'];
end

n = [n;ones(isDistributionT,1)];

strings = [repmat({'C'}, isConstantInMean, 1);
repmat({'AR(#)'}, R , 1);
repmat({'MA(#)'}, M , 1);
repmat({'Regress(#)'}, nX, 1);
repmat({'InMean'}, isVarianceInMean, 1);
'K';
repmat({'GARCH(#)'}, P, 1);
repmat({'ARCH(#)'}, Q, 1);
repmat({'Leverage(#)'}, length(Leverage), 1);
repmat({'DoF'}, isDistributionT, 1)];

colData = cell(nTotalParameters,4);
for row = 1:nTotalParameters
%   If no error occurred in the parameter estimation covariance matrix,
%   then indicate that a particular parameter was held fixed throughout the
%   optimization by printing 'Fixed'. Otherwise, allow a NaN to appear in
%   the printout to indicate the presence of an error condition.

if Fix(row) && ~errorFlag
colData(row,:) = {strrep(strings{row,:},'#',int2str(n(row))),...
sprintf('%.4f',parameters(row)),'Fixed','Fixed'};
else
Tval = parameters(row) / errors(row); % Compute t-statistic for this parameter
colData(row,:) = {strrep(strings{row,:},'#',int2str(n(row))),...
sprintf('%.4f',parameters(row)),...
sprintf('%.6f',errors(row)),...
sprintf('%.4f',Tval)};
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to create a simple About Box
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

mStr = sprintf('%s %s, %s\n\n%s\n\n%s\n%s',...
mfilename,...
'was written using MATLAB R2010a by Phil Goddard',...
'the Principal of Goddard Consulting.',...
'Version 1.2');
msgbox(mStr,...
'help',...
'modal');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function to export data to the MATLAB Workspace
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localExportToWorkspace(src,evt)%#ok

% get the app data

try
% Get the name of the variable to write to
requery = true;
varName = {sprintf('%sStruct',mfilename)};
while requery
% Keep prompting until the user enters a valid variable name or
% presses the cancel button
varName = inputdlg(...
'Enter the name of the variable to create:',...
'Get Export Variable Name',...
1,varName);
if isempty(varName)
% Cancel was pressed so do nothing
return
elseif ~isvarname(varName{1})
% This is not a valid variable name so tell the user and
% then re-query them for a variable name
eStr = sprintf('"%s"%s\n\n%s',...
varName{1},...
' is not a valid variable name.',...
uiwait(errordlg(eStr,...
sprintf('%s Error',mfilename),...
'modal'));
else
% Check if a variable with this name already exists
allNames = evalin('base','whos');
if ismember(varName,{allNames.name})
% name already exists so prompt for overwriting
qStr = sprintf('"%s"%s\n\n%s',...
varName{1},...
'Do you wish to overwrite it?');
overWrite = questdlg(...
qStr,...
sprintf('%s Question',mfilename),...
'Yes','No','No');
if strcmp(overWrite,'Yes')
% name is OK so create/overwrite it
requery = false;
% else
% They don't want to overwrite so prompt again
end
else
% name is OK so create it
requery = false;
end
end
end

% Get all the info to be output
% The data and dates info will always exist but check anyway
requiredFields = {'DatenumVec','DataVec','preDates','preData'};
outputName = {'dates','data','fittedDates','fittedData'};
for idx = 1:length(requiredFields)
else
output.(outputName{idx}) = [];
end
end
% modelinfo will only be available if a model has been fitted
requiredFields = {'coeff','errors','eFit','sFit'};
outputName = {'coeff','errors','eFit','sFit'};
for idx = 1:length(requiredFields)
output.fittedmodel.(outputName{idx}) = ...
else
output.fittedmodel.(outputName{idx}) = [];
end
end
else
output.modelinfo.fittedmodel = [];
end
else
output.modelinfo = [];
end
% forecast will only be available if a forecast was calculated
requiredFields = {'usingPredData','ySim',...
'simulationDates','simulationData',...
'forecastDates','forecastData'};
outputName = {'modelPrediction','modelSimulation',...
'simulationDates','simulationData',...
'forecastDates','forecastData'};
for idx = 1:length(requiredFields)
output.forecast.(outputName{idx}) = ...
else
output.forecast.(outputName{idx}) = [];
end
end
else
output.forecast = [];
end

% Write the variable
assignin('base',varName{1},output);

catch ME
eStr = sprintf('%s\n\n%s%s',...
'There was a problem exporting the data and model information.',...
'The specific error was: ',...
ME.message);
errordlg(eStr,sprintf('%s Error',mfilename),'modal');
end