Esta publicación tiene dos objetivos, uno personal y otro general. El objetivo personal es tener en limpio y a la mano el código para poder replicar el índice de tipo de cambio real que Dani Rodrik utiliza para su análisis de esta variable y el crecimiento económico. El segundo objetivo, el general, es simplemente compartirlo a todo aquel que guste, aprovechando que la apreciación del peso mexicano es un tema de moda.
No hay comando en este script que no se encuentre en sitios y foros como stackoverflow, repositorios de github, rpubs, los manuales de Wickham, The R graph gallery, etc.
Aviso: Recomiendo leer el artículo de Rodrik.
Como insumo para sus cálculos él utiliza la Penn World Table
6.2, así que haré lo mismo. El cálculo con la versión más
reciente, la Penn World Table 10.01, se deja al lector,
sin embargo, de tener dificultades pueden pedírmelo personalmente. Si
algún enlace no abre con click izquierdo, intenta usar click derecho y
abrir en otra pestaña.
Cualquier corrección o comentario házmelo saber por este medio o a través de mi twitter ecodiegoale.
rm(list = ls()) #para borrar todos los objetos en la memoria de la consola
options(scipen=999) #para desactivar la notación científica
Los paquetes que usaremos.
#Si no cuentas con los paquetes, instálalos utilizando el comando install.packages("ejemplo")
library(tidyverse)
library(ggthemes)
library(reshape2)
library(readxl)
Ahora la base de datos.
# Este es el URL
url <- "https://www.rug.nl/ggdc/docs/pwt62_data.xlsx"
# Descargamos el archivo
download.file(url, destfile = "pwt62_data.xlsx", mode = "wb")
#Vemos cuántas hojas tiene y sus nombres
excel_sheets("pwt62_data.xlsx")
## [1] "Variables" "Data"
En la hoja Variables viene la descripción de las variables o columnas, en la hoja Data viene la base de datos de la PWT6.2.
tabla <- "Data"
data <- read_excel("pwt62_data.xlsx", sheet = tabla)
variables <- "Variables"
codebook <- read_excel("pwt62_data.xlsx", sheet = variables)
Vamos a ver qué variables trae la PWT6.2 (para más información abrir este enlace).
print(codebook)
## # A tibble: 25 × 2
## POP Population
## <chr> <chr>
## 1 XRAT Exchange Rate
## 2 PPP Purchasing Power Parity over GDP
## 3 cgdp Real Gross Domestic Product per Capita
## 4 cc Consumption Share of CGPD
## 5 cg Government Share of CGDP
## 6 ci Investment Share of CGDP
## 7 p Price Level of Gross Domestic Product
## 8 pc Price Level of Consumption
## 9 pg Price Level of Government
## 10 pi Price Level of Investment
## # … with 15 more rows
Siguiendo los pasos de Rodrik, primero se calcula un índice del tipo de cambio real:
\(lnRER_{it}=ln(XRAT_{it}/PPP_{it})\)
donde:
\(i\) es un subíndice para los países y \(t\) es un subíndice para periodos de tiempo (de 5 años).
Values of RER greater than one indicate that the value of the currency is lower (more depreciated) than indicated by purchasing power parity. However, in practice nontradable goods are also cheaper in poorer countries (through the Balassa-Samuelson effect), which requires an adjustment (Rodrik, 2008, p. 371).
Vamos a generar la variable que indique el periodo de tiempo de 5 años. Revisamos cuántos años incluye la base.
unique(data$year)
## [1] 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
## [16] 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
## [31] 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994
## [46] 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
El periodo abarca 55 años, vamos a generar una variable dummy para los años, cada cinco años tomará el valor \(n+1\), por lo que cada país tendrá una serie (f_time) donde los valores serán desde 1 hasta 11.
data$f_time <- ceiling((data$year - 1949) / 5)
head(data$f_time, n = 15 )
## [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
Ya tenemos las variables que necesitamos, ahora vamos a revisar a grandes rasgos cómo está compuesta la PWT6.2:
summary(data)
## country country isocode year POP
## Length:10340 Length:10340 Min. :1950 Min. : 7.3
## Class :character Class :character 1st Qu.:1963 1st Qu.: 1142.5
## Mode :character Mode :character Median :1977 Median : 4388.7
## Mean :1977 Mean : 22848.7
## 3rd Qu.:1991 3rd Qu.: 12942.1
## Max. :2004 Max. :1294845.6
## NA's :11
## XRAT PPP cgdp cc
## Length:10340 Length:10340 Length:10340 Length:10340
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## cg ci p pc
## Length:10340 Length:10340 Length:10340 Length:10340
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## pg pi openc cgnp
## Length:10340 Length:10340 Length:10340 Length:10340
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## y rgdpl rgdpch rgdpeqa
## Length:10340 Length:10340 Length:10340 Length:10340
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## rgdpwok rgdptt openk kc
## Length:10340 Length:10340 Length:10340 Length:10340
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## kg ki grgdpch f_time
## Length:10340 Length:10340 Length:10340 Min. : 1
## Class :character Class :character Class :character 1st Qu.: 3
## Mode :character Mode :character Mode :character Median : 6
## Mean : 6
## 3rd Qu.: 9
## Max. :11
##
Observamos que las variables que nos interesan son del tipo character, y nosotros necesitamos que sean números. Primero, vamos a quedarnos con las variables que nos importan.
data <- data%>%
dplyr::select(year, country, f_time, XRAT, PPP, rgdpch)
Luego, convertimos a número las variables para poder operarlas.
data$xrat <-as.numeric(data$XRAT)
data$ppp <-as.numeric(data$PPP)
data$rgdpch<-as.numeric(data$rgdpch)
data$f_time<-as.factor(data$f_time)#La función lm() convierte factores a dummies de manera automática.
Otro aspecto a considerar es la cantidad de NAs que hay en nuestra base, para nuestro caso simplemente vamos a omitirlos mediante el siguiente comando:
data <- na.omit(data)
Ya podemos calcular \(lnRER_{it}\) como indica Rodrik.
data<- data%>%
mutate(xratppp = xrat/ppp,
ln_rer = log(xratppp),
ln_rgdpch = log(rgdpch))
Una vez calculado el tipo de cambio real, se ajusta por el efecto Balassa-Samuelson por medio de una regresión de datos panel del siguiente tipo:
\(lnRER_{it}=\alpha+\beta RDPCH_{it}+ f_t + u_{it}\)
donde:
Para Rodrik, usando datos de la Penn World Table 6.2, el estimador \(\hat{\beta}=-0.24\).
Procedemos a calcular dicha regresión:
lnrer <- lm(data = data,
ln_rer ~ ln_rgdpch + f_time -1)
summary(lnrer)
##
## Call:
## lm(formula = ln_rer ~ ln_rgdpch + f_time - 1, data = data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.1496 -0.2575 0.0057 0.2603 3.9720
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## ln_rgdpch -0.229434 0.005241 -43.78 <0.0000000000000002 ***
## f_time1 2.330466 0.051242 45.48 <0.0000000000000002 ***
## f_time2 2.422105 0.049949 48.49 <0.0000000000000002 ***
## f_time3 2.503465 0.046812 53.48 <0.0000000000000002 ***
## f_time4 2.524475 0.047442 53.21 <0.0000000000000002 ***
## f_time5 2.501989 0.046264 54.08 <0.0000000000000002 ***
## f_time6 2.376269 0.046847 50.72 <0.0000000000000002 ***
## f_time7 2.465214 0.047098 52.34 <0.0000000000000002 ***
## f_time8 2.606330 0.047300 55.10 <0.0000000000000002 ***
## f_time9 2.703895 0.047095 57.41 <0.0000000000000002 ***
## f_time10 2.772996 0.047246 58.69 <0.0000000000000002 ***
## f_time11 2.893721 0.048317 59.89 <0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.4956 on 7322 degrees of freedom
## Multiple R-squared: 0.6944, Adjusted R-squared: 0.6939
## F-statistic: 1386 on 12 and 7322 DF, p-value: < 0.00000000000000022
Para mí \(\hat{\beta}=-0.229\), además de que es altamente significativa.
…suggesting a strong and precisely estimated Balassa-Samuelson effect: when incomes rise by 10 percent, the real exchange rate falls by around 2.4 percent. (Rodrik, 2008, p. 371).
Por último, se calcula lo que Rodrik llama el índice de subvaluación de tipo de cambio.
\(lnUNDERVAL_{it}=lnRER_{it}-ln\hat{RER_{it}}\)
Esto es la diferencia del tipo de cambio real observado menos el estimado por la regresión anterior.
#Calculamos el tipo de cambio real estimado
data$lnrer_hat <- predict(lnrer)
#Hacemos la diferencia del observado menos el estimado
data<- data%>%
mutate(lnunder = ln_rer - lnrer_hat)
Defined in this way, UNDERVAL is comparable across countries and over time. Whenever UNDERVAL exceeds unity, it indicates that the exchange rate is set such that goods produced at home are relatively cheap in dollar terms: the currency is undervalued. When UNDERVAL is below unity, the currency is overvalued. (Rodrik, 2008, p. 372).
Filtramos para México.
data.mx <- data%>%
filter(country == "Mexico")
Ahora graficamos.
tcr_mx <- ggplot(data = data.mx, aes(x = year, y = lnunder))+
geom_hline(yintercept = 0, size=1, linetype = 'dashed', alpha = 0.5)+
geom_line(aes(y = lnunder), colour="#00AFBB",cex = 1)+
theme_bw()+
labs(title="México: Índice de tipo de cambio real",
caption="Fuente: Elaboración propia con información de Penn World Table 6.2.")+
xlab(" ")+
ylab("Logaritmo natural")
tcr_mx
Vamos a comparar el comportamiento de nuestro tipo de cambio real que calculamos con el índice de tipo de cambio real multilateral que elabora el Banco de México. Para esto usaremos la API del propio banco. No me detendré para explicar cómo usar la API, eso ya lo hice en una entrada pasada, puedes consultarla aquí.
Cargamos la librería necesaria:
library(siebanxicor)
Cargamos el token y bajamos la serie.
setToken("8f7fb9112cdec753a2e2dedb149dc1d982523f138b05af2e34aebc07c6a5fca4")
idSerie <- c("SR28")
metadata <- getSeriesMetadata(idSerie)
head(metadata)
## idSerie title
## 1 SR28 Pesos´s Real Exchange Rate Index P/ Real Exchange Rate Index
## startDate endDate frequency dataType unit
## 1 1968-01-01 2023-04-01 Monthly Indexes Without units
Esta serie tiene una frecuencia mensual y va desde enero de 1968 hasta abril del 2023. Nuestra serie del tipo de cambio real ajustado por el efecto Balassa-Samuelson es una serie anual de 1950 a 2004. Así que con esto mente procesamos la serie del Banco de México.
tcr_banxico <- getSeriesData(idSerie, '1968-01-01', '2004-12-01')
tcr_banxico <- getSerieDataFrame(tcr_banxico,"SR28")
head(tcr_banxico)
## date value
## 1 1968-01-01 64.058
## 2 1968-02-01 64.146
## 3 1968-03-01 63.575
## 4 1968-04-01 63.727
## 5 1968-05-01 63.034
## 6 1968-06-01 63.944
Como la serie es mensual, vamos a obtener un promedio anual.
tcr_banxico <- tcr_banxico %>%
mutate(year = lubridate::year(date)) %>%
group_by(year) %>%
summarise(tcr_promedio = mean(value))
head(tcr_banxico)
## # A tibble: 6 × 2
## year tcr_promedio
## <dbl> <dbl>
## 1 1968 64.1
## 2 1969 65.1
## 3 1970 65.4
## 4 1971 66.1
## 5 1972 69.8
## 6 1973 71.8
Ahora graficamos:
tcr_bxco <- ggplot(data = tcr_banxico, aes(x = year, y = tcr_promedio))+
geom_line(colour="#FC4E07",cex = 1)+
theme_bw()+
labs(title="Índice de tipo de cambio real multilateral",
caption="Fuente: Elaboración propia con información de Banco de México.")+
xlab(" ")+
ylab("Índice")
tcr_bxco
Para tener una mejor visualización vamos a poner ambos índices de
tipo de cambio real en un solo gráfico usando
grid.arrange(). No me detendré a explicar cómo graficar de
esta manera pues ya lo abordé en otra entrada. Puedes consultar dicha
entrada aquí.
#Esto para emparejar las series de tiempo
data.mx <- data.mx%>%
filter(year>1967)
#Hacemos un solo dataframe
tcr.df <- bind_cols(tcr_banxico, data.mx$lnunder)
head(tcr.df)
## # A tibble: 6 × 3
## year tcr_promedio ...3
## <dbl> <dbl> <dbl>
## 1 1968 64.1 0.00402
## 2 1969 65.1 -0.0137
## 3 1970 65.4 0.0361
## 4 1971 66.1 0.0334
## 5 1972 69.8 0.0253
## 6 1973 71.8 -0.0303
Le cambiamos el nombre a la columna 3 que es la que tiene los valores del tipo de cambio de Rodrik.
tcr.df <- tcr.df %>%
rename(tcr_rodrik = ...3)
Ahora ya podemos graficar.
tcr_rodrik <- ggplot(data = tcr.df, aes(x = year, y = tcr_rodrik))+
geom_hline(yintercept = 0, size=1, linetype = 'dashed', alpha = 0.5)+
geom_line(aes(y = tcr_rodrik), colour="#00AFBB",cex = 1)+
theme_bw()+
labs(title="Índice de tipo de cambio real a la Rodrik",
caption="Fuente: Elaboración propia con información de Penn World Table 6.2.")+
xlab(" ")+
ylab("Logaritmo natural")
Ahora ambos gráficos:
library(grid)
library(gridExtra)
grid.arrange(tcr_rodrik, tcr_bxco, nrow=2)
Podemos observar ciertas divergencias en ambos índices, un motivo es que tienen objetivos diferentes, el índice de Rodrik tiene como fin determinar cuándo el tipo de cambio real está subvaluado y que pueda ser utilizado en modelaciones de datos panel, sin embargo los periodos de crisis son muy marcados en ambos, ya que las devaluaciones son evidentes. Nuevamente, la elaboración del índice anual de Banxico a fechas más recientes se le deja al lector.