Conditional Forecasts and Scenario Analysis
/*--------------------------------------------------------------
SAS Sample Library
Name: varex05.sas
Description: Example program from SAS/ETS User's Guide,
The VARMAX Procedure
Title: Conditional Forecasts and Scenario Analysis
Product: SAS/ETS Software
Keys: Vector AutoRegressive Moving-Average
processes with eXogenous regressors
PROC: VARMAX
Notes:
--------------------------------------------------------------*/
****************************************************************;
* Hard Conditions ;
****************************************************************;
title 'Conditional Forecasts and Scenario Analysis';
%macro cfSimulateData(dgpi,T,lead,tblDGP,tblSample);
* dgpi: index of DGP;
* T: in-sample sample size;
* lead: future horizons;
* tblDGP: output table name for full-sample data;
* tblSample: output table name for in-sample data;
proc iml;
* simulate the data;
* trivariate VAR(2) model;
seed = 12345 + &dgpi.; * random seed;
n = 3; * dim of dependent variable;
T = &T.; * in-sample sample size;
lead = &lead.; * future horizons;
p = 2; * AR order;
* parameter values;
const = {2.425, 0.054, -0.110};
phi = {0.234 -0.134 -0.057,
0.029 0.575 0.200,
0.059 0.038 1.006,
0.164 -0.150 -0.165,
-0.039 0.138 -0.184,
0.031 0.019 -0.087};
sigma = {9.265 0.296 0.553,
0.296 1.746 0.184,
0.553 0.184 0.752};
call varmasim(y,phi) sigma = sigma n = T+lead seed = seed;
mu = (inv(I(3)-phi[1:3,]-phi[4:6,])*const)`;
y = y + mu;
name={y1 y2 y3};
create &tblDGP. from y[colname=name];
append from y;
close;
quit;
data &tblSample.; set &tblDGP.(obs=&T.); run;
%mend;
%macro hcConstructScenarios(T,tblDGP,tblScenarios);
* T: in-sample sample size;
* tblDGP: input table name for full-sample data;
* tblScenarios: output table name for scenarios;
data &tblScenarios.;
set &tblDGP.(firstobs=%eval(&T.+1) obs=%eval(&T.+1))
&tblDGP.(firstobs=%eval(&T.+1) obs=%eval(&T.+2))
&tblDGP.(firstobs=%eval(&T.+1) obs=%eval(&T.+3))
&tblDGP.(firstobs=%eval(&T.+1) obs=%eval(&T.+4))
&tblDGP.(firstobs=%eval(&T.+1) obs=%eval(&T.+1));
* scenario 1: y3(1) is known;
if(_N_=1) then do;
y1=.; y2=.; myscenario=1;
end;
* scenario 2: y3(1:2) is known;
if(_N_>1 and _N_<=3) then do;
y1=.; y2=.; myscenario=2;
end;
* scenario 3: y3(1:3) is known;
if(_N_>3 and _N_<=6) then do;
y1=.; y2=.; myscenario=3;
end;
* scenario 4: y3(1:4) is known;
if(_N_>6 and _N_<=10) then do;
y1=.; y2=.; myscenario=4;
end;
* scenario 5: nothing is known (unconditional forecast);
if(_N_>10) then do;
y1=.; y2=.; y3=.; myscenario=5;
end;
run;
%mend;
%macro hcEstimateAndForecast(tblSample,tblScenarios,alpha,lead,nmc,
tblF,tblCf,tblCfSim);
* tblSample: input table name for in-sample data;
* tblScenarios: input table name for scenarios;
* alpha: size of the confidence interval or credible interval;
* lead: future horizons;
* nmc: number of Monte Carlo iterations;
* tblF: output table name of equation-based point and interval forecasts;
* tblCf: output table name of conditionial point and interval forecasts;
* tblCfSim: output table name of simulated conditional forecasts;
proc varmax data=&tblSample.;
model y1 - y3 / p=2 prior noprint;
output alpha=&alpha. lead=&lead. out=&tblF. noprint;
condfore alpha=&alpha. lead=&lead. out=&tblCf. outsim=&tblCfSim.
sdata=&tblScenarios. sid=myscenario
parm=sampling(scenario) nbi=1000 nmc=&nmc.;
run;
%mend;
%macro hcSaveForecasts(dgpi,T,lead,nScenarios,tblDGP,tblF,tblCf,tblAll);
* dgpi: index of DGP;
* T: in-sample sample size;
* lead: future horizons;
* nScenarios: number of scenarios;
* tblDGP: input table name for full-sample data;
* tblF: input table name of equation-based point and interval forecasts;
* tblCf: input table name of conditionial point and interval forecasts;
* tblAll: output table name of point and interval forecasts for all DGPs;
data forecasts;
set &tblDGP.(firstobs=%eval(&T.+1) obs=%eval(&T.+&lead.) keep=Y1 Y2);
* for notation convenience, name equation-based forecasts as S0;
set &tblF.(firstobs=%eval(&T.+1) obs=%eval(&T.+&lead.)
rename=( for1=Y1_S0 for2=Y2_S0
lci1=Y1_LB_S0 uci1=Y1_UB_S0
lci2=Y2_LB_S0 uci2=Y2_UB_S0)
keep=FOR1 LCI1 UCI1 FOR2 LCI2 UCI2);
%do i = 1 %to &nScenarios.;
set &tblCf.(where=(myscenario_S&i.=&i.)
rename=( Y1_MEDIAN=Y1_S&i. Y2_MEDIAN=Y2_S&i.
Y1_LB=Y1_LB_S&i. Y1_UB=Y1_UB_S&i.
Y2_LB=Y2_LB_S&i. Y2_UB=Y2_UB_S&i.
myscenario=myscenario_S&i.)
keep=myscenario Y1_MEDIAN Y2_MEDIAN Y1_LB Y1_UB Y2_LB Y2_UB);
%end;
dgpIndex = &dgpi.;
h = _N_;
drop myscenario_S1 - myscenario_S&nScenarios.;
run;
proc append base=&tblAll. data=forecasts; run;
%mend;
%macro cfEvaluate(tblAll,lead,nSim,nScenarios,qScenario0,scenarioBM,tblEval);
* tblAll: input table name of point and interval forecasts for all DGPs;
* lead: future horizons;
* nSim: number of DGPs;
* nScenarios: number of scenarios;
* qScenario0: whether there is S0 for equation-based forecasts,
1 for yes and 0 for no;
* scenarioBM: the index of the benchmark scenario;
* tblEval: output table name for evaluation results;
proc iml;
use &tblAll.;
read all into d;
close;
lead = &lead.;
nSim = &nSim.;
nScenarios = &nScenarios. + &qScenario0.;
scenarioBM = &scenarioBM.;
nVars = 2;
sMAPE = J(lead,nScenarios*nVars,0);
rsMAPE = J(lead,nScenarios*nVars,0);
sizeCI = J(lead,nScenarios*nVars,0);
rLenCI = J(lead,nScenarios*nVars,0);
do iSim = 1 to nSim;
do h = 1 to lead;
do iScenario = 1 to nScenarios;
do iVar = 1 to nVars;
yF=d[(iSim-1)*lead+h,
nVars+((iScenario-1)*nVars+(iVar-1))*3+1];
yFlb=d[(iSim-1)*lead+h,
nVars+((iScenario-1)*nVars+(iVar-1))*3+2];
yFub=d[(iSim-1)*lead+h,
nVars+((iScenario-1)*nVars+(iVar-1))*3+3];
yFlbBM=d[(iSim-1)*lead+h,
nVars+((scenarioBM-1)*nVars+(iVar-1))*3+2];
yFubBM=d[(iSim-1)*lead+h,
nVars+((scenarioBM-1)*nVars+(iVar-1))*3+3];
y =d[(iSim-1)*lead+h,iVar];
* symmetric Mean Absolute Percentage Error (sMAPE);
if(abs(yF)+abs(y)>0) then do;
sMAPE[h,(iVar-1)*nScenarios+iScenario] =
sMAPE[h,(iVar-1)*nScenarios+iScenario]
+ 2*abs(yF-y)/(abs(yF)+abs(y))/nSim;
end;
* size;
if(y>=yFlb & y<=yFub) then do;
sizeCI[h,(iVar-1)*nScenarios+iScenario] =
sizeCI[h,(iVar-1)*nScenarios+iScenario] + 1/nSim;
end;
* relative length;
if(yFubBM-yFlbBM>0) then do;
rLenCI[h,(iVar-1)*nScenarios+iScenario] =
rLenCI[h,(iVar-1)*nScenarios+iScenario]
+ (yFub-yFlb)/(yFubBM-yFlbBM)/nSim;
end;
end;
end;
end;
end;
do h = 2 to lead;
do iScenario = 1 to nScenarios;
do iVar = 1 to nVars;
sMAPE[h,(iVar-1)*nScenarios+iScenario] =
(sMAPE[h,(iVar-1)*nScenarios+iScenario]
+ sMAPE[h-1,(iVar-1)*nScenarios+iScenario]*(h-1))/h;
end;
end;
end;
do h = 1 to lead;
do iScenario = 1 to nScenarios;
do iVar = 1 to nVars;
* relative symmetric Mean Absolute Percentage Error;
rsMAPE[h,(iVar-1)*nScenarios+iScenario] =
sMAPE[h,(iVar-1)*nScenarios+iScenario]
/ sMAPE[h,(iVar-1)*nScenarios+scenarioBM];
end;
end;
end;
* rearrange results;
n = ncol(sMAPE)/nVars;
evalResult = sMAPE[,1:n];
do iVar = 2 to nVars;
evalResult = evalResult // sMAPE[,(iVar-1)*n+1:iVar*n];
end;
do iVar = 1 to nVars;
evalResult = evalResult // rsMAPE[,(iVar-1)*n+1:iVar*n];
end;
do iVar = 1 to nVars;
evalResult = evalResult // sizeCI[,(iVar-1)*n+1:iVar*n];
end;
do iVar = 1 to nVars;
evalResult = evalResult // rLenCI[,(iVar-1)*n+1:iVar*n];
end;
evalResult = ((1:4)`@J(lead*nVars,1,1))
|| (J(4,1,1)@((1:nVars)`@J(lead,1,1)))
|| (J(4*nVars,1,1)@(1:lead)`)
|| evalResult;
create &tblEval. from evalResult;
append from evalResult;
close;
quit;
%mend;
%macro hcTest(nSim,T,lead,alpha,nmc,nScenarios,qScenario0,scenarioBM,
tblAll,tblEval);
* nSim: number of DGPs;
* T: in-sample sample size;
* lead: future horizons;
* alpha: size of the confidence interval or credible interval;
* nmc: number of Monte Carlo iterations;
* nScenarios: number of scenarios;
* qScenario0: whether there is scenario 0 for equation-based forecasts,
1 for yes and 0 for no;
* scenarioBM: the index of the benchmark scenario;
* tblAll: output table name of point and interval forecasts for all DGPs;
* tblEval: output table name for evaluation results;
%do iSim = 1 %to &nSim.;
%cfSimulateData(&iSim.,&T.,&lead.,t1,t2);
%hcConstructScenarios(&T.,t1,t3);
%hcEstimateAndForecast(t2,t3,&alpha.,&lead.,&nmc.,of,ocf,ocfsim);
%hcSaveForecasts(&iSim.,&T.,&lead.,&nScenarios.,t1,of,ocf,&tblAll.);
%end;
%cfEvaluate(&tblAll.,&lead.,&nSim.,
&nScenarios.,&qScenario0.,&scenarioBM.,
&tblEval.);
%mend;
%let nSim = 1000;
%let T = 200;
%let lead = 4;
%let alpha = 0.05;
%let nmc = 10000;
%let nScenarios = 5;
%let qScenario0 = 1;
%let scenarioBM = 6;
%hcTest(&nSim.,&T.,&lead.,&alpha.,&nmc.,
&nScenarios.,&qScenario0.,&scenarioBM.,
hcForecasts,hcEval);
proc template;
define table hcEvalTemplate;
column col3 col4 col5 col6 col7 col8 col9;
define header hc;
text "Conditional Forecasts, Hard Conditions";
start=col5; end=col8;
end;
define column col3;
header="Horizon";
end;
define column col4;
header="Equation Based"; format=7.5;
end;
define column col5;
header="Scenario 1"; format=12.5;
end;
define column col6;
header="Scenario 2"; format=12.5;
end;
define column col7;
header="Scenario 3"; format=12.5;
end;
define column col8;
header="Scenario 4"; format=12.5;
end;
define column col9;
header="Unconditional"; format=12.5;
end;
end;
run;
%macro cfPrint(template,data);
data _NULL_;
set &data.;
file print ods=(template="&template.");
put _ODS_;
run;
%mend;
%cfPrint(hcEvalTemplate, hcEval(where=(col1=1 and col2=1)));
%cfPrint(hcEvalTemplate, hcEval(where=(col1=1 and col2=2)));
%cfPrint(hcEvalTemplate, hcEval(where=(col1=2 and col2=1)));
%cfPrint(hcEvalTemplate, hcEval(where=(col1=2 and col2=2)));
%cfPrint(hcEvalTemplate, hcEval(where=(col1=3 and col2=1)));
%cfPrint(hcEvalTemplate, hcEval(where=(col1=3 and col2=2)));
%cfPrint(hcEvalTemplate, hcEval(where=(col1=4 and col2=1)));
%cfPrint(hcEvalTemplate, hcEval(where=(col1=4 and col2=2)));
****************************************************************;
* Soft Conditions ;
****************************************************************;
%macro scEstimateAndForecast(tblSample,alpha,lead,nmc,tblUcf,tblUcfSim);
* tblSample: input table name for in-sample data;
* alpha: size of the credible interval;
* lead: future horizons;
* nmc: number of Monte Carlo iterations;
* tblUcf: output table name of unconditional point and interval
forecasts;
* tblUcfSim: output table name of simulated unconditional forecasts;
proc varmax data=&tblSample.;
model y1 - y3 / p=2 prior noprint;
condfore alpha=&alpha. lead=&lead. out=&tblUcf. outsim=&tblUcfSim.
parm=sampling nbi=1000 nmc=&nmc.;
run;
%mend;
%macro scConstructScenarios(T,lead,tblDGP,tblUcf);
* T: in-sample sample size;
* lead: future horizons;
* tblDGP: input table name for full-sample data;
* tblUcf: input table name of unconditional point and interval
forecasts;
* four scenarios are implicitly output:
scenarios i, i=1 to 4: future y3 is known for
lb_j<=y3_j<=ub_j, j=1 to i, where lb_j and ub_j are lower and
upper bounds whose values are saved in the corresponding macro
variables, and y3_j is the j-step-ahead furture value of y3;
data _NULL_;
set &tblDGP.(firstobs=%eval(&T.+1) obs=%eval(&T.+&lead.) keep=Y3);
set &tblUcf.(keep=step Y3_MEDIAN Y3_LB Y3_UB);
array q[&lead.] q1 - q&lead.;
array lb[&lead.] lb1 - lb&lead.;
array ub[&lead.] ub1 - ub&lead.;
retain q lb ub;
if(Y3<=Y3_LB) then do;
q[step] = 1; ub[step] = Y3_LB;
end;
if (Y3>Y3_LB and Y3<=Y3_MEDIAN) then do;
q[step] = 2; lb[step] = Y3_LB; ub[step] = Y3_MEDIAN;
end;
if (Y3>Y3_MEDIAN and Y3<=Y3_UB) then do;
q[step] = 3; lb[step] = Y3_MEDIAN; ub[step] =Y3_UB;
end;
if (Y3>Y3_UB) then do;
q[step] = 4; lb[step] = Y3_UB;
end;
if(_N_=&lead.) then do;
%do i = 1 %to &lead.;
call symputx("lb&i.",lb&i.,'G');
call symputx("ub&i.",ub&i.,'G');
%end;
end;
run;
%mend;
%macro scClassifySimulatedForecasts(lead,tblUcfSim,tblSCSim);
* lead: future horizons;
* tblUcfSim: output table name of simulated unconditional forecasts;
* tblSCSim: output table name of simulated conditional forecasts
under soft conditioins specified in the scenarios;
data &tblSCSim.;
set &tblUcfSim.;
array lb[&lead.] lb1 - lb&lead.;
array ub[&lead.] ub1 - ub&lead.;
array y3f[&lead.] y3_1 - y3_&lead.;
%do j = 1 %to &lead.;
lb[&j.]=&&lb&j.; ub[&j.]=&&ub&j.;
%end;
do myScenario=1 to 4;
outputCond = 1;
do i = 1 to myScenario;
if(outputCond=1) then do;
if(lb[i]=.) then do;
if(y3f[i]<=ub[i]) then outputCond=1;
else outputCond = 0;
end;
else do;
if(ub[i]=.) then do;
if(y3f[i]>lb[i]) then outputCond=1;
else outputCond = 0;
end;
else do;
if(y3f[i]>lb[i] and y3f[i]<=ub[i]) then outputCond=1;
else outputCond = 0;
end;
end;
end;
end;
if(outputCond=1) then output;
end;
run;
proc sort data=&tblSCSim.; by myscenario; run;
%mend;
%macro scGetForecastStats(alpha,lead,tblSCSim,tblSCForecasts);
* alpha: size of the credible interval;
* lead: future horizons;
* tblSCSim: input table name of simulated conditional forecasts
under soft conditioins specified in the scenarios;
* tblSCForecasts: output table name of conditional point and interval
forecasts under soft conditioins specified in the scenarios;
data _NULL_;
lbPctl = &alpha./2*100;
ubPctl = 100-lbPctl;
call symputx("lbPctl",lbPctl,'G');
call symputx("ubPctl",ubPctl,'G');
run;
proc univariate data=&tblSCSim. noprint;
var y1_1 - y1_&lead. y2_1 - y2_&lead.;
output out=oucfx pctlpts=&lbPctl. &ubPctl. 50
pctlpre=%do j=1 %to &lead.; y1_&j. %end;
%do j=1 %to &lead.; y2_&j. %end;
pctlname=_lb _ub _median;
by myscenario;
run;
data &tblSCForecasts.;
set oucfx;
array y1f[&lead.] %do j=1 %to &lead.; Y1_&j._median %end; ;
array y1lb[&lead.] %do j=1 %to &lead.; Y1_&j._lb %end; ;
array y1ub[&lead.] %do j=1 %to &lead.; Y1_&j._ub %end; ;
array y2f[&lead.] %do j=1 %to &lead.; Y2_&j._median %end; ;
array y2lb[&lead.] %do j=1 %to &lead.; Y2_&j._lb %end; ;
array y2ub[&lead.] %do j=1 %to &lead.; Y2_&j._ub %end; ;
do i = 1 to &lead.;
Y1_MEDIAN = y1f[i];
Y1_LB = y1lb[i];
Y1_UB = y1ub[i];
Y2_MEDIAN = y2f[i];
Y2_LB = y2lb[i];
Y2_UB = y2ub[i];
step = i;
output;
end;
keep myscenario step y1_median y1_lb y1_ub y2_median y2_lb y2_ub;
run;
%mend;
%macro scSaveForecasts(dgpi,T,lead,tblDGP,tblUcf,tblSCForecasts,tblAll);
* dgpi: index of DGP;
* T: in-sample sample size;
* lead: future horizons;
* tblDGP: input table name for full-sample data;
* tblUcf: input table name of unconditional point and interval
forecasts;
* tblSCForecasts: input table name of conditional point and interval
forecasts under soft conditioins specified in the scenarios;
* tblAll: output table name of point and interval forecasts for all DGPs;
data forecasts;
set &tblDGP.(firstobs=%eval(&T.+1) obs=%eval(&T.+&lead.) keep=Y1 Y2);
%do i = 1 %to 4;
set &tblSCForecasts.( where=(myscenario_S&i.=&i.)
rename=( Y1_MEDIAN=Y1_S&i. Y2_MEDIAN=Y2_S&i.
Y1_LB=Y1_LB_S&i. Y1_UB=Y1_UB_S&i.
Y2_LB=Y2_LB_S&i. Y2_UB=Y2_UB_S&i.
myscenario=myscenario_S&i.)
keep=myscenario Y1_MEDIAN Y2_MEDIAN Y1_LB Y1_UB Y2_LB Y2_UB);
%end;
set &tblUcf.(
rename=( Y1_MEDIAN=Y1_S5 Y2_MEDIAN=Y2_S5
Y1_LB=Y1_LB_S5 Y1_UB=Y1_UB_S5
Y2_LB=Y2_LB_S5 Y2_UB=Y2_UB_S5 )
keep=Y1_MEDIAN Y2_MEDIAN Y1_LB Y1_UB Y2_LB Y2_UB);
dgpIndex = &dgpi.;
h = _N_;
drop myscenario_S1 - myscenario_S4;
run;
proc append base=&tblAll. data=forecasts; run;
%mend;
%macro scTest(nSim,T,lead,alpha,nmc,nScenarios,qScenario0,scenarioBM,
tblAll,tblEval);
* nSim: number of DGPs;
* T: in-sample sample size;
* lead: future horizons;
* alpha: size of the confidence interval or credible interval;
* nmc: number of Monte Carlo iterations;
* nScenarios: number of scenarios;
* qScenario0: whether there is S0 for equation-based forecasts,
1 for yes and 0 for no;
* scenarioBM: the index of the benchmark scenario;
* tblAll: output table name of point and interval forecasts for all DGPs;
* tblEval: output table name for evaluation results;
%do iSim = 1 %to &nSim.;
%cfSimulateData(&iSim.,&T.,&lead.,t1,t2);
%scEstimateAndForecast(t2,&alpha.,&lead.,&nmc.,oucf,oucfsim);
%scConstructScenarios(&T.,&lead.,t1,oucf);
%scClassifySimulatedForecasts(&lead.,oucfsim,oucfsimx);
%scGetForecastStats(&alpha.,&lead.,oucfsimx,oscf);
%scSaveForecasts(&iSim.,&T.,&lead.,t1,oucf,oscf,&tblAll.);
%end;
%cfEvaluate(&tblAll.,&lead.,&nSim.,
&nScenarios.,&qScenario0.,&scenarioBM.,
&tblEval.);
%mend;
%let nSim = 1000;
%let T = 200;
%let lead = 4;
%let alpha = 0.50;
%let nmc = 100000;
%let nScenarios = 5;
%let qScenario0 = 0;
%let scenarioBM = 5;
%scTest(&nSim., &T.,&lead.,&alpha.,&nmc.,
&nScenarios.,&qScenario0.,&scenarioBM.,
scForecasts,scEval);
proc template;
define table scEvalTemplate;
column col3 col4 col5 col6 col7 col8;
define header sc;
text "Conditional Forecasts, Soft Conditions";
start=col4; end=col7;
end;
define column col3;
header="Horizon";
end;
define column col4;
header="Scenario 1"; format=12.5;
end;
define column col5;
header="Scenario 2"; format=12.5;
end;
define column col6;
header="Scenario 3"; format=12.5;
end;
define column col7;
header="Scenario 4"; format=12.5;
end;
define column col8;
header="Unconditional"; format=12.5;
end;
end;
run;
%cfPrint(scEvalTemplate, scEval(where=(col1=1 and col2=1)));
%cfPrint(scEvalTemplate, scEval(where=(col1=1 and col2=2)));
%cfPrint(scEvalTemplate, scEval(where=(col1=2 and col2=1)));
%cfPrint(scEvalTemplate, scEval(where=(col1=2 and col2=2)));
%cfPrint(scEvalTemplate, scEval(where=(col1=3 and col2=1)));
%cfPrint(scEvalTemplate, scEval(where=(col1=3 and col2=2)));
%cfPrint(scEvalTemplate, scEval(where=(col1=4 and col2=1)));
%cfPrint(scEvalTemplate, scEval(where=(col1=4 and col2=2)));