Skip to content
All library documents

How the GRS Test Responds to Rescaling a Market Factor

Article Quant Q&A · Author: Richard Hardy

Summary

The document describes simulations using the Gibbons–Ross–Shanken test to evaluate a CAPM-style model across multiple test portfolios. With returns generated under the model, the test does not reject the null; adding nonzero portfolio alphas leads to rejection. Replacing the market factor with an unrelated random variable also produces rejection in the reported simulations, while the author notes that detecting this misspecification required a sufficiently large sample.

The central puzzle is that multiplying the true market excess return by a constant still yields p-values resembling those from the correctly specified factor. The simulation therefore illustrates that factor scale alone does not alter the test’s outcome in this setup. This is an empirical investigation built from simulated returns and an R implementation, not a general proof. Its conclusions are limited to the stated data-generating design and test configuration; it does not explain the mathematical invariance behind the result.

Key ideas

  • The GRS test does not reject the simulated CAPM when the true market factor is used.
  • Adding nonzero portfolio alphas leads the test to reject the model in the reported simulations.
  • An unrelated factor is rejected in the setup when the sample provides sufficient power.
  • Rescaling the true factor leaves the reported p-value behavior similar to the correctly scaled case.
  • The simulation demonstrates an outcome but does not establish a general proof or explain its mathematical cause.

Tags

Full text
# GRS test does not reject a scalar multiple of the market factor


# GRS test does not reject a scalar multiple of the market factor












I have been playing with the GRS test (see my R script below) in relation to Why not use a time series regression when the factor is not a return?. I generated a $10,000\times 26$ matrix of returns on 25 "portfolios" and the market portfolio according to the CAPM. I used the function `GRS.test::GRS.test` in R to test the CAPM, and I could not reject the $H_0$. Then I added idiosyncratic $\alpha$s to each "portfolio", tested the CAPM again and now could easily reject the $H_0$. So far so good.

Then I generated data according to the CAPM again and ran the GRS test with the market's excess return replaced by an unrelated random variable (a random factor). The test easily rejected $H_0$. For completeness, I added idiosyncratic $\alpha$s to each "portfolio" and tested the CAPM again with the random factor. As in the case with the true factor, I could again easily reject the $H_0$. So far so good.

Then I generated data according to the CAPM again and ran the GRS test with the market's excess return replaced by a scalar multiple of itself with a scaling factor $c=100$. To my surprise, the test could not reject the $H_0$! The $p$-value distribution over the simulation runs was close to Uniform[0,1], as we would expect when testing the true factor. For completeness, I added idiosyncratic $\alpha$s to each "portfolio" and tested the CAPM again with the random factor. As in the case with the true factor, I could again easily reject the $H_0$.

Question: What is going on? Should the GRS test not reject a model with a scalar multiple of the true factor?

(You can run the script online and see the results for yourself at https://rdrr.io/snippets/. Just paste the script there and click "Run". You may deleted the # symbol before the commented lines to vary between the specifications of $\alpha$s and the factor that is supplied to the GRS test.)

```
library(MASS)
library(GRS.test)
data("data")  # Fama-French data: market's excess return and 25 portfolios (5x5, sorted on SMB and HML) 
data=data/100 # because original data was in percent

M=1e2 # number of simulation runs
T=1e4 # sample size (length of time series)
N=25  # number of test assets/portfolios
#c=1   # scaling factor
c=100 # scaling factor

Sigma=cov(data[,c(8:32,2)])    # empirical covariance matrix; the last column is the market, the other 25 columns are the portfolios
alpha =rep(0,N+1)              # Jensen's alpha is set to zero for all assets
#set.seed(-1); alpha=runif(n=N+1,min=-0.01,max=0.01) # Jensen's alpha, in this case nonzero for all assets
beta_m=rep(NA,N+1); for(i in 1:(N+1)) beta_m[i]=Sigma[i,N+1]/Sigma[N+1,N+1] # actual betas from Fama-French data
mu_mte=rep(mean(data[,2]),T)   # expected value of market excess return, in this case time-constant and in line with Fama-French data

results=list(); pvals=rep(NA,M)
for(j in 1:M){
 # Generate a matrix of returns according to a 1 factor model with a scaling constant c for the factor:
 set.seed(j); r_matrix=mvrnorm(n=T, mu=alpha+beta_m*mean(mu_mte), Sigma=Sigma)
 f_matrix=cbind(r_matrix[,N+1])*c               # factor return matrix for the function GRS.test()
 #set.seed(-j); f_matrix=cbind(rnorm(T,mean=5)) # random, unrelated factor returns
 results[[j]]=GRS.test(r_matrix[,1:N],f_matrix) # GRS test
 pvals[j]=results[[j]]$GRS.pval
}

# Plot p-values of all simulation runs of the GRS test
plot(sort(pvals),xlim=c(0,M),ylim=c(0,1)); abline(a=0,b=1/M,lwd=2,col="red")
```

P.S. At first, there was also a puzzle about not being able to reject a random factor, but that was solved by increasing the sample size and thereby the power of the test. The related question and answer can be found here.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.