program rosssekh, rclass

	capture drop cvgraph1
	capture drop cvrs
	capture drop RollingTestStat1
	capture drop RollingTestStat
	capture drop RossSekhTest

	syntax varlist(min = 2) [if] [in], window(integer) alpha(real) [nw(integer -1) *]

	* Count the number of forecasts to be tested
	local narg = 1
	while "``narg''" != "" {
		local ++narg
	}
	if `nw' > 0 {
	local narg = `narg' - 5
	}
	else if `nw' == 0 {
	local narg = `narg' - 5
	}
	else if `nw' == -1 {
	local narg = `narg' - 4
	}
	*


	* Clear the variables that have already been created if the test has been run before...
	capture drop forecasterror
	capture drop forecasterrortemp
	local vartemp = 1
	while "``vartemp''" != "" & `vartemp' <= `narg' {
		local ++vartemp
		local errorname = "forecasterror"+regexr("``vartemp''", ",","")
		capture drop `errorname'
	}
	*
	disp " "
	disp " "
	disp as text "Running the Rossi - Sekhposyan (2016) forecast rationality test..."
	disp " "
	*disp "REMINDER"
	*disp "Forecast: " regexr("`2'", ",","")
	*disp "Actual series: " regexr("`1'", ",","")
	*disp " "

	if `nw' == -1{
	disp "WARNING"
	disp "When no bandwidth is specified using the nw(.) option, the test statistics are NOT calculated using HAC variance estimators. "
	disp " "
	}
	*

	* Matrix of critical values for the test

	if `alpha'==0.01{
		matrix critvalu = (0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9\1,15.0484,14.0966,12.0133,12.5257,11.2177,10.5051,9.4237,8.5435,8.203\2,18.5865,15.9096,16.8898,14.1998,14.0067,14.1862,12.5407,12.8689,10.4675\3,22.2589,18.461,18.1309,16.6749,16.6152,16.6209,15.182,14.2981,12.7461\4,23.2931,22.6241,20.4215,20.1829,18.5263,18.7161,17.1985,16.8407,15.3503\5,25.9859,24.9017,22.113,22.3233,22.0671,19.2611,19.5215,17.5694,18.9347\6,28.3701,27.1948,25.1033,24.2014,24.8307,22.2983,20.9119,19.108,18.074\7,31.4425,28.9881,27.1075,26.9725,24.3925,24.0897,24.2268,21.7648,20.5248\8,32.4669,29.5149,28.6144,28.1559,26.8484,26.2502,25.2785,23.0942,22.8633\9,33.7114,35.2864,31.3305,29.5492,29.0904,28.217,25.6922,26.0238,24.8479\10,36.6704,33.1601,32.265,32.6074,30.0138,31.1782,27.3047,25.9979,26.2313)
	}
	else if `alpha==0.05'{
		matrix critvalu = (0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9\1,11.829,10.5637,8.9252,8.1468,8.1409,7.2803,6.4978,6.0837,5.4695\2,14.9966,13.0846,12.8141,10.9084,11.1314,9.9386,9.1724,9.0589,7.8305\3,17.6768,15.7548,15.0608,13.4383,13.2113,12.6018,10.9597,10.8426,9.4727\4,19.8434,17.6051,17.0158,16.3186,15.1404,14.7573,13.5928,13.1087,10.8243\5,21.7091,20.4659,18.7186,18.2152,17.1092,15.6317,15.4842,13.9418,13.6335\6,24.2721,22.487,20.9717,20.2839,20.2971,17.8602,16.5583,15.4633,14.4789\7,26.2869,24.2644,22.8543,21.6818,20.5974,20.12,19.0697,17.7064,15.9126\8,28.303,25.7461,24.3315,23.4497,22.4328,21.1563,20.3632,19.144,18.1475\9,29.5489,27.9249,26.8101,25.2662,24.251,22.7821,21.7109,20.2745,19.7147\10,31.7548,29.4709,27.598,27.0357,25.3011,25.325,23.4556,22.618,21.6647)
	}
	else if `alpha==0.10'{
		matrix critvalu = (0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9\1,10.0909,8.8274,7.7116,6.9555,6.4272,5.841,4.9404,4.8508,4.0096\2,13.2456,11.4773,10.7955,9.6482,9.3648,8.3442,7.7478,7.4669,6.2243\3,15.9915,14.2049,13.3396,11.6461,11.4939,10.4839,9.39,8.9699,7.9423\4,18.4447,15.5897,15.1254,13.8661,13.2415,12.7312,11.5331,10.7335,9.3509\5,19.969,18.2447,16.719,15.7116,15.0672,14.1355,13.1798,12.1317,11.4857\6,22.3413,20.3183,19.1924,18.0867,17.3395,15.6658,14.764,13.4408,12.3823\7,24.3462,22.3182,21.0891,20.0822,18.4705,17.7375,16.8276,15.6473,13.922\8,26.593,23.8825,22.407,21.6763,20.1078,18.7631,18.1456,17.0475,15.8832\9,27.8409,26.0117,24.504,23.3912,21.4939,20.6265,19.2173,18.056,17.2398\10,29.2933,27.1103,25.8483,24.6502,23.4647,22.5659,20.667,20.0081,18.402)
	}



	* Create variable(s) containing forecast error
	local vartemp = 1
	while "``vartemp''" != "" & `vartemp' <= `narg' {
		local ++vartemp
		local errorname = "forecasterror"+regexr("``vartemp''", ",","") // the name where the forecast error is stored.
		local command = regexr("`1'", ",","")+"-"+regexr("``vartemp''", ",","") // The command used by stata to compute the forecast error.
		generate forecasterrortemp = `command'
		rename forecasterrortemp `errorname'
	}
	*

	* Get critical value for the test
	qui count if `1' !=.
	local P = r(N)
	set matsize `P'
	local mu =`window'/`P'
	local cvcol = round(`mu'*10)+1
	if `cvcol' == 1 {
	`cvcol' = 2
	}
	if `cvcol' > 10 {
	`cvcol' = 10
	}
	local nreg = `narg' + 1
	local cv = critvalu[`nreg' + 1,`cvcol']
	disp as text "Critical value for the test: " `cv'

	* Rolling ols regression: regressing the forecast error on reference forecasts
	local T = _N
	local nlag = int(`window'^(1/4))
	mat RollingTestStat = J(`T' - `window' + 1,1,1)
	forvalues j=`window'(1)`P'{
	if `nreg' == 1 {
	*
	}
	else {
	local start = `j'-`window'+1
	local end = `j'
	local command = "`errorname'" + " " + regexr("`2'", ",","") + " in " + "`start'" + "/" + "`end'"
	if `nw' > 0 {
	qui newey `command', lag(`nw') force // regression with Newey-West standard errors, lag length is given by user
	}
	else if `nw' == 0{
	qui newey `command', lag(`nlag') force // regression with Newey-West standard errors, lag length is round(w^0.25)
	}
	else if `nw' == -1{
	qui reg `command' // regression without Newey-West standard errors
	}
	mat foo = e(b)*inv(e(V))*e(b)'
	mat RollingTestStat[`j' - `window'+1,1] = foo[1,1]
	*
	}
	}
	mat cvgraph = `cv'*J(`P',1,1)
	svmat cvgraph, names(cvgraph)
	capture generate cvrs = cvgraph1[_n - `window' + 1]
	svmat RollingTestStat, names(RollingTestStat)
	capture generate RossSekhTest = RollingTestStat1[_n - `window' + 1]
	disp as text "NOTE: the program generates two variables for plotting:"
	disp "           - cvrs, which contains the critical values"
	disp "           - RossSekhTest, which contains the sequence of rolling Rossi - Sekhposyan test statistics"
	disp " "
	disp " "
	disp " "
	disp " "

	capture drop cvgraph1
	capture drop RollingTestStat1
	capture drop `errorname'

	qui sum RossSekhTest
	local tstat_inf = r(min)
	local tstat_sup = r(max)


	qui tsset
	local timevariable = r(timevar)
	line cvrs RossSekhTest `timevariable' in `window'/`T', ///
	legend(order(1 2) label(1 "Critical value") label(2 "R-S test stat.")) ///
	lpattern(dash solid) ///
	color(red blue) ///
	xtitle(Time) ///
	xlabel(,labsize(small)) ///
	ylabel(,labsize(small)) ///
	title(Rossi - Sekhposyan Forecast Rationality Test)

	* ereturn post


	/* Results to return */
	return scalar cv = `cv'
	return matrix CV critvalu
	return matrix RollStat RollingTestStat
	return local cmdline `"`0'"'
	return local cmd "rosssekh"
	return scalar tstat_sup = `tstat_sup'
	return scalar level = `alpha'

	disp "Rossi and Sekhposyan's (2016) test rejects the null hypothesis of forecast rationality when the test statistic is above the critical value line."
	disp "Done!"

end