Sunday 23 October 2011

Principal component analysis : Use extended to Financial economics : Part 2

My previous post talked about how we can employ PCA on the data for multiple stock returns to reduce the number of variables in explaining the variance of the underlying data. But the idea was greeted with skepticism by many. A caveat to the application of PCA was that the meaning or the intuition behind the variable is lost in the computation of components, but since I was concerned with only explaining the variance in the underlying data it worked as a powerful method. This method was also adopted by Dr. Oyama in his research paper.

I came across this interesting research paper published in one of the most coveted journals, (International Journal on Finance and Economics) which has used the PCA on the macroeconomic variables. So relating it to my previous post and the question of investigating the factor affecting stock returns, what they do is that they take individual stocks and regresses it on the PCA of macroeconomic variables. At the first glance this would appear an inappropriate use of the tool, however the question that it intends to ask is also very different. There has been or infact still is this great battle between the Capital Asset Pricing (CAPM) school of thought and Arbitrage Pricing Theory (APT) school of thought. What the essential difference between these two schools is that the CAPM says that the returns to a stock are sensitive to only one factor, i.e the market rate of returns (single factor model) which captures the effect of all the various factors, however the APT guys scream that it depends on a number of factors and market rate of return would be just one of them. So in this battle to prove their point the APT folks take stock returns as a dependent variable and as independent variables they use the PCA of many macroeconomic variables. They do this essentially so that they can prove that there are more than one factors playing a significant part in the explaining the returns on a stock, they do not care whether the economic intuition is lost in the process on one-upmanship.

Well anything is fair in war, but I think this path taken by APT guys of proving their point is a fair point. The variables that are thrown into the PCA are chosen with an economic intuition in mind, so its not correct to say this entire methodology is flawed on the pretext that the PCA of these macroeconomic variables have no economics intuition. If one really digs into the intuition behind PCA as explained in this article one can visualize what the PCA of macroeconomics variables would be representing, the principal underlying components that give rise to such a macroeconomic series (signals). This is an unconventional way of doing an econometric study, as in this is more of a qualitative than a quantitative study. I cannot make sense of a statement that 1 unit increase in my first PCA results in "x" unit increase in returns, this is an absurd statement, but nevertheless the methodology of answering the underlying question is not absurd.

The methodology for calculating the PCA for macroeconomics is same as what was used in the previous post. We can have a number of macroeconomic variables, however, I have done this demonstration with only 2 variables change in Mumbai inter-bank offer rates (MIBOR) rates and change in INR/USD exchange rates.

#### Calculating the PCA of macroeconomic variables ####


# Reading the relevant files
mibor <- read.csv("MIBOR.csv", na.strings="#N/A")
exchange <- read.csv("Exchange_rates.csv", na.strings="#N/A")


# Making sure that there are no missing values in the data, the missing values are replaced by linear interpolation
mibor[, 2] <- approx(as.Date(mibor$Dates, '%d-%b-%y'), mibor[ ,2], as.Date(mibor$Dates, '%d-%b-%y'))$y   # approx() returns the interpolated values in column 'y'


exchange[, 2] <- approx(as.Date(exchange$Year,'%d-%b-%y'), exchange[ ,2], as.Date(exchange$Year, '%d-%b-%y'))$y  # Similarly for exchange rates


# Now we will have to compute the change in MIBOR and exchange rates:
for(k in 2:nrow(mibor))
{
  mibor$Change1[k] <- ((mibor$MIBOR[k] - mibor$MIBOR[k-1])/mibor$MIBOR[k-1])*100
}


for(j in 2:nrow(exchange))
{
exchange$Change[j] <- ((exchange$Exchange.rates[j] - exchange$Exchange.rates[j-1])/exchange$Exchange.rates[j-1])*100
}


# Creating matrix of the data
macro <- as.data.frame(rep(0, 2498))   


macro$ex <- exchange$Change
macro$rate <- mibor$Change1


macro.mat <- as.matrix(macro, nrow = 2498 , ncol = 2)

# Calculating the principal components 
prin.macro <- princomp(macro.mat)

barplot(prin.macro$sdev[1:2]/prin.macro$sdev[1])  # bar plot of the ratio is the standard deviation of the PC's with the standard deviation of the 1st PC, this can help us decide which PC to be used by simple eyeballing the plot.

# Extract the 1st PC in a variable
load1 <- prin.macro$loadings[,1]   # get the loadings of the 1st PC into 'load1'

pr.ma <- macro.mat %*% load1 # matrix multiply the loading with the original data to get the PC

pr1 <- as.numeric(pr.ma) # And 'pr1' has your first principal component. 

Now if you have read this article that I shared earlier, the first component gives me the principal underlying factor that gives rise to the series (signals) that I observe.

Caveats and cautions:

Before I am bombarded with question about the relevance of this methodology in this particular problem let me confess that in the above particular exercise its not the best idea to use PCA. One should use PCA only if one has many macroeconomic variables like M1, M3, CPI, IIP, WPI, etc and there is high correlation between them. I have done the above only for illustrative purposes (since I am not employing PCA on macro-variables in my project). 

Assuming I had other macro-variables in the calculation of my PCA above, I could use them as an independent variable and regress them on the stock specific returns to understand  if there are more than one factors that come out to be significant in this regression. What this would essentially mean is that are there more than one factors explaining the stock returns. For the finance students, this is the classic argument between the Capital Asset Pricing (CAPM) guys and the Arbitrage Pricing Theory (APT) guys. 

If in the regression of the PC's of macroeconomic variables on the returns we find that more than one factors are significant then we would have found evidence for or against one of the above theories.

Limitations in the above method:
  1. In the above exercise I have just taken 2 variables merely for illustration, I would have to include more variables if I really intent to find evidences against the CAPM.
  2. Again the caveat of interpretation applies. Its difficult to interpret the PCA on macrovariables

My take:

Despite of the above caveats I think PCA does a good job of giving us a good empirical way to answer the question of whether CAPM or APT is a superior asset pricing theory. The main idea behind these asset pricing theories is to see what factors need to be incorporated to compute the asset specific risk premiums, so on that front, its not difficult to see what people still stick to CAPM, as its a lot simple and easier to work with. APT on the other hand makes a bold assertion of multiple factors governing the returns but it has always found it difficult to list out these factors. Well in most cases you would be able to conclude that the returns can be modeled best using a multi-factor model, but whats interesting to ask is how much additional explanation is offered by factors other than the 1st one. If my multi factor model offers just a marginally higher adjusted-R-squared, is it reasonable for you to complicate your model is the question?

If it were only to prove this empirically why would you not choose the multi-factor model? The idea of modelling returns is to identify the factors that you need to take into account while computing the risk premiums, and if your factors do not have any economic intuition how can you assign risk premia looking at your principal component, that's the big question. But I would hate to impose my take here, further discussion is welcome.

P.S : In case you wish to replicate the above exercise you can find the data here, exchange rates, MIBOR

4 comments:

  1. Hello,
    Thank you for the interesting article.
    I want to replicate the exercise, but the links for exchange rates and MIBOR are the same.
    Please can you fix this.
    Thanks,
    Andre

    ReplyDelete
  2. My apologies Andre, I have updated the link.

    Thanks for pointing it out.

    ReplyDelete
  3. I get funny results when I run the approx() function for exchange rates. Specifically, the original data has

    Year Exchange.rates Change
    1 01-Jan-01 46.66 -0.192884698
    2 02-Jan-01 46.69 0.064294899
    3 03-Jan-01 46.7 0.021417862
    4 04-Jan-01 46.74 0.085653105
    5 05-Jan-01 46.74 0
    6 08-Jan-01 46.69 -0.106974754
    7 09-Jan-01 46.66 -0.064253587
    8 10-Jan-01 46.61 -0.107158165
    9 11-Jan-01 46.63 0.042909247
    10 12-Jan-01 46.61 -0.042890843
    11 15-Jan-01 46.53 -0.171636988


    and after running your code I get


    Year Exchange.rates Change
    1 01-Jan-01 506 -0.192884698
    2 02-Jan-01 509 0.064294899
    3 03-Jan-01 510 0.021417862
    4 04-Jan-01 514 0.085653105
    5 05-Jan-01 514 0
    6 08-Jan-01 509 -0.106974754
    7 09-Jan-01 506 -0.064253587
    8 10-Jan-01 501 -0.107158165
    9 11-Jan-01 503 0.042909247
    10 12-Jan-01 501 -0.042890843
    11 15-Jan-01 493 -0.171636988


    Any idea what is happening to the Exchange.rate variable?

    ReplyDelete
  4. Madhav,

    The problem, as I see it, is because you have not specified how to read the "#N/A"'s in the data.(Note its "#N/A" and not just NA, which is spoiling the numbers)

    See if you dont specify in the beginning that the #N/A's are not to be treated as strings, R would assign weird numeric values to these #N/A's (which will basically screw up the calculations. For eg:

    > exchange <- read.csv("Exchange_rates.csv")
    > class(exchange$Exchange.rates)
    [1] "factor"

    > exchange <- read.csv("Exchange_rates.csv", na.strings="#N/A")
    > class(exchange$Exchange.rates)
    [1] "numeric"

    So you see that the (na.strings="#N/A") makes sure that
    it doesn't treat the #N/A's as strings. I think this should solve your problem.

    ReplyDelete