program Nowcast syntax varlist , date(varname) freq(name) target(varname) model(name) legend(name) [factors(integer 2) shocks(integer 1) varorder(integer 1) forecast(integer 1) copy delete verbose bridgevars(varlist ts)] qui { /* Notes */ * This program only applies if the data is monthly. * But target variable can be either monthly or quarterly. /* options */ * date: date variable * freq: frequency of target variable (m or q for now) * target: target variable * model: name to prefix variables (used when copy is specified) * factors: number of factors * shocks: number of common shocks to the factors * varorder: VAR order, number of lags * legend: name of legend file, must be in the current working directory * forecast: number of forecasts to make after the end of the current data set (used to tsappend) * copy: if to copy specified variables and prefix the name with model name or replace all variables involved * delete: if variables not used are to be deleted, usually combined with copy to generate a data set containing only variables involved * verbose: if to display additional log information * bridgevars: variables to be put in the bridge equation. if specified, then the vairiables won't be used in factor extraction. /* example command */ * Nowcast x1 x2 x3 x4, date(month) freq(M) target(rgdp) model(M1) factors(3) shocks(2) varorder(4) legend(legend) forecast(12) copy delete /* Check bridge equation specification */ if "`bridgevars'"!="" { noi LogShow Variables to be put in bridge equation in addition to factors: `bridgevars' noi di as error "Out-of-sample forecasting not possible with independent variables in bridge equations!" } /* set verbose global */ global verbose `verbose' noi LogShow Check user specified variables and options /* Check frequency */ if lower("`freq'")=="m" { noi LogShow Target variable is monthly } else if lower("`freq'")=="q" { noi LogShow Target variable is quarterly } else { noi di as error "Unable to recognize specified frequency `freq'" exit 3000 } /* tsset data */ tsset `date' /* delete unused variables when asked to */ if "`delete'"=="delete" { noi LogShow Delete unused variables... keep `date' `target' `varlist' `bridgevars' } /* Create copy of variables to use */ if "`copy'"=="copy" { if "`model'"!="" { noi LogShow Make copies of variables to be used... foreach var of varlist `target' `varlist' { cap drop `var'_`model' gen `var'_`model' = `var' local vartouse "`vartouse' `var'_`model'" } } else { noi di as error "No model name specified for copy" exit 3000 } } else { local vartouse "`varlist'" } /* Transform variables */ * preserve current data noi LogShow Read legend file information preserve * read legend file use `legend'.dta, clear * count number of entries count local max=r(N) * read for each entry the transformation code forvalues obs=1/`max' { local name = varname[`obs'] local transcode = transcode[`obs'] if "`copy'"=="copy" { local `name'_`model'=`transcode' } else { local `name'=`transcode' } } * get back to current data restore noi LogShow Transcodes obtained from legend file * transform independent variables noi LogShow Transform variables according to transcode foreach var of varlist `vartouse' `target' { if "``var''"=="1" { * monthly growth rate cap drop `var'_tmp gen `var'_tmp = ((`var'-l.`var')/l.`var')*100 in 13/l replace `var' = `var'_tmp cap drop `var'_tmp } else if "``var''"=="2" { * monthly differences cap drop `var'_tmp gen `var'_tmp = d.`var' in 13/l replace `var' = `var'_tmp cap drop `var'_tmp } else if "``var''"=="3" { * monthly diff of yearly growth rate cap drop `var'_tmp gen `var'_tmp = ((`var'-l12.`var')/l12.`var')*100 in 13/l replace `var' = `var'_tmp cap drop `var'_tmp } else if "``var''"=="0" { * no transform } else { noi di as error "Unable to recognize transformation code ``var'' of variable `var'" exit 3000 } } * drop initial 12 observations lost due to transformation noi LogShow Drop initial 12 observations lost due to transformation drop in 1/12 * Trasform monthly diffenences (growth rates) in quarterly equivalents if lower("`freq'")=="q" { noi LogShow Trasform monthly diffenences (growth rates) in quarterly equivalents foreach var of varlist `vartouse' { cap drop `var'_tmp gen `var'_tmp = `var'+2*l.`var' if `var'!=.&(`var'+2*l.`var')!=.&_n==2 replace `var'_tmp = `var'+2*l.`var'+3*l2.`var' if `var'!=.&(`var'+2*l.`var'+3*l2.`var')!=.&_n==3 replace `var'_tmp = `var'+2*l.`var'+3*l2.`var'+2*l3.`var' if `var'!=.&(`var'+2*l.`var'+3*l2.`var'+2*l3.`var')!=.&_n==4 replace `var'_tmp = `var'+2*l.`var'+3*l2.`var'+2*l3.`var'+l4.`var' if `var'!=.&(`var'+2*l.`var'+3*l2.`var'+2*l3.`var'+l4.`var')!=.&_n>5 replace `var' = `var'_tmp if `var'!=.&`var'_tmp!=. cap drop `var'_tmp } } /* Make user data starts from first month of a quarter */ noi LogShow Drop the first few observations if necessary to make the data starts from first month of a quarter if !(month(dofm(`date'))==1|month(dofm(`date'))==4|month(dofm(`date'))==7|month(dofm(`date'))==10) { drop in 1 } if !(month(dofm(`date'))==1|month(dofm(`date'))==4|month(dofm(`date'))==7|month(dofm(`date'))==10) { drop in 1 } /* Uses only the series for which there are less than 1/3 of missing data */ noi LogShow Check if the amount of missing data is more than 1/3 count local total=r(N) foreach var of varlist `vartouse' { count if `var'==. local miss = r(N) if `miss'/`total'>1/3 { local missvar "`missvar' `var'" } } if length("`missvar'")!=0 { noi di as error "There are variables with more than 1/3 of missing data:" noi di as error "`missvar'" exit 3000 } /* Outliers Correction */ noi LogShow Correct for missing values and outliers su `date' if `target'!=. local MaxDateToCorrect=r(max)-12 local StartDate = r(min) OutliersCorrection `vartouse', date(`date') end(`MaxDateToCorrect') start(`StartDate') /* Add observations to hold forecasts */ su `date' local allmax = r(max) su `date' if `target'!=. local targetmax = r(max) if lower("`freq'")=="q" { local toadd = `forecast'*3 - (`allmax'-`targetmax') } else { local toadd = `forecast' - (`allmax'-`targetmax') } if `toadd'>0 { noi LogShow Add observations to hold forecasts tsappend, add(`toadd') } /* Set up new date variable for regression */ if lower("`freq'")=="q" { noi LogShow Set up quarterly date variable tempvar quarter cap drop `quarter' gen `quarter' = qofd(dofm(`date')) if (month(dofm(`date'))==3|month(dofm(`date'))==6|month(dofm(`date'))==9|month(dofm(`date'))==12) local date2 "`quarter'" } else { local date2 "`date'" } /* Factor Extraction */ noi LogShow Start extracting factors FactorExtraction `vartouse', q(`shocks') r(`factors') p(`varorder') name(EstFct) /* Forecast and report results */ if "`forecast'"=="1" { cap drop `target'_pred tsset `date2' reg f.`target' EstFct* `bridgevars' if `date2'!=. tempvar pred cap drop `pred' predict `pred', xb gen `target'_pred = `pred' if `date2'!=. tsset `date' } else { forvalues h=1/`forecast' { if "`bridgevars'"!="" { local lbridgevars " " foreach var of varlist `bridgevars' { local lbridgevars "`lbridgevars' l`h'.`var'" } } cap drop `target'_pred`h' tsset `date2' reg `target' EstFct* `lbridgevars' if `date2'!=. tempvar pred cap drop `pred' predict `pred', xb gen `target'_pred`h' = `pred' if `date2'!=. tsset `date' } } * end quietly } * di "Summary statistics of target variable `target'" * su `target' * feval `target' `target'_pred end program LogShow if "$verbose"=="verbose" { noisily display as text "[" c(current_time) "] " "`0'" } end program feval, rclass version 10 syntax varlist(min=2 max=2 numeric) [if] [in] qui { marksample touse preserve keep if `touse' tempvar a b c d e f g gen `a'=(`1'-`2')^2 gen `b'=abs(`1'-`2') su `a' local mse=round(r(mean), 0.0001) local rmse=round(`mse'^0.5, 0.0001) su `b' local mae=round(r(mean), 0.0001) gen `c'=(`1'-`2') su `c' local me=round(r(mean), 0.0001) gen `d' = `c'/`1' su `d' local mpe=round(r(mean), 0.0001) gen `e'=abs(`d') su `e' local mape=round(r(mean), 0.0001) gen `f'=(`1'-`1'[_n-1])^2 su `f' local rmsenc = round(r(mean)^0.5, 0.0001) local u=`rmse'-`rmsenc' corr `1' `2' local corr = round(r(rho), 0.0001) restore return local me = `me' return local mae = `mae' return local mpe = `mpe' return local mape = `mape' return local mse = `mse' return local rmse = `rmse' return local u = `u' return local corr = `corr' noi di in smcl "{hline 41}" _asis noi di as text "Simple Statistics for Forecast Evaluation" noi di in smcl "{hline 41}" _asis noi di as text "Target: " as result "`1'" as text "; Forecast: " as result "`2'" noi di in smcl "{hline 41}" _asis noi di as text " ME: " as result %10.4f `me' _column(26) as text " MAE: " as result %10.4f `mae' noi di as text "MPE: " as result %10.4f `mpe' _column(26) as text "MAPE: " as result %10.4f `mape' noi di as text "MSE: " as result %10.4f `mse' _column(26) as text "RMSE: " as result %10.4f `rmse' noi di as text " Theil's U: " as result %10.4f =`u' noi di as text "Correlation: " as result %10.4f =`corr' noi di in smcl "{hline 41}" _asis } end