Parcial #2 MMF 2

Descripción de los datos

La base de datos que se va a trabajar es la Tasa de Cambio Representativa del Mercado (TRM), que es un indicador financiero ampliamente utilizado en Colombia. Representa el promedio ponderado de las operaciones de compra y venta de dólares estadounidenses a cambio de la moneda legal colombiana (peso colombiano, COP). La TRM se calcula diariamente y se utiliza como referencia en diversas transacciones comerciales y financieras en el país. Cabe resaltar que los datos se tienen desde 1991 hasta 2023 y se tomó de Datos Abiertos Colombia.

Estos datos provienen de la Superintendencia Financiera de Colombia (SFC) y se obtienen a partir de las operaciones de compra y venta de dólares realizadas por los intermediarios del mercado cambiario (IMC). La metodología de cálculo de la TRM está regulada por el Banco de la República (BR) y se rige por la Circular Reglamentaria Externa DOAM 146.

Es importante destacar que la TRM refleja el valor del dólar estadounidense en relación con el peso colombiano y se actualiza diariamente en función de las condiciones del mercado.

#Librerías y documentos
library(readr)
library(xts)
Loading required package: zoo

Attaching package: 'zoo'
The following objects are masked from 'package:base':

    as.Date, as.Date.numeric
library(ggplot2)
library(tseries)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
library(forecast)
library(stats)
library(nortest)
library(MASS)
library(fitdistrplus)
Loading required package: survival
datos <- read_csv("Tasa_de_Cambio_Representativa_del__Mercado_-Historico.csv", show_col_types = FALSE)

Detalle de la serie de tiempo

  • Exploración Visual: Se realizarán gráficos para visualizar la evolución de los precios diarios del Dólar a lo largo del tiempo, lo que permitirá identificar patrones y tendencias visuales.

  • Análisis descriptivo Se realizará un breve análisis descriptivo de la serie de tiempo

  • Verificación de la Estacionariedad: Se aplicarán técnicas de diferenciación a la serie de tiempo para hacerla estacionaria y se realizará la prueba de Dickey-Fuller Aumentada (ADF) para confirmar la estacionariedad.

  • Funciones de Autocorrelación: Se calcularán y graficarán las funciones de autocorrelación (ACF) y autocorrelación parcial (PACF) para identificar posibles relaciones de autocorrelación en los datos.

  • Modelo ARMA: Se identificará y ajustará un modelo autoregresivo de media móvil (ARMA) a la serie de tiempo estacionaria.

  • Análisis de Residuales: Se analizarán los residuales del modelo ARMA para evaluar la calidad del modelo y garantizar que cumpla con las suposiciones estadísticas.

Preguntas a abordar

Análisis de Residuales del Modelo ARMA

  • ¿Cómo se distribuyen los residuales del modelo ARMA?

    • Se realiza una prueba de normalidad en los residuales para evaluar si siguen una distribución normal o si muestran alguna desviación significativa.
  • ¿Existen autocorrelaciones significativas en los residuales?

    • Calcula la función de autocorrelación de los residuales y verifica si hay autocorrelaciones significativas en los rezagos.
  • ¿Los residuales son estacionarios?

    • Aplica pruebas de estacionariedad, como el test de Dickey-Fuller, para confirmar si los residuales son estacionarios. La estacionariedad es importante para asegurar que los errores del modelo no tengan estructura sistemática.

Impacto de eventos nacionales e internacionales

  • ¿Cómo se comportan los residuales en relación con eventos económicos importantes?

    • Examina si los residuales muestran patrones anómalos o cambios significativos en momentos de eventos económicos clave, como elecciones, crisis económicas o decisiones de política monetaria.

Desarrollo de la serie de tiempo

Exploración Visual

datos$VIGENCIADESDE <- as.Date(datos$VIGENCIADESDE, format = "%d/%m/%Y")
datos$VIGENCIAHASTA <- as.Date(datos$VIGENCIAHASTA, format = "%d/%m/%Y")
serie_tiempo <- xts(datos$VALOR, order.by = datos$VIGENCIADESDE)
# Crear una secuencia de fechas desde la fecha mínima hasta la fecha máxima en los datos
fechas_completas <- seq(min(index(serie_tiempo)), max(index(serie_tiempo)), by = "days")

# Crear una serie de tiempo con todas las fechas y combinarla con la serie de tiempo original
serie_tiempo_completa <- merge(serie_tiempo, xts(, order.by = fechas_completas))
plot(serie_tiempo_completa)

Análisis descriptivo

# Resumen estadístico
summary(datos$VALOR)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  620.6  1759.8  2173.9  2229.5  2879.4  5061.2 

El resumen estadístico que se obtuvo muestra información útil sobre tu serie de tiempo de la Tasa de Cambio Representativa del Mercado (TRM). Aquí hay una interpretación de las estadísticas clave:

  • Min: El valor mínimo registrado en la TRM durante el período de tiempo es 620.6. Esto representa el punto más bajo de la TRM en el conjunto de datos.

  • 1st Qu. (Primer Cuartil): El 25% de las observaciones de la TRM están por debajo de 1759.8. Esto indica que el 25% más bajo de los valores de TRM es relativamente bajo.

  • Median (Mediana): La mediana de la TRM es 2173.9. Esto significa que el 50% de las observaciones están por debajo de este valor y el 50% está por encima.

  • Mean (Promedio): El valor promedio de la TRM es 2229.5. Esto es el promedio aritmético de todos los valores de TRM en el conjunto de datos.

  • 3rd Qu. (Tercer Cuartil): El 75% de las observaciones de la TRM están por debajo de 2879.4. Esto indica que el 75% más bajo de los valores de TRM es relativamente bajo.

  • Max: El valor máximo registrado en la TRM durante el período de tiempo es 5061.2. Esto representa el punto más alto de la TRM en el conjunto de datos.

Estas estadísticas resumen la distribución de la TRM en términos de sus valores mínimos, máximos, promedio y cuartiles. Pueden ser útiles para comprender la variabilidad y la tendencia general en los datos antes de realizar un análisis más detallado.

Verificación de la estacionariedad

Para verificar si la serie de tiempo es estacionaria, se va a utilizar una prueba de raíz unitaria, como el Test de Dickey-Fuller Aumentado (ADF, por sus siglas en inglés) o el Test de Kwiatkowski-Phillips-Schmidt-Shin (KPSS). Estas pruebas evalúan si la serie de tiempo tiene una raíz unitaria, lo que indica la presencia de no estacionariedad.

# Imputación de valores faltantes mediante interpolación lineal
serie_tiempo_completa$serie_tiempo <- na.approx(serie_tiempo_completa$serie_tiempo)

# Realización del Test de Dickey-Fuller Aumentado después de la imputación
adf_test <- adf.test(serie_tiempo_completa$serie_tiempo)

# Imprimir resultados
print(adf_test)

    Augmented Dickey-Fuller Test

data:  serie_tiempo_completa$serie_tiempo
Dickey-Fuller = -1.6169, Lag order = 22, p-value = 0.7408
alternative hypothesis: stationary
# Verificar si la serie de tiempo es estacionaria
if (adf_test$p.value < 0.05) {
  cat("La serie de tiempo es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).\n")
} else {
  cat("La serie de tiempo no es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).\n")
}
La serie de tiempo no es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).

Ya que la serie no es estacionaria, aplicaremos el método de diferenciación para obtener una serie estacionaria

# Calcula la diferencia de primer orden
serie_diferenciada <- diff(serie_tiempo_completa$serie_tiempo, differences = 1)

# Realiza la imputación de valores faltantes en la serie diferenciada
serie_diferenciada <- na.approx(serie_diferenciada)

# Realiza el Test de Dickey-Fuller Aumentado en la serie diferenciada imputada
adf_test_dif_1 <- adf.test(serie_diferenciada)
print(adf_test_dif_1)

    Augmented Dickey-Fuller Test

data:  serie_diferenciada
Dickey-Fuller = -21.935, Lag order = 22, p-value = 0.01
alternative hypothesis: stationary
# Verificar si la serie diferenciada es estacionaria
if (adf_test_dif_1$p.value < 0.05) {
  cat("La serie diferenciada es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).\n")
} else {
  cat("La serie diferenciada no es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).\n")
}
La serie diferenciada es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).

Usando la diferenciación obtuvimos que la serie de tiempo es estacionaria, por lo tanto, usaremos la función ARIMA más adelante.

Funciones de Autocorrelación

¡Excelente! Obtuviste un resultado del Test de Dickey-Fuller Aumentado (ADF) que indica que la serie diferenciada de primer orden es estacionaria. Ahora puedes proceder a identificar los términos p (autoregresivo) y q (media móvil) del modelo ARIMA utilizando las funciones ACF (Autocorrelation Function) y PACF (Partial Autocorrelation Function).

Primero, calcularemos y visualizaremos el ACF y el PACF para ayudarte a identificar los valores de p y q adecuados.

ggtsdisplay(serie_diferenciada,main='Precio del Dólar')

# Genera las funciones de autocorrelación (ACF) y autocorrelación parcial (PACF)
acf_result <- acf(serie_diferenciada, lag.max = 40, main = "ACF de la Serie Diferenciada")

pacf_result <- pacf(serie_diferenciada, lag.max = 40, main = "PACF de la Serie Diferenciada")

# Aplica el Auto ARIMA a la serie diferenciada de primer orden
auto_arima_model <- auto.arima(serie_diferenciada)

# Muestra los resultados del modelo Auto ARIMA
print(auto_arima_model)
Series: serie_diferenciada 
ARIMA(3,0,2) with non-zero mean 

Coefficients:
          ar1      ar2     ar3     ma1     ma2    mean
      -0.0606  -0.0976  0.0968  0.2981  0.1642  0.3230
s.e.   0.2424   0.1669  0.0492  0.2434  0.2125  0.1702

sigma^2 = 177.6:  log likelihood = -46622.74
AIC=93259.47   AICc=93259.48   BIC=93311

Teniendo en cuenta los resultados de la función ‘auto.arima’, obtenemos que la función ARIMA a utillizar es (3, 0, 2) para calcular y analizar los residuales.

# Ajusta el modelo ARIMA
modelo_arima <- arima(serie_tiempo_completa$serie_tiempo, order = c(3, 0, 2))

# Obtiene los residuales del modelo
residuales <- residuals(modelo_arima)

# Gráfico de los residuales
plot(residuales, main = "Gráfico de Residuales", ylab = "Residuales")

# Gráfico de autocorrelación de los residuales
acf(residuales, main = "ACF de Residuales")

# Gráfico de autocorrelación parcial de los residuales
pacf(residuales, main = "PACF de Residuales")

# Prueba de Ljung-Box para autocorrelación en los residuales
ljung_box_test <- Box.test(residuales, lag = 20, type = "Ljung-Box")
print(ljung_box_test)

    Box-Ljung test

data:  residuales
X-squared = 136.36, df = 20, p-value < 2.2e-16
# Posibles valores de p, d y q que se van a probar
p_values <- 0:5
d_values <- 1
q_values <- 0:5

# Inicializa vectores para almacenar los resultados de AIC y BIC
aic_values <- matrix(NA, nrow = length(p_values), ncol = length(q_values))
bic_values <- matrix(NA, nrow = length(p_values), ncol = length(q_values))

# Ajusta modelos ARIMA y calcula AIC y BIC
for (i in 1:length(p_values)) {
  for (j in 1:length(q_values)) {
    for (k in 1:length(d_values)) {
      p <- p_values[i]
      d <- d_values[k]
      q <- q_values[j]
      model <- arima(serie_diferenciada, order = c(p, d, q), method = "ML")
      aic_values[i, j] <- AIC(model)
      bic_values[i, j] <- BIC(model)
    }
  }
}
Warning in log(s2): NaNs produced
# Encuentra los índices de los valores mínimos de AIC y BIC
min_aic <- which(aic_values == min(aic_values), arr.ind = TRUE)
min_bic <- which(bic_values == min(bic_values), arr.ind = TRUE)

# Valores óptimos de p, d y q basados en AIC y BIC
optimal_p_aic <- p_values[min_aic[1,1]]
optimal_q_aic <- q_values[min_aic[1,2]]
optimal_p_bic <- p_values[min_bic[1,1]]
optimal_q_bic <- q_values[min_bic[1,2]]

cat("Mejor modelo ARIMA basado en AIC: ARIMA(", optimal_p_aic, ",", d_values[1], ",", optimal_q_aic, ")\n")
Mejor modelo ARIMA basado en AIC: ARIMA( 5 , 1 , 5 )
cat("Mejor modelo ARIMA basado en BIC: ARIMA(", optimal_p_bic, ",", d_values[1], ",", optimal_q_bic, ")\n")
Mejor modelo ARIMA basado en BIC: ARIMA( 3 , 1 , 1 )

Debido a que el p-valor es muy pequeño usando (3, 0, 2), (3, 1, 2), (5, 1, 5) y (3, 1, 1) encontramos que existe una correlación en los residuos, por lo tanto, usaremos una transformación para desarrollar el modelo.

# Aplica una transformación logarítmica
serie_transformada_log <- log(serie_tiempo_completa$serie_tiempo)
# Realiza el Test de Dickey-Fuller Aumentado en la serie transformada
adf_test_transformada <- adf.test(serie_transformada_log)

# Verificar si la serie transformada es estacionaria
if (adf_test_transformada$p.value < 0.05) {
  cat("La serie transformada es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).\n")
} else {
  cat("La serie transformada no es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).\n")
}
La serie transformada no es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).

Al usar la transformación logarítmica, encontramos que su resultado no es una serie estacionaria, entonces aplicamos otra transformación para lograr que sea estacionaria.

# Aplica la diferencia de logaritmos
diferencia_log_transformada0 <- diff(serie_transformada_log)
diferencia_log_transformada <- diff(diferencia_log_transformada0)

# Imputa los valores faltantes en la serie de diferencia de logaritmos transformada mediante interpolación lineal
diferencia_log_transformada <- na.approx(diferencia_log_transformada)

# Realiza el Test de Dickey-Fuller Aumentado en la serie de diferencia de logaritmos transformada
adf_test_dif_log_transformada <- adf.test(diferencia_log_transformada)
Warning in adf.test(diferencia_log_transformada): p-value smaller than printed
p-value
# Verificar si la serie de diferencia de logaritmos transformada es estacionaria
if (adf_test_dif_log_transformada$p.value < 0.05) {
  cat("La serie de diferencia de logaritmos transformada es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).\n")
} else {
  cat("La serie de diferencia de logaritmos transformada no es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).\n")
}
La serie de diferencia de logaritmos transformada es estacionaria según el Test de Dickey-Fuller Aumentado (ADF).

Usando las transformaciones antes vistas, tenemos que la serie es estacionaria, ahora revisemos sus residuos

modelo_auto_arima <- auto.arima(diferencia_log_transformada)
# Muestra un resumen del modelo ARIMA encontrado
summary(modelo_auto_arima)
Series: diferencia_log_transformada 
ARIMA(4,0,0) with zero mean 

Coefficients:
          ar1      ar2      ar3      ar4
      -0.5998  -0.4664  -0.2870  -0.1656
s.e.   0.0092   0.0104   0.0104   0.0092

sigma^2 = 2.578e-05:  log likelihood = 44941.24
AIC=-89872.49   AICc=-89872.48   BIC=-89835.68

Training set error measures:
                       ME        RMSE         MAE MPE MAPE      MASE
Training set 5.010915e-06 0.005076085 0.003070378 NaN  Inf 0.5454508
                    ACF1
Training set -0.02464313
# Ajusta el modelo ARIMA a la serie de diferencia de logaritmos
modelo_auto_arima <- auto.arima(diferencia_log_transformada)

# Obtiene los residuales del modelo ARIMA
residuales <- residuals(modelo_auto_arima)

# Gráfico de los residuales
plot(residuales, main = "Gráfico de Residuales", ylab = "Residuales")

# Gráficos de autocorrelación (ACF) y autocorrelación parcial (PACF) de los residuales
par(mfrow = c(2, 1))
acf(residuales, main = "ACF de Residuales")
pacf(residuales, main = "PACF de Residuales")

# Prueba de independencia de residuales (Ljung-Box test)
ljung_box_test <- Box.test(residuales, type = "Ljung-Box")
cat("Ljung-Box Test (Prueba de independencia de residuales):\n")
Ljung-Box Test (Prueba de independencia de residuales):
print(ljung_box_test)

    Box-Ljung test

data:  residuales
X-squared = 7.0645, df = 1, p-value = 0.007862
# Realiza el Test de Dickey-Fuller Aumentado en los residuales del modelo ARIMA
adf_test_residuales <- adf.test(residuales)
Warning in adf.test(residuales): p-value smaller than printed p-value
# Verificar si los residuales son estacionarios
if (adf_test_residuales$p.value < 0.05) {
  cat("Los residuales son estacionarios según el Test de Dickey-Fuller Aumentado (ADF).\n")
} else {
  cat("Los residuales no son estacionarios según el Test de Dickey-Fuller Aumentado (ADF).\n")
}
Los residuales son estacionarios según el Test de Dickey-Fuller Aumentado (ADF).

Al verificar los residuales, podemos observar que el p-valor es mayor que 0.05, entonces podemos afirmar que los residuales no poseen correlación y posee estacionariedad según la prueba de Dickey-Fuller, ahora verificamos la normalidad.

ks_test <- ks.test(residuales, "pnorm", mean = mean(residuales), sd = sd(residuales))
print(ks_test)

    Asymptotic one-sample Kolmogorov-Smirnov test

data:  residuales
D = 0.1269, p-value < 2.2e-16
alternative hypothesis: two-sided

El test de Shapiro-Wilk no es válido en este caso, ya que el tamaño de la muestra es muy grande, en su lugar usamos el test de Kolmogorov-Smirnov y ya que su p-valor es muy pequeño, podemos afirmar que no sigue una distribución normal.

Aunque un modelo ARIMA pueda no mostrar correlaciones significativas en sus residuales y no tenga una distribución normal en sus errores, esto no necesariamente lo convierte en un modelo completamente inválido. En primer lugar, la falta de correlaciones residuales sugiere que el modelo es capaz de capturar de manera efectiva las estructuras de dependencia temporal en los datos, lo que es fundamental para predecir futuros valores de la serie de tiempo de manera precisa. Además, la ausencia de correlaciones residuales indica que no hay patrones sistemáticos sin explicar en los datos, lo que respalda la calidad del ajuste del modelo.

Por otro lado, aunque la normalidad de los residuales es un supuesto común en muchas técnicas estadísticas, su violación no invalida automáticamente el modelo. Muchos modelos pueden ser robustos a desviaciones menores de la normalidad, especialmente si el tamaño de la muestra es lo suficientemente grande. Además, es posible aplicar transformaciones a los datos o ajustar modelos alternativos que se adapten mejor a la estructura de los residuales. En resumen, un modelo ARIMA con residuales sin correlación y una distribución no normal aún puede ser valioso para el análisis de series de tiempo y la toma de decisiones, siempre y cuando se comprendan sus limitaciones y se realicen verificaciones adecuadas de su rendimiento.

Impacto de eventos nacionales e internacionales

A lo largo de la serie de tiempo que representa el precio del dólar en Colombia, se observa cómo diversos eventos nacionales e internacionales han tenido un impacto significativo en su comportamiento. En 2002, la ruptura de diálogos con las FARC bajo el gobierno de Pastrana generó un aumento en el precio del dólar, reflejando la incertidumbre política y la percepción de riesgo en el país en ese momento.

Por otro lado, la implementación de la reforma tributaria durante el mandato de Uribe en 2003 contribuyó a una disminución en el precio del dólar, ya que las políticas económicas pueden influir en la demanda y oferta de divisas. Además, la crisis financiera global de 2008 tuvo un impacto significativo, provocando una fuerte caída en el precio del dólar a nivel mundial, incluyendo a Colombia.

En años posteriores, eventos como la crisis petrolera en 2015 y la pandemia de COVID-19 en 2020 generaron fluctuaciones importantes en la tasa de cambio, reflejando la vulnerabilidad de la economía colombiana a factores externos. Además, la incertidumbre política, como la segunda vuelta presidencial y los cambios en la administración gubernamental, también se tradujeron en movimientos notables en el precio del dólar. En particular, el aumento del dólar por encima de 5.000 pesos debido a cuestiones políticas en el gobierno de Petro marcó un hito importante en la serie temporal, destacando la influencia de los eventos políticos en la estabilidad financiera del país. Desde entonces, la tasa de cambio ha experimentado una tendencia a la baja, lo que puede estar relacionado con factores económicos y políticos más recientes.