Asset Pricing [4b: Fama MacBeth]

Fama and MacBeth (1973) suggest an alternative procedure for running cross-sectional regressions. The first step of the procedure is identical to the time series regression performed earlier, where excess asset returns were regressed against excess market returns. The estimates of  beta are then fed as inputs into a cross section regression which constitutes the second step of the FMB process. The difference between the two pass regression examined in the previous blog posts and the FMB procedure delineated here is that the latter estimates a cross-sectional regression at each time period while the former estimates a single cross-sectional regression with sample averages.

This post focuses on the application of the FMB methodology to the previous dataset.

[1] Estimate a beta for each of the 351 stocks on the basis of the first 48 months of observations in the data set.

[2] Rank order all of the stock betas, and form 20 portfolios with assets appearing in descending order in terms of their systematic risk.

[3]Estimate a portfolio beta for each of the 20 portfolios by regressing portfolio monthly returns against excess market returns on the basis of the next 60 months worth of observations.

[4] Estimate the expost SML for each month of the next 48 months worth of data.

[5] Estimate the SML accounting for nonlinearity and residual variances for the same time period as step 4.

[6] Repeat steps 1-5 as often as possible across adjacent regression windows. Unfortunately in this case,due to data restrictions, I only have 2 regression windows before running out of data.

[7] Compute the mean value for each of the coefficients estimated in steps 5 and 6.

The code for the FMB procedure follows

#Fama MacBeth
FB <- list()
  alpha.list <- NULL
  beta.list <- NULL
  nl.alpha.list <- NULL
  nl.beta.list <- NULL
  nl.betasq.list <- NULL
  rv.alpha.list <- NULL
  rv.beta.list <- NULL
  rv.betasq.list <- NULL
  rv.res.list <- NULL
  FB$windows1.loc.beg <- c(1,49)
  FB$windows1.loc.end <- c(48,96)
  FB$windows2.loc.beg <- c(49,97)
  FB$windows2.loc.end <- c(108,156)
  FB$windows3.loc.beg <- c(109,157)
  FB$windows3.loc.end <- c(156,204)
  FB$port.beg <- c(seq(1,289,by=18),seq(307,337,by=15))
  FB$port.end <- c(seq(18,306,by=18),seq(321,351,by=15))
  FB$ <- 2
  FB$windows <- list()
        for(i in 1:FB${
         FB$windows[[i]]$alpha.list <- NULL
	 FB$windows[[i]]$beta.list <- NULL
	 FB$windows[[i]]$portfolios <- NULL
	 FB$windows[[i]]$portfolios.mean <- NULL			
         FB$windows[[i]]$portfolio.mat <- NULL
         FB$windows[[i]]$ <- NULL
	for(j in 1:ncol(stock.ret)){
	 FB$windows[[i]]$fit[[j]]$alpha <- coef(FB$windows[[i]]$fit[[j]])[1]
         FB$windows[[i]]$fit[[j]]$beta <- coef(FB$windows[[i]]$fit[[j]])[2]
         FB$windows[[i]]$alpha.list <- rbind(FB$windows[[i]]$alpha.list,FB$windows[[i]]$fit[[j]]$alpha)
	 FB$windows[[i]]$beta.list <- rbind(FB$windows[[i]]$beta.list,FB$windows[[i]]$fit[[j]]$beta)
	 FB$windows[[i]]$fit[[j]]$alpha.p <- summary(FB$windows[[i]]$fit[[j]])[[4]][7]
	 FB$windows[[i]]$fit[[j]]$beta.p <- summary(FB$windows[[i]]$fit[[j]])[[4]][8]
	 FB$windows[[i]]$fit[[j]]$rsquared <- summary(FB$windows[[i]]$fit[[j]])[[9]]
	rownames(FB$windows[[i]]$alpha.list) <- colnames(monthly.ret)
	rownames(FB$windows[[i]]$beta.list) <- colnames(monthly.ret)
	colnames(FB$windows[[i]]$alpha.list) <- 'alphas'
	colnames(FB$windows[[i]]$beta.list) <- 'betas'
	FB$windows[[i]]$matrix <- cbind(FB$windows[[i]]$alpha.list,FB$windows[[i]]$beta.list,t(stock.ret[(FB$windows2.loc.beg[i]):(FB$windows2.loc.end[i]),1:351]))
	FB$windows[[i]]$matrix.sorted <- FB$windows[[i]]$matrix[order(FB$windows[[i]]$matrix[,2],decreasing=TRUE),]
	for(k in 1:20){
	 FB$windows[[i]]$portfolios[[k]] <- FB$windows[[i]]$matrix.sorted[FB$port.beg[k]:FB$port.end[k],]
	 FB$windows[[i]]$portfolios.mean[[k]] <- matrix(colMeans(FB$windows[[i]]$portfolios[[k]][,3:62]),ncol=1)
	 FB$windows[[i]]$portfolio.mat <- cbind(FB$windows[[i]]$portfolio.mat,FB$windows[[i]]$portfolios.mean[[k]])
	colnames(FB$windows[[i]]$portfolio.mat) <- paste('Portfolio ',1:20)
      	FB$windows[[i]]$ <- lm(FB$windows[[i]]$portfolio.mat~exm.ret[FB$windows2.loc.beg[i]:FB$windows2.loc.end[i],1])
        FB$windows[[i]]$port.betas <- matrix(coef(FB$windows[[1]]$[2,],ncol=1)
	FB$windows[[i]]$matrix.sml <- cbind(FB$windows[[i]]$alpha.list,FB$windows[[i]]$beta.list,t(stock.ret[(FB$windows3.loc.beg[i]):(FB$windows3.loc.end[i]),1:351]))
	FB$windows[[i]]$matrix.sorted.sml <- FB$windows[[i]]$matrix.sml[order(FB$windows[[i]]$matrix.sml[,2],decreasing=TRUE),]
	for(k in 1:20){
	 FB$windows[[i]]$portfolios.sml[[k]] <- FB$windows[[i]]$matrix.sorted.sml[FB$port.beg[k]:FB$port.end[k],]
	 FB$windows[[i]]$portfolios.mean.sml[[k]] <- matrix(colMeans(FB$windows[[i]]$portfolios.sml[[k]][,3:50]),ncol=1)
	 FB$windows[[i]]$portfolio.mat.sml <- (cbind(FB$windows[[i]]$portfolio.mat.sml,FB$windows[[i]]$portfolios.mean.sml[[k]]))
        FB$windows[[i]]$ <- lm(FB$windows[[i]]$portfolio.mat.sml~FB$windows[[i]]$port.betas)
	sq <- ((FB$windows[[i]]$port.betas)^2)
	resd <- apply(resid(FB$windows[[i]]$,2,sd)^2
        FB$windows[[i]]$ <- lm(FB$windows[[i]]$portfolio.mat.sml~FB$windows[[i]]$port.betas+sq)
        FB$windows[[i]]$ <- lm(FB$windows[[i]]$portfolio.mat.sml~FB$windows[[i]]$port.betas+sq+resd)
	alpha.list <- rbind(alpha.list,matrix(ncol=1,coef(FB$windows[[i]]$[1,]))
        alpha.mean <- mean(alpha.list)
	beta.list <- rbind(beta.list,matrix(ncol=1,coef(FB$windows[[i]]$[2,]))
        beta.mean <- mean(beta.list)
	nl.alpha.list <- rbind(nl.alpha.list,matrix(ncol=1,coef(FB$windows[[i]]$[1,]))
        nl.alpha.mean <- mean(nl.alpha.list)
	nl.beta.list <- rbind(nl.beta.list,matrix(ncol=1,coef(FB$windows[[i]]$[2,]))
        nl.beta.mean <- mean(nl.beta.list)
	nl.betasq.list <- rbind(nl.betasq.list,matrix(ncol=1,coef(FB$windows[[i]]$[3,]))
        nl.betasq.mean <- mean(nl.betasq.list)
	rv.alpha.list <- rbind(rv.alpha.list,matrix(ncol=1,coef(FB$windows[[i]]$[1,]))
        rv.alpha.mean <- mean(rv.alpha.list)
	rv.beta.list <- rbind(rv.beta.list,matrix(ncol=1,coef(FB$windows[[i]]$[2,]))
        rv.beta.mean <- mean(rv.beta.list)
	rv.betasq.list <- rbind(rv.betasq.list,matrix(ncol=1,coef(FB$windows[[i]]$[3,]))
        rv.betasq.mean <- mean(rv.betasq.list)
        rv.res.list <- rbind(rv.res.list,matrix(ncol=1,coef(FB$windows[[i]]$[4,]))
        rv.res.mean <- mean(rv.res.list)

Clearly the BJS and FMB procedures have been hardcoded for the current example rather than generalised for any arbitrary dataset.

To visualise some of the results

#Visualise FB
tab1 tab2 annot c1 c2 tab
port.names for(k in 1:17){
  port.names   port.names }

for(k in 18:20){
  port.names  port.names }

tab.port rn tab.port annot.port

TableMaker(row.h=c(1),apply(tab.port,2,rev),annot.port,strip=F,strip.col=c('red','green'),col.cut=0,alpha=0.6,border.col='lightgrey',text.col='black',header.bcol='gold',header.tcol='black',title='Portfolios in window 1')

colours plot(xlab='months',ylab='portfolio mean returns',main='Mean portfolio returns for next 5 years',cex.main=0.85,cex.lab=0.8,cex.axis=0.8,as.ts(FB$windows[[1]]$portfolios.mean[[1]]),col=colours[1])
for(i in 2:20){

annot r1 tab.com1 tab.com2 tab.com2
TableMaker(row.h=c(1),apply(tab.com1,2,rev),annot,strip=F,strip.col=c('red','green'),col.cut=0,alpha=0.6,border.col='white',text.col='black',header.bcol='light blue',header.tcol='black',title='Portfolios in window 1')

TableMaker(row.h=c(1),apply(tab.com2,2,rev),annot,strip=F,strip.col=c('red','green'),col.cut=0,alpha=0.6,border.col='white',text.col='black',header.bcol='light blue',header.tcol='black',title='Portfolios in window 1')

To get a sense of how the 20 beta-sorted portfolios look like, i have plotted their composition in the following table. Rows signify portfolios, with the smaller numbered portfolios corresponding to collections of assets with higher betas and larger numbered portfolios corresponding to collections of assets with lower betas. Since we have 351 assets in our dataset, we cannot evenly divide them into 20 equally sized portfolios. As a consequence, the first 17 portfolios have 18 assets while the last three portfolios have 15 assets in order to,quite arbitrarily, cover the total of 351 assets. The data plotted here is for the first regression window,covering the first 48 months of observations. The next and final regression window would cover the next 48 months of data (not shown here). The line chart at the bottom of the plot window tracks the average return of each of the 20 portfolios over the next 60 months in the dataset. This corresponds to step 3 of the FMB process outlined above.


To get a sense of the coefficient estimates from steps 4-6, the following table (splitted into two plots due to plotting space problems) summarises estimated parameters for 3 models across two regression windows that total 96 months of data (48 months of observations per window).


The last rows of the table reflect column averages and associated p-values, which taken together should inform CAPM consistency. The only time we can reject the null hypothesis is with respect to residual variances in the last model such that for all other figures, statistical insignificance is to be inferred. Alphas, being statistically indistinguishable from 0 at traditional levels of significance is a point towards the CAPM.Betas,being insignificant do not help in explaining portfolio returns,constitute a departure from theory . Nonlinearity does not seem to be an issue but residual variance appears to matter greatly.On balance the CAPM does not seem to hold in terms of its implications for beta and residual variances but appears somewhat sensible for alphas and nonlinearity.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: