<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="gfn2html.xsl"?>
<gretl-functions>
<gretl-function-package name="gqtest" model-requirement="ols" minver="2024a">
<author email="oleh.komashko1@gmail.com">Oleh Komashko</author>
<version>0.38</version>
<date>2026-07-17</date>
<description>obtains weights to use in wls, GQ het. test</description>
<tags>C20 C12</tags>
<label>Goldfeld - Quandt test</label>
<menu-attachment>MODELWIN/Tests</menu-attachment>
<help>
The package contains 2 functions to obtain weights
to use in wls for popular versions of feasible weighted least
squares. In addition it performs Goldfeld - Quandt heteroskedasticity test.
It includes 5 public functions.
Test: gqtest(), GUI_gqtest(), gqtest_print().
Wls-helpers: clustweights(), expweights()

The main reason for this package is pedagogical.
There are plethora of books &quot;Using Soft (e.g., Stata, Eviews, Excel)
with Hill Griffiths Lim&quot;. And there exists a possibility of someone
making an opinion of a piece of software by comparing how simple is
to solve computer exercises in it.
The package contains two functions to compute
clustered and exponential weights for further use with wls.
Additionally, the package allows testing group-wise
heteroskedasticity as in HGL, 4-th, 8.2.3. As Prof. Riccardo Lucchetti wrote:
&quot;Nobody uses this test anymore in serious empirical
research, and it's rapidly disappearing from textbooks as well.&quot;
But the package author thinks it can be useful for the courses
relying upon HGL.


FUNCTIONS DESCRIPTION

function matrix gqtest (series y &quot;the dependent var&quot;,
                        list xl &quot;independent vars, include 'const',
                        if required&quot;,
                        series sby[null] &quot;variable to sort by&quot;,
                        scalar c[0:1:NA]) &quot;fraction of middle obs. to omit&quot;)
Outputs a 1 by 4 matrix: F-statistics, 2 degrees of freedom, and
2-sided p-value. Always prints the results. This function doesn't support
panel data.
Parameters:
c - must be in (0,1), for the only exception see below,
    fraction of the sample to omit; default is 1/3
sby - variable to sort observations by
    if 'sby' is dummy, 'c' is ignored, the sample split rule
      is 0/1
    if 'sby' is integer variable with 3 distinct values, and c=1
      sby is used for idiosyncratic splitting of the sample with
      observations, corresponding to the middle value omitted.
    if 'sby' = 'const', observations are not sorted, as in
    time series setting.
    if sby is missed, it is set as 'const'
Usage:

 nulldata 24
 series y = normal(0,1)
 x1 = normal(0,1)
 x2 = normal(0,1)
 series qwerty = normal(0,1)
 list xl =  0 x1 x2
 d = (obs&gt;14)
 dd = (obs&lt;6)+2*(obs&gt;16)

gqtest(y,xl) # data sorted by y; middle 1/3 omitted
gqtest(y,xl,qwerty) # data sorted by qwerty; middle 1/3 omitted
gqtest(y,xl,const) # data unsorted ; middle 1/3 omitted
gqtest(y,xl,d) # 'c' ignored
gqtest(y,xl,dd,1) # obs. with middle values of dd omitted


function bundle GUI_gqtest (series sby[null] &quot;variable to sort by&quot;,
                            scalar c[NA] &quot;fraction of middle obs. to omit&quot;)

GUI path: model window (ols)-&gt; tests
The GUI version omits 2 first arguments in comparison
with script version, since the dependent variable and regressors
are the same as in the estimated model.

function void gqtest_print (bundle *b)
A helper to GUI version: the script version outputs a matrix
and prints the results by default. This function doesn't support
panel data.


function series clustweights (series y &quot;the dependent variable&quot;,
      list xlist &quot;independent variables&quot;,
      series clustvar &quot;cluster variable&quot;)
Computes weights series to use in wls estimation
for grouped data, as described in POE-4, s. 8.4.2.
Example (datafile from POE-4):
open cps2.gdt
list xlist = 0 educ exper metro
w = clustweights (wage, xlist, metro)
wls w wage xlist


function series expweights (series y &quot;the dependent variable&quot;,
    list xlist &quot;independent variables&quot;,
    list zlist[null] &quot;sd vars, null: logs xlist, zlist=xlist==hsk&quot;)
Computes weights series to use in wls estimation according
to the following model for variance:
log(sigma_i^2) = const + z'_i*alpha
See, e.g POE-4, s. 8.5.
zlist = null means zlist = log(xlist), if possible

Example (datafile from POE-4):
variables in the variance model are the logarithms of the original
regression variables

open food.gdt
list xlist = 0 income
series wtb = expweights(food_exp, xlist)
wls wtb food_exp 0 income

List of abbreviations
POE - gretl data set to Principles of Econometrics.
HGL, POE-4 - Hill, Griffiths, Lim - Principles of Econometrics - Fourth
Edition.

NEWS  in 0.3
Printing pvalues for one-sided alternatives added to qgtest
2 new functions added: clustweights(), expweights().
NEWS  in 0.38
Type of sby in qtest() changed to series.
Some changes in help file.
</help>
<gretl-function name="clustweights" type="series">
 <params count="3">
  <param name="y" type="series">
<description>the dependent variable</description>
  </param>
  <param name="xlist" type="list">
<description>independent variables</description>
  </param>
  <param name="clustvar" type="series">
<description>cluster variable</description>
  </param>
 </params>
<code>cvals = uniq(clustvar)
ncv = nelem(cvals)
matrix sigmas = zeros(ncv,1)
loop i=1..ncv -q
  smpl  (clustvar==cvals[i]) --restrict --replace
  ols y xlist -q
  sigmas[i] = $sigma
endloop
smpl full
series www = 0
loop i=1..ncv -q
  www = www+(clustvar==cvals[i])/(sigmas[i])^2
endloop
www = www/sd(www)
setinfo www --description=&quot;cluster weights&quot;
return www
</code>
</gretl-function>
<gretl-function name="GUI_gqtest" type="bundle" no-print="1" menu-only="1" pkg-role="gui-main">
 <params count="2">
  <param name="sby" type="series" optional="true">
<description>variable to sort by</description>
  </param>
  <param name="c" type="scalar" min="0" max="1" default="0.33333">
<description>fraction of middle obs. to omit</description>
  </param>
 </params>
<code>bundle b
list Y = $ylist
string yname = $depvar
loop foreach i Y -q
  series @yname = Y.$i
endloop
list xlist = $xlist
if missing(c)
  c=1/3
endif
aaaaa = exists(sby)
#print aaaaa
if aaaaa == 0
  #series sby = @yname
  #sby = const
  bundle b = gqtest_gui(@yname,xlist,const,c)
else
  uaa = uniq(sby)
  tuaa = typeof(uaa)
  if tuaa == 1 &amp;&amp; uaa == 1
    bundle b = gqtest_gui(@yname,xlist,const,c)
  else
    bundle b = gqtest_gui(@yname,xlist,sby,c)
  endif
endif
#list sby = bys
#if nelem(sby)==0
#  sby = const
#endif
#print sby
#bundle b = gqtest_gui(@yname,xlist,sby,c)

return b
</code>
</gretl-function>
<gretl-function name="gqtest_print" type="void" pkg-role="bundle-print">
 <params count="1">
  <param name="b" type="bundleref"/>
 </params>
<code>matrix ret = b[&quot;ret&quot;]
scalar F = ret[1]
scalar df1 = ret[2]
scalar df2 = ret[3]
scalar pv = ret[4]
scalar pvg = ret[5]
scalar pvl = ret[6]
scalar check1 =  b[&quot;check1&quot;]
scalar check2 =  b[&quot;check2&quot;]
scalar t1 = b[&quot;t1&quot;]
scalar t2 = b[&quot;t2&quot;]
string ay = b[&quot;ay&quot;]
string sss = b[&quot;sss&quot;]
printf &quot;\nGoldfeld - Quandt heteroskedasticity test.\n\n&quot;
if check1
  printf &quot;%d first valid observations (s1^2)\n&quot;, t1
  printf &quot;and %d last valid observations were used (s2^2).\n&quot;, t2
else
  if  check2
    printf &quot;%d observations with %s = 0 (s1^2)\n&quot;, t1, ay
    printf &quot;and %d with %s = 1 were used (s2^2).\n&quot;, t2, ay
  else
    printf &quot;%d observations with the smallest value%s (s1^2)\n&quot;, t1, sss
    printf &quot;and %d with the largest value%s of '%s' were used (s2^2).\n&quot;, t2, sss, ay
  endif
endif
printf &quot;\nTest statistic: s2^2/s1^2 = F(%d,%d) = %.6g\n&quot;, df2, df1, F
printf &quot;H1(s1^2 != s2^2): pvalue = %.4f\n&quot;, pv
printf &quot;H1(s1^2 &lt; s2^2):  pvalue = %.4f\n&quot;, pvg
printf &quot;H1(s1^2 &gt; s2^2):  pvalue = %.4f\n\n&quot;, pvl
</code>
</gretl-function>
<gretl-function name="expweights" type="series">
 <params count="3">
  <param name="y" type="series">
<description>the dependent variable</description>
  </param>
  <param name="xlist" type="list">
<description>independent variables</description>
  </param>
  <param name="zlist" type="list" optional="true">
<description>variance model vars; null: log(xlist)</description>
  </param>
 </params>
<code>if nelem(zlist)==0
  list x0 = xlist-0
  l_x0 = log(x0)
  zlist = const l_x0
else
  if !(inlist(zlist,const))
    zlist = const zlist
  endif
endif
ols y xlist -q
series lnsighat = ln($uhat^2)
ols lnsighat zlist -q
matrix alpha = $coeff
series wt = 1/exp(lincomb(zlist, alpha))
wt = wt/sd(wt)
setinfo wt --description=&quot;exp. weights&quot;
return wt
</code>
</gretl-function>
<gretl-function name="gqtest" type="matrix">
 <params count="4">
  <param name="y" type="series">
<description>the dependent var</description>
  </param>
  <param name="xl" type="list">
<description>independent vars, include 'const', if required</description>
  </param>
  <param name="sby" type="series" optional="true">
<description>variable to sort by</description>
  </param>
  <param name="c" type="scalar" min="0" max="1" default="0.33333">
<description>fraction of middle obs. to omit</description>
  </param>
 </params>
<code># this function doesn't support panel data
if missing(c)
  c=1/3
endif
if (c&lt;=0)||(c&gt;1)
  funcerr &quot;Wrong fraction value&quot;
endif
if $datatype == 3
  funcerr &quot;this function dosn't support panel data&quot;
endif
#print missing(sby)
#if is_null(sby)
#series sby = const
#endif
#aaaaa = exists(argname(sby))
aaaaa = exists(sby)
#print aaaaa
if aaaaa == 0
  series sby = const
endif
uaa = uniq(sby)
#eval argname(sby)
list lysby = sby
nsby = nelem(lysby)
list xxxl = y xl
if nsby&gt;1
  funcerr &quot;Only one variable can be included as the third argument&quot;
elif nsby==1
  series z = lysby[1]
  #series z = sby
  list xxxl = y xl
  uuu =  inlist(xxxl,lysby[1])
  if uuu&gt;0
    smpl xxxl  --no-missing
  else
    xxxl = xxxl sby
    smpl xxxl --no-missing
  endif
  #ay = varname(sby)
  tuaa = typeof(uaa)
  #suaa = &quot;tuaa&quot;
  #print  suaa tuaa
  #ay = uaa == const
  #print ay
  #ay = &quot;foo&quot;
  if tuaa == 1 &amp;&amp; uaa == 1
    ay = &quot;const&quot;
  else
    ay = argname(sby)
  endif
  #print ay
  if c==1
    val = values(lysby[1])
    rval = round(val)
    ddd = (val.=rval)
    nval = nelem(val)
    sval = sum(ddd)
    if (nval==3)&amp;&amp;(sval==3)
      d1=(lysby[1]==val[1])
      d2=(lysby[1]==val[3])
      smpl d1==1 --restrict
    else
      funcerr &quot;Wrong fraction value&quot;
    endif
  else
    if ay == &quot;const&quot;
      T = $nobs
      n1 = round(T*(1-c)/2)
      smpl 1 n1
    elif isdummy(lysby[1])
      smpl lysby[1]==0 --restrict
    else
      scalar cutpoint_lo = quantile(lysby[1], c)
      scalar cutpoint_hi = quantile(lysby[1], (1-c))
      smpl lysby[1]&lt;=cutpoint_lo --restrict
    endif
  endif
else
  if c==1
    funcerr &quot;Wrong fraction value&quot;
  endif
  smpl y xl  --no-missing
  scalar cutpoint_lo = quantile(y, c)
  scalar cutpoint_hi = quantile(y, (1-c))
  smpl y&lt;=cutpoint_lo --restrict
  ay = argname(y)
endif
ols y xl --quiet
scalar df1 = $df
scalar den = $ess / df1
scalar t1 = $T
smpl full
smpl xxxl --no-missing
if nsby==1
  if c==1
    smpl d2==1 --restrict
  else
    if ay == &quot;const&quot;
      T = $nobs
      n2 = T-n1+1
      smpl obs&gt;=n2  --restrict
    elif isdummy(lysby[1])
      smpl lysby[1]==1 --restrict
    else
      smpl lysby[1]&gt;=cutpoint_hi --restrict
    endif
  endif
else
  smpl y&gt;=cutpoint_hi --restrict
endif
ols y xl --quiet
scalar df2 = $df
scalar num = $ess / df2
scalar t2 = $T
scalar F = num/den
ff = den/num
print ff
scalar pv =  pvalue(F,df2,df1,F)
scalar pvg = pv
scalar pvl = 1 - pv
pv = 2*xmin(pv,(1-pv))
smpl full
if c==1
  sss =&quot;&quot;
else
  sss=&quot;s&quot;
endif
printf &quot;\nGoldfeld - Quandt heteroskedasticity test.\n\n&quot;
if ay == &quot;const&quot;
  printf &quot;%d first valid observations (s1^2)\n&quot;, t1
  printf &quot;and %d last valid observations were used (s2^2).\n&quot;, t2
else
  if  (nsby==1)&amp;&amp;(isdummy(lysby[1]))
    printf &quot;%d observations with %s = 0 (s1^2)\n&quot;, t1, ay
    printf &quot;and %d with %s = 1 were used (s2^2).\n&quot;, t2, ay
  else
    printf &quot;%d observations with the smallest value%s (s1^2)\n&quot;, t1, sss
    printf &quot;and %d with the largest value%s of '%s' were used (s2^2).\n&quot;, t2, sss, ay
  endif
endif
printf &quot;\nTest statistic: s2^2/s1^2 = F(%d,%d) = %.6g\n&quot;, df2, df1, F
printf &quot;H1(s1^2 != s2^2): pvalue = %.4f\n&quot;, pv
printf &quot;H1(s1^2 &lt; s2^2):  pvalue = %.4f\n&quot;, pvg
printf &quot;H1(s1^2 &gt; s2^2):  pvalue = %.4f\n\n&quot;, pvl
ret = F~df1~df2~pv~pvg~pvl
return ret
</code>
</gretl-function>
<gretl-function name="gqtest_precheck" type="scalar" private="1" pkg-role="gui-precheck">
<code>scalar err = 0
string cmd = $command
if cmd != &quot;ols&quot;
  print &quot;gqtest: not an ols model&quot;
  err = 1
endif
return err
</code>
</gretl-function>
<gretl-function name="gqtest_gui" type="bundle" private="1">
 <params count="4">
  <param name="y" type="series">
<description>the dependent var</description>
  </param>
  <param name="xl" type="list">
<description>independent vars, include 'const', if required</description>
  </param>
  <param name="sby" type="list" optional="true">
<description>variable to sort by</description>
  </param>
  <param name="c" type="scalar" default="NA">
<description>fraction of middle obs. to omit</description>
  </param>
 </params>
<code>set echo off
set messages off
if missing(c)
  c=1/3
endif
if (c&lt;=0)||(c&gt;1)
  funcerr &quot;Wrong fraction value&quot;
endif
nsby = nelem(sby)
list xxxl = y xl
if nsby&gt;1
  funcerr &quot;Only one variable can be included as the third argument&quot;
elif nsby==1
  series z = sby[1]
  list xxxl = y xl
  uuu =  inlist(xxxl,sby[1])
  if uuu&gt;0
    smpl xxxl  --no-missing
  else
    xxxl = xxxl sby
    smpl xxxl --no-missing
  endif
  ay = varname(sby)
  if c==1
    val = values(sby[1])
    rval = round(val)
    ddd = (val.=rval)
    nval = nelem(val)
    sval = sum(ddd)
    if (nval==3)&amp;&amp;(sval==3)
      d1=(sby[1]==val[1])
      d2=(sby[1]==val[3])
      smpl d1==1 --restrict
    else
      funcerr &quot;Wrong fraction value&quot;
    endif
  else
    if ay == &quot;const&quot;
      T = $nobs
      n1 = round(T*(1-c)/2)
      smpl 1 n1
    elif isdummy(sby[1])
      smpl sby[1]==0 --restrict
    else
      scalar cutpoint_lo = quantile(sby[1], c)
      scalar cutpoint_hi = quantile(sby[1], (1-c))
      smpl sby[1]&lt;=cutpoint_lo --restrict
    endif
  endif
else
  if c==1
    funcerr &quot;Wrong fraction value&quot;
  endif
  smpl y xl  --no-missing
  scalar cutpoint_lo = quantile(y, c)
  scalar cutpoint_hi = quantile(y, (1-c))
  smpl y&lt;=cutpoint_lo --restrict
  ay = argname(y)
endif
m1 &lt;- ols y xl --quiet
scalar df1 = m1.$df
scalar den = m1.$ess / df1
scalar t1 = m1.$T
smpl full
smpl xxxl --no-missing
if nsby==1
  if c==1
    smpl d2==1 --restrict
  else
    if ay == &quot;const&quot;
      T = $nobs
      n2 = T-n1+1
      smpl obs&gt;=n2  --restrict
    elif isdummy(sby[1])
      smpl sby[1]==1 --restrict
    else
      smpl sby[1]&gt;=cutpoint_hi --restrict
    endif
  endif
else
  smpl y&gt;=cutpoint_hi --restrict
endif
m2 &lt;- ols y xl --quiet
scalar df2 = m2.$df
scalar num = m2.$ess / df2
scalar t2 = m2.$T
scalar F = num/den
scalar pv=  pvalue(F,df2,df1,F)
scalar pvg = pv
scalar pvl = 1 - pv
pv = 2*xmin(pv,(1-pv))
smpl full
if c==1
  sss =&quot;&quot;
else
  sss=&quot;s&quot;
endif
bundle b
check1  = (ay == &quot;const&quot;)
print check1
check2  = (nsby==1)&amp;&amp;(isdummy(sby[1]))
print check2
ret = F~df1~df2~pv~pvg~pvl
b[&quot;ret&quot;] = ret
b[&quot;check1&quot;] = check1
b[&quot;check2&quot;]=check2
b[&quot;t1&quot;] = t1
b[&quot;t2&quot;] = t2
b[&quot;ay&quot;] = ay
b[&quot;sss&quot;] = sss
return b
</code>
</gretl-function>
<sample-script>
# sample function call
include gqtest.gfn

###### The test
### different usages
set messages off
set echo off
nulldata 24

# for reproducibility
set seed 147
series y = normal(0,1)
x1 = normal(0,1)
x2 = normal(0,1)
series qwerty = normal(0,1)
list xl =  0 x1 x2
# dummy
d = (obs&gt;14)
# integer variable with 3 distinct values
dd = (obs&lt;6)+2*(obs&gt;16)
set echo on
gqtest(y,xl) # data sorted by y; middle 1/3 omitted 
gqtest(y,xl,qwerty) # data sorted by qwerty; middle 1/3 omitted 
gqtest(y,xl,const) # data unsorted ; middle 1/3 omitted
gqtest(y,xl,d) # 'c' ignored
gqtest(y,xl,dd,1) # obs. with middle values of dd omitted


###### wls-helpers
open data7-2

list xlist = 0 EDUC EXPER AGE GENDER
w = clustweights  (WAGE, xlist,GENDER)
wls w WAGE xlist

w1 = expweights(WAGE, xlist)
wls w1 WAGE xlist

w2 = expweights(WAGE, xlist, xlist)
wls w2 WAGE xlist

# the same

hsk WAGE xlist --no-squares --quiet
eval $coeff
</sample-script>
</gretl-function-package>
</gretl-functions>

