I am currently testing whether three proprietary factors - Valuation, Size and Momentum - explain cross-sectional returns. A sample of 3000 securities was tested using Fama-MacBeth two-pass regressions over the period 1988-2013. In order to mitigate any thorny estimation problems due to time-varying regression slopes, I have used 50 portfolios sorted on size and book/market (25), and size and momentum (25), as test assets (LHS variables).
The unconditional regressions resulted in insignificant premia for the three factors. Since these factors might behave differently in disparate market conditions, I have also performed conditional regressions based on regimes. The hypothesis was that Valuation should be highly significant in a Bear market, while Momentum should have a statistically significant premia in Bull markets. However, the results showed insignificant premia for all factors across all market regimes.
I am a bit surprised by the results, and made me question the actual testing methodology.
For a sanity check for the methodology, I have decided to test the Fama-French factors HML and SMB using the same sample period used in the Fama-French(1993) paper. The data was downloaded from Kenneth French website. However, even in this case, the Fama-MacBeth procedure was unable to discover any significant premia for either HML or SMB factors.
Would anyone have any thoughts on this issue?
Here is the code for the Fama-MacBeth procedure using 50 portfolios as test assets. The 50 sorted portfolios, as well as the factor-mimicking portfolios - VAL, SIZE and MOM - are constructed using a sample of 3000 securities.
- In the first pass of Fama-MacBeth (time-series regression), betas are estimated using rolling windows of 60 months each. Betas are updated monthly.
- Securities are sorted at the end of June each year, and test portfolios' returns are computed from July to June of the next year.
The returns on the factor mimicking portfolios (VAL, SIZE and MOM) are computed as the top-bottom spread of 5 book-to-market quantiles, 5 market-cap quantiles, and 5 momentum quantiles respectively.
In the second-pass of Fama-MacBeth, the previously estimated betas of portfolios are used as independent variables in monthly-cross-sectional regressions, on a subsequent sample period. The premiums for VAL, SIZE and MOM are estimated monthly. When all the monthly cross-sectional regressions have been done, the mean of the time-series of premiums is estimated for each factor. This is all performed by the function pmg(). The average premiums are then tested for statistically significant difference from zero using the t-statistic.
- The conditional regressions based on market regimes is not included in the code. The reason being is that the regime definition is also proprietary. All you need to know is that when the cross-sectional regressions are evaluated, the time-series of premiums for each factors are averaged on a per-regime basis: in other words, you average the premiums for the periods of bull-markets, and periods of bear-markets, ... separately. The bull and bear, and .. premiums for each factor are tested using the t-statistic.
Please be mindful that this is only a representative (modified) snapshot of the code.
##########################################################################
### Time-Series Regressions ###
##########################################################################
portfolios = 50 ## Test assets
num.factors = 3 ## VAL, SIZE and MOM
rows = nrow(ret.ff.zoo) - 60 + 1 ### Number of time windows
beta.mat <- matrix(nc = num.factors + 1, nr = portfolios*rows)
portfolio.id = matrix(nc = 1, nr = portfolios*rows)
d = 1
for(i in seq(1:portfolios)) {
######### Dataset (merging test assets' returns and returns of factor-mimicking portfolios
data = merge(return = ret.zoo[,i], VAL = df$VAL, SIZE = df$SIZE, MOM = df$MOM, all = c(TRUE, rep("FALSE", num.factors))) ## "df" is the dataframe (zoo object) containing the returns of VAL, SIZE and MOM only
############ Coefficients of regression
reg = function (z) coef(lm(return ~., data = as.data.frame(z)))
beta = rollapply(data, width = 60, FUN = reg, by.column = FALSE, align = "right")
beta.mat[d:(d+rows-1),] = beta
portfolio.id[d:(d+rows-1),] = i
d = d + rows
}
beta.df = data.frame(port = portfolio.id, date = index(beta), beta.mat)
colnames(beta.df) <- c("portfolio", "date", "intercept", colnames(beta)[-1])
##########################################################################
### Cross-Sectional Regressions ###
##########################################################################
## requires library(plm)
return <- matrix(ret.zoo[which(index(ret.zoo) >= beta.df$date[1]),], ncol = 1)
dataset <- cbind(beta.df, return)
fpmg <- pmg(return ~ VAL + SIZE + MOM, data = dataset, index = c("date", "portfolio"), na.action = na.omit)
summary(fpmg)
Thank you,