9 abr 2022

Aplicaciones de la función Rollaplay (de R) en la econometría financiera

 1.       Lógica detrás de la función

La función crea una ventana móvil sobre la cual va calculando algo (mediante una función) y posteriormente podemos obtener información histórica sobre ese cálculo. Imaginemos que todos los días calculáramos la varianza del precio del arroz, si lo hacemos todos los días y vamos guardando este precio, terminaremos teniendo una serie promedio de precios del arroz. Ahora, si tenemos información de 10 años necesitamos repetir esta operación para cada día dentro de la muestra de datos, es aquí donde surge la importancia de esta función.  

Supongamos, tenemos el vector x=(x1,x2,x3,x4,x5), podemos obtener un promedio móvil usando una ventada de tres días. Note que la ventana de datos móvil que va utilizando el programa va dejando una observación detrás y tomando la observación siguiente (en caso de solo ir tomando una observación adicional, partiendo siempre desde la primera observación, se llaman datos recursivos). Los datos vacios pueden omitirse o quedar como NA.

x

Datos móvil

X1

 

X2

 

X3

x1,x2,x3

X4

x2,x3,x4

X5

x3,x4,x5

X6

x4,x5,x6

En R, este procedimiento se puede realizar utilizando la función rollapply, la misma segmenta las observaciones de determinados grupos de tamaño (width = 3), y posteriormente realiza el cálculo indicado en la función que se le brinda de argumento a la función.

library(dplyr)
library(lubridate)
library(zoo)
 
x_ej <- zoo(c(3,4,2,8,9,3))
 
rollapply(data = x_ej, width = 3, FUN = mean)
       2        3        4        5
3.000000 4.666667 6.333333 6.666667

También podemos crear nuestras propias funciones para alimentar los procedimientos dentro de la función rollapply:

mean2 = function(x){
  sum(x)/length(x)
}
 
rollapply(data = x_ej, width = 3, FUN = mean2)
   2        3        4        5
3.000000 4.666667 6.333333 6.666667

Alinear los datos arriba o debajo del vector de datos sobre el cual estamos aplicando la función, además de determinar cuál valor queremos sustituir dentro de las observaciones que quedan sin datos:

media<-rollapply(data = x_ej, width = 3, FUN = mean2, align = "right", fill=NA)
media2<-rollapply(data = x_ej, width = 3, FUN = mean2, align = "left", fill=NA)
 
tabla1 <- cbind(x_ej,media,media2)
tabla1
 
  x_ej    media   media2
1    3       NA 3.000000
2    4       NA 4.666667
3    2 3.000000 6.333333
4    8 4.666667 6.666667
5    9 6.333333       NA
6    3 6.666667       NA

También podemos realizar el cálculo a partir de x grupos no superpuesto. En otras palabras, calcular nuestro promedio cada x cantidad de observaciones utilizando el argumento by dentro de la función.

x
Datos móvil
X1
.
X2
.
X3
x1,x2,x3
X4
.
X5
.
X6
x4,x5,x6

media_by <- rollapply(data = x_ej, width = 3, FUN = mean2, align = "right", fill=NA, by=3)
 
tabla1 <- cbind(tabla1,media_by)
tabla1
x_ej    media   media2 media_by
1    3       NA 3.000000       NA
2    4       NA 4.666667       NA
3    2 3.000000 6.333333 3.000000
4    8 4.666667 6.666667       NA
5    9 6.333333       NA       NA
6    3 6.666667       NA 6.666667

Los valores NA también se pueden completar con información parcial, en este caso se usarán las ventadas disponibles para la estimación. Esto solo es recomendable en algunos procedimientos estadísticos, porque otros están influenciados en la cantidad de observaciones usadas. 

x

Datos móvil

X1

x1

X2

x1,x2

X3

x1,x2,x3

X4

x2,x3,x4

X5

x3,x4,x5

X6

x4,x5,x6

media_par <- rollapply(data = x_ej, width = 3, FUN = mean, fill=NA, align = "right", partial = T)
 
tabla1 <- cbind(tabla1,media_par)
tabla1
x_ej    media   media2 media_by media_par
1    3       NA 3.000000       NA  3.000000
2    4       NA 4.666667       NA  3.500000
3    2 3.000000 6.333333 3.000000  3.000000
4    8 4.666667 6.666667       NA  4.666667
5    9 6.333333       NA       NA  6.333333
6    3 6.666667       NA 6.666667  6.666667

También se puede modificar el argumento width para modificar el tamaño de la ventana a voluntad y generar ventanas recursivas, es decir, donde el tamaño de la ventana vaya creciendo con cada estimación.

x

Datos móvil

X1

x1

X2

x1,x2

X3

x1,x2,x3

X4

x1,x2,x3, x4

X5

x1,x2,x3,x4,x5

X6

x1,x2,x3,x4,x5,x6

obs<-length(x_ej)
mean_re <- rollapply(data = x_ej, width = 1:obs, FUN = mean, align = "right")
 
tabla1 <- cbind(tabla1,mean_re)
tabla1
 
x_ej    media   media2 media_by media_par  mean_re
1    3       NA 3.000000       NA  3.000000 3.000000
2    4       NA 4.666667       NA  3.500000 3.500000
3    2 3.000000 6.333333 3.000000  3.000000 3.000000
4    8 4.666667 6.666667       NA  4.666667 4.250000
5    9 6.333333       NA       NA  6.333333 5.200000
6    3 6.666667       NA 6.666667  6.666667 4.833333

2.       Aplicaciones de la función rollapply a la econometría financiera

2.1. Ventana de volatilidad (ventana móvil)

Usamos la data EuStockMarkets para estos ejemplos. El primero calcula las tasas de variación para estas series (recuerde siempre trabajar con series estacionarias) para posteriormente estimar la volatilidad de la misma en una ventana de datos de 100 días. Es un proceso muy utilizado en la gestión del riesgo para analizar la volatilidad condicional.

plot(EuStockMarkets)
 
data <- EuStockMarkets  %>%
  data.frame() %>%
  mutate(across(is.numeric, ~((./dplyr::lag(.)-1)*100))) %>%
  na.omit()
 
r_data0 <- data[,"DAX"]
 
vol_t <- rollapply(r_data0, width=100, FUN=sd)
plot(vol_t, type="l")

2.2. Ventana de volatilidad (ventana recursiva)

 ***

2.3. Calcular el VaR histórico de un activo

Aquí también podemos obtener la evolución del VaR de determinada serie financiera. Se muestra además la flexibilidad de la función al permitirnos colocar dos argumentos a la vez.

rollapply(data, width, FUN, …, )

var_dax <- rollapply(r_data0, 100, quantile, probs = 0.01, align = "right")
 
plot(r_data0, type="l")
lines(var_dax)

#backtesting
mean(r_data0<var_dax)
[1] 0.01667563

2.4. Correlación histórica entre activos

La función no solo permite incluir más de un argumento de una función, sino que facilita el trabajo con más de una variable. Aquí se muestra como trabajar con varias columnas. Este es necesario cuando quisiéramos ver cuestiones como la evolución histórica de la correlación entre dos series y como vimos anteriormente, cuando necesitamos incluir funciones propias para reservar los datos que vamos obteniendo. Esta función la podemos crear fuera o colocar dentro de la misma función.

r_data <- data[,c(1,2)]
 
corr_t <- rollapply(r_data, width=100, function(x) cor(x[,1],x[,2]), by.column=FALSE)
plot(corr_t, type="l")

 

2.5. Obtener el beta histórico de una cartera

 Sumamente útil para descomponer el riesgo de un activo e identificar el componente sistémico de su volatilidad, además de identificar fuentes de riesgo y la sensibilidad de la serie a factores puntuales de riesgo. El procedimiento consiste en guardar el coeficiente de regresión de un modelo factorial sencillo, pero note que modificando la función podemos obtener modelos factoriales con mayor cantidad de factores de riesgo.  

beta_sis = function(x){
  lm(x[,2] ~ x[,1])[[1]][[2]]
}
 
Beta <- rollapply(r_data, width=100, by.column = F,  beta_sis)
plot(Beta, type="l")

Verifique que se usa el argumento by.column, cuyo valor por default es TRUE, esto para evitar que la función se aplique a cada una de las columnas con las que estamos trabajando. En los casos anteriores, como solo teníamos un vector como argumento de datos, no era necesario preocuparnos por este argumento de la función.

Note que esta función la podemos modificar para obtener más de un resultado de la función con la que estamos interesados. Por ejemplo, podemos estar enterados en recuperar el intercepto y la pendiente del modelo de regresión, o adicionalmente recuperar el R2.

beta_sis2 = function(x){
  lmr <-lm(x[,2] ~ x[,1])
  c(beta=coef(lmr)[[2]], r2=summary(lmr)$r.squared)
}
 
Beta_r2 <- rollapply(r_data, width=100, by.column = F,  beta_sis2)
 
par(mfrow=c(2,1))
plot(Beta_r2[,1], type="l")
plot(Beta_r2[,2], type="l")

Una alternativa mostrada en data.camp es:

FUN = function(z) coef(lm(y ~ y1 + y12, data = as.data.frame(z))

3.       Condiciones de la estimación

3.1. Tamaño de la ventana

 Note que no es trivial elegir el tamaño de la ventana. Pues la sensibilidad al contexto, o inclusive la dinámica de la serie puede cambiar de forma significativa en función del tamaño de la ventana seleccionada.

 #diferentes ventanas de estimation
vol_t <- rollapply(r_data0, width=100, FUN=sd,align = "right", fill=NA)
vol_t500 <- rollapply(r_data0, width=500, FUN=sd,align = "right", fill=NA)
vol_t1000 <- rollapply(r_data0, width=1000, FUN=sd, align = "right", fill=NA)
 
plot(vol_t, type="l")
lines(vol_t500)
lines(vol_t1000)

3.2. Ventana recursiva vs. ventana móvil

 ***

4.       Referencias

DataCamp. 2022. rollapply: Apply Rolling Functions.
 
Dumitrescu, E.; Hurlin, C.; Pham., V. Backtesting Value-at-Risk: From Dynamic Quantile to Dynamic Binary Tests.
 
Grothendieck, K. (2020). Rollapply for backtesting the value at risk. stackoverflow.
 
Grothendieck, K. (2021). Using Rollapply to return both the Coefficient and RSquare. stackoverflow.
 
Kleiber, C. (2017). Applied Econometrics whith R.
 
Simaan, M. (2018). Tip of the Month: rollapply.
 
Wickham., H. (2021). Advanced R. Functionals.

Creando variables por grupos en dplyr (group_by + mutate)

  Simulemos una base de hogares, donde se identifica el hogar, el sexo (1 mujer) y provincia y edad para cada miembro.   # Definir la lista ...