Partimos del concepto de cointegración entre series no estacionarias. Aquí tenemos datos de la Contabilidad Nacional del INE de Consumo e Inversión (Formación Bruta de Capital Fijo).
require(xts)
datos <- read.csv("GDPdemand.csv",head=TRUE,sep=";",dec=".",fileEncoding = "Latin1")
gcf = log(datos$Total[1:104])
fbcf = log(datos$Total[105:208])
trimestre <- as.yearqtr(datos$Periodo[1:104],format="%YT%q")
gcf <- zoo(gcf,trimestre)
fbcf <- zoo(fbcf,trimestre)
plot.zoo(merge(gcf,fbcf),plot.type="single",main="Log Consumption and Investment",col=c("steelblue","red"),lwd=4)
legend("bottomright",legend=c("GCF","FBCF"),lty=c(1,1),lwd=4,,col=c("steelblue","red"))
Estas series no están cointegradas. Regresamos una contra otra y realizamos un ADF test sobre los residuos para comprobarlo.
require(dynlm)
model <- dynlm(gcf ~ fbcf)
ehat <- resid(model)
summary(model)
Time series regression with "zoo" data: Start = 1995 Q1, End = 2020 Q4 Call: dynlm(formula = gcf ~ fbcf) Residuals: Min 1Q Median 3Q Max -0.22515 -0.17306 -0.07365 0.18115 0.30148 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 3.34598 0.62954 5.315 6.3e-07 *** fbcf 0.80226 0.05811 13.807 < 2e-16 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 0.1803 on 102 degrees of freedom Multiple R-squared: 0.6514, Adjusted R-squared: 0.648 F-statistic: 190.6 on 1 and 102 DF, p-value: < 2.2e-16
plot.zoo(ehat,main="C vs. I RESIDS",lwd=4)
tseries::adf.test(ehat)
Augmented Dickey-Fuller Test data: ehat Dickey-Fuller = -2.3392, Lag order = 4, p-value = 0.436 alternative hypothesis: stationary
Consideramos dos series $\{ x_t, y_t \}_{t=1}^T$. La idea es tomar una ventana $m$ y convertir sucesivamente las observaciones $x_t,\ldots,x_{t+m-1}$ e $y_t,\ldots,y_{t+m-1}$ en n-tuples ordenados $\left( s_1^x (t),\ldots , s_m^x(t)\right)$ y $\left( s_1^y (t),\ldots , s_m^y(t)\right)$ para $t=1,\ldots,T-m+1$.
Con las series convertidas en símbolos, podemos calcular la distancia $d(s,s')$ entre dos símbolos cualesquiera $\left( s_1,\ldots , s_m\right)$ y $\left( s'_1,\ldots , s'_m\right)$ como la suma de sus distancias en valor absoluto y normalizado sobre el máximo valor que puede alcanzar dicha diferencia, es decir,:
$d(s,s') = \frac{1}{\delta(m)} \sum_{j=1}^m \mid s_j - s'_j \mid $
La función $\delta(m)$ es dos veces la suma de los números naturales pares inferiores a $m$, si $m$ es impar o de los naturales impares inferiores a $m$ si $m$ es par. Es decir:
$ \delta(m) = \left\{ \begin{array}{ll} % m^2/2 & \textrm{ si m es par}\\ (m^2-1)/2 & \textrm{ si m es impar} \end{array} \right. $
# Funcion para normalizar distancias
delta <- function(dimension=5) {
if ((m/2)==floor(m/2)) {
dummy <- (m^2)/2
} else {
dummy <- (m^2-1)/2
}
return(dummy)
}
A modo de ejemplo, supongamos que las primeras seis observaciones de consumo e inversión son
C = (11.39, 11.40, 11.41, 11.43, 11.39, 11.36),
I = (12.39, 12.40, 12.41, 12.43, 12.42, 12.36),
entonces:
Consumo | C.Symbol | Inversion | I.Symbol | Normalizada |
---|---|---|---|---|
11.39 11.40 11.41 11.43 | 4 3 2 1 | 12.39 12.40 12.41 12.43 | 4 3 2 1 | 0.00 |
11.40 11.41 11.43 11.39 | 3 2 1 4 | 12.40 12.41 12.43 12.42 | 3 4 2 1 | 0.75 |
11.41 11.43 11.39 11.36 | 2 1 3 4 | 12.41 12.43 12.42 12.36 | 2 3 1 4 | 0.50 |
Obsérvese que la serie de distancias admite un número discreto de valores posibles. Si por ejemplo $m=4$, entonces los valores posibles para la distancia entre dos series son {0,2,4,6,8} sin normalizar o {0, 1/4, 1/2, 3/4, 1} normalizados. Si $m$ es por ejemplo $m=5$ entonces tenemos {0,2,4,6,8,10,12} sin normalizar o {0, 1/6, 1/3, 1/2, 2/3, 5/6, 1} normalizados. Es decir, la serie de las distancias también es una serie con un número finito $\delta(m)$ de símbolos.
A continuación calculamos esa serie para nuestro consumo e inversión y hacemos el plot.
# Parametros iniciales ----------------------------------------------------------------
T=length(gcf) # Numero de obervaciones
m=8 # Dimension de la ventana
max_dist <- delta(m) # Maxima distancia para normalizar
# Bucle que transforma las secuencias de observaciones en distancias -------------------
xdist=NULL
for (i in 1:(T-m+1)) {
gcf_sym <- sort.list(gcf[i:(i+m-1)],decreasing=TRUE)
fbcf_sym <- sort.list(fbcf[i:(i+m-1)],decreasing=TRUE)
xdist[i] <- sum(abs(gcf_sym - fbcf_sym))/max_dist
}
xdist <- zoo(c(xdist,rep(NA,m-1)),trimestre)
plot(xdist,main="Symbol Distance",lwd=4)
Lo que vemos es que las series "se parecen mucho" en los trimestres anteriores al inicio de la crisis del 2008 y que ambas empiezan a diverger alcanzándose una distancia de casi 1 en torno a 2009. Pero ¿qué significan estos números? Si miramos las series originales, hasta 2005 las dos series seguían un mismo trend. Si ambas presentan patrones constantemente crecientes, se distancia es pequeña o cero. A partir de 2005 consumo sube, pero inversión baja. Cuando una serie sube y la otra baja en una vetana concreta, la distancia medida va a ser máxima (1 normalizada). Eso es lo que reflejan los picos de casi uno durante la crisis. Una pregunta natural de la que aún no tengo certeza en la respuesta es cómo podemos saber si un valor entra dentro de "las series divergen" o "las series se comportan de manera parecida". La cointegración si que te dice que las series tienen relación de largo plazo y eso tiene significado económico. Aquí no estoy seguro de que interpretación tienen estos números. Lo único que se me ha ocurrido es calcular unas "bandas de confianza" bajo la nula de que las dos series se comportasen de manera completamente aleatoria. Esto (que no es la manera correcta de calcularlo, ya lo sé) es lo que hago con la siguiente función que hace una simulación del proceso simbolico y halla valores críticos de la distribución simulada).
# Funcion para calcular los puntos criticos
CritVals <- function(dimension=5,boots=100,clevel=0.05) {
max_dist <- delta(dimension) # Llamada a delta(m)
xdif <- NULL
for (i in (1:boots)) {
x1 <- sort.list(runif(dimension),decreasing=TRUE)
x2 <- sort.list(runif(dimension),decreasing=TRUE)
xdif[i] <- sum(abs(x1-x2))/max_dist
}
xpts <- as.numeric(levels(as.factor(xdif)))
ypts <- hist(xdif,breaks=xpts,plot=FALSE)
ypts <- c(0,cumsum(ypts$counts/boots))
f <- splinefun(ypts,xpts)
c1 <- f(clevel/2)
c2 <- f(1-clevel/2)
return(c(c1,c2))
}
# Obtenemos los valores criticos
cvs <- CritVals(dimension=m,boots=1000,clevel=0.10)
clow <- zoo(cvs[1],trimestre)
cup <- zoo(cvs[2],trimestre)
# Grafico
plot(merge(xdist,clow,cup),plot.type="single",main="Symbol Distance",lwd=c(4,2,2))
Lo que queda por debajo de la linea inferior serían periodos en los que las series "van a la par" (whatever it means), lo que queda por arriba son períodos en los que las series "van a la contra" y lo que queda por en medio periodos en los que "van por libre".
NOTA FINAL: El procedimiento anterior no es la manera correcta de calcular esas bandas de confianza. La manera correcta tendría en cuenta que si la distancia en "t" ha sido cero por ejemplo, en t+1 es imposible que tome ciertos valores porque t+1 tiene m-1 valores (los m-1 últimos de t) que siguen un mismo orden, y la aparición de un nuevo valor solo puede modificar la distancia en ciertas formas (es decir, hay persistencia en la serie de distancias, y mi procedimiento no la tiene en cuenta).