Analysis of Financial Time Series in Stan - Chapter 9 - Principal Component Analysis and Factor Models

Chapter_9.knit

In this series we are trying to reproduce the models and examples listed in the book “Analysis of Financial Time Series, 3rd Edition”, by Ruey S. Tsay, using Stan https://mc-stan.org/ and the package RStan https://cran.r-project.org/web/packages/rstan/index.html. The main repository for the presented models and data can be found at https://github.com/marcomarconi/AFTS_with_Stan.

{
  require(tidyverse)
  require(rstan)
  rstan_options(auto_write = TRUE)
  rstan_options(javascript = FALSE)
  theme_set(theme_classic(base_size = 24))
}

9.2 MACROECONOMETRIC FACTOR MODELS

We are going to consider a single-factor market model:

\[ r_{it} = \alpha_i + \beta_i r_{mt} + e_{it}, \quad i=i,...k, \quad t=1,...,T,\] where \(r\) it is the excess return of the ith asset, \(r_{mt}\) is the excess return of the market, and \(\beta_i\) is the well-known \(\beta\) for stock returns. We consider the percentage monthly returns of 13 stocks from January 1990 to December 2003 and use the return of the S&P 500 index as the market return.
The single-factor market model implementation in Stan is straightforward:

data {
  int<lower=0> T;
  int<lower=0> K;
  matrix[T,K] r;
  vector[T] m;
}
parameters {
  vector[K]  alpha;
  vector[K]  beta;
  corr_matrix[K] Omega;
  vector<lower=0>[K] tau;
}
transformed parameters{
  matrix[K,K] Sigma;
  Sigma = quad_form_diag(Omega, tau);
}
model {
  tau ~ exponential(1);
  Omega ~ lkj_corr(2);
  alpha ~ normal(0, 10);
  beta ~ normal(0, 1);
  for(t in 1:T)
    r[t,] ~ multi_normal(m[t]*beta + alpha, Sigma);
}

Let’s fit the data to the model:

m <- read.table("data/m-fac9003.txt", header=T)
SFM <- stan_model("models/Chapter_9/SFM.stan")
fit_SFM <- sampling(SFM, data = list(T=nrow(m), K=ncol(m)-1, r=m[,1:(ncol(m)-1)], m=m[,ncol(m)]), chains = 4, cores = 4, iter=1000)

We can observe the bayesian estimation for the betas, and plot them with the implied 90% compatible intervals:

pars <- rstan::extract(fit_SFM)
cbind(beta=colMeans(pars$beta), sd=colMeans(pars$tau))
##            beta        sd
##  [1,] 1.2420126  7.636117
##  [2,] 1.4975939  7.876375
##  [3,] 0.8992488  7.683152
##  [4,] 1.1755270  8.191537
##  [5,] 0.7708189  8.921869
##  [6,] 1.0042878  8.108413
##  [7,] 1.5667987  9.436320
##  [8,] 0.5422418  6.101420
##  [9,] 1.1043800  6.201762
## [10,] 0.7457985  6.625805
## [11,] 0.4650995  6.516062
## [12,] 0.6860196  7.207216
## [13,] 1.7113828 11.412031
q <- t(apply(pars$beta, 2, function(x) quantile(x,probs=c(0.05,0.5,0.95))))
rownames(q) <- colnames(m[,1:(ncol(m)-1)])
ggplot(as.data.frame(q)) + geom_bar(aes( x=rownames(q), y=`50%`),  stat = "identity") + geom_errorbar(aes(rownames(q), ymin=`5%`, ymax=`95%`, width=0.1)) + xlab("")+ ylab("beta")

One assumption of this model is that the special factor are not correlated among the stocks, but we can see that some high correlations still exist:

library(corrplot)
rho <- apply(pars$Omega, c(2,3), mean)
colnames(rho) <- rownames(rho) <- colnames(m[,1:(ncol(m)-1)])
corrplot(rho, tl.cex = 2,  cl.cex = 1.5)

9.3 FUNDAMENTAL FACTOR MODELS

Fundamental factor models use observable asset specific fundamentals such as industrial classification, market capitalization, book value, and style classification (growth or value) to construct common factors that explain the excess returns. In this type of factor models the betas are treated as observed values (usually as 0 or 1 indicators to specify to which class the asset belongs) and tries to estimate the factors.

9.3.1 BARRA Factor Model

The BARRA model is similar to the previous market model but the returns are first mean corrected, and the betas are provided as 0/1 indicators.
The BARRA model can be implemented in Stan as follows:

data {
  int<lower=0> N;
  int<lower=0> K;
  int<lower=0> F;
  matrix[N,K] y;
  matrix[K,F] betas;
}


parameters {
  vector<lower=0>[K] sigma;
  matrix[N,F] eff;
}

model {
  sigma ~ exponential(1);
  for(t in 1:N) {
    vector[K] mu;  
    eff[t,] ~ normal(0,1);
    for(k in 1:K){
      mu[k] = 0;
      for(f in 1:F)
        mu[k] += betas[k,f] * eff[t,f];
    }
    y[t,] ~ normal(mu, sigma);    
  }
}

For example we consider 10 stocks returns (mean-corrected) and classify them depending on the industrial sector, finance, technology or other:

da <- read.table("data//m-barra-9003.txt", header=T)
rm = matrix(apply(da,2,mean),1)
rtn = da - matrix(1,168,1)%*%rm # mean-correct the returns
finance <- c(rep(1,4),rep(0,6))
technology <- c(rep(0,4),rep(1,3),rep(0,3))
other <- c(rep(0,7),rep(1,3))
ind.dum <- cbind(Finance=finance,Technology=technology,Other=other)
print(ind.dum)
##       Finance Technology Other
##  [1,]       1          0     0
##  [2,]       1          0     0
##  [3,]       1          0     0
##  [4,]       1          0     0
##  [5,]       0          1     0
##  [6,]       0          1     0
##  [7,]       0          1     0
##  [8,]       0          0     1
##  [9,]       0          0     1
## [10,]       0          0     1

We can fit the BARRA model to this data:

BARRA <- stan_model("models/Chapter_9/BARRA.stan")
fit_BARRA <- sampling(BARRA,  data=list(N = nrow(rtn), K=ncol(rtn), y = rtn, F=3, betas=ind.dum) , chains=4, cores=4)

We can plot the estimated factor realizations of BARRA industrial factor model for the three industrial sectors:

9.5 STATISTICAL FACTOR ANALYSIS

We are not going to see factor analysis models but we refer the reader to the Stan manual page https://mc-stan.org/docs/2_27/stan-users-guide/loading-matrix-for-factor-analysis.html and the implementation proposed by Rick Farouni https://rfarouni.github.io/assets/projects/BayesianFactorAnalysis/BayesianFactorAnalysis.html.

Comments