Series de Timepo

Librerias

library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.3.1
library(quantmod)
## Warning: package 'quantmod' was built under R version 4.3.3
## Loading required package: xts
## Warning: package 'xts' was built under R version 4.3.2
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## Loading required package: TTR
## Warning: package 'TTR' was built under R version 4.3.2
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(plotly)
## Warning: package 'plotly' was built under R version 4.3.2
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
library(tseries)
## Warning: package 'tseries' was built under R version 4.3.3
library(forecast)
## Warning: package 'forecast' was built under R version 4.3.3
library(zoo)
library (TSstudio)
## Warning: package 'TSstudio' was built under R version 4.3.3
library(dplyr)
## 
## ######################### Warning from 'xts' package ##########################
## #                                                                             #
## # The dplyr lag() function breaks how base R's lag() function is supposed to  #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or       #
## # source() into this session won't work correctly.                            #
## #                                                                             #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop           #
## # dplyr from breaking base R's lag() function.                                #
## #                                                                             #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
## #                                                                             #
## ###############################################################################
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:xts':
## 
##     first, last
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggthemes)
## Warning: package 'ggthemes' was built under R version 4.3.3

Datos Tecnoglass

Empresa líder en la transformación de vidrio arquitectónico y productos de aluminio para la industria global de la construcción. Tiene su sede en Barranquilla, Colombia, y cuenta con operaciones en 19 países.

ticker <- "TGLS"
getSymbols(ticker, src = "yahoo")
## [1] "TGLS"
TGLS_data <- data.frame(Date = index(TGLS), TGLS.Open = TGLS[, "TGLS.Open"],
                        TGLS.High = TGLS[, "TGLS.High"], TGLS.Low = TGLS[, "TGLS.Low"],
                        TGLS.Close = TGLS[, "TGLS.Close"])
head(TGLS_data)
##                  Date TGLS.Open TGLS.High TGLS.Low TGLS.Close
## 2012-05-10 2012-05-10      9.97     10.00     9.50       9.80
## 2012-05-11 2012-05-11      9.70      9.70     9.70       9.70
## 2012-05-14 2012-05-14      9.80      9.80     9.80       9.80
## 2012-05-15 2012-05-15      9.75      9.75     9.75       9.75
## 2012-05-16 2012-05-16      9.75      9.75     9.75       9.75
## 2012-05-17 2012-05-17      9.60      9.60     9.60       9.60

Resumen Estadístico

summary(TGLS_data)
##       Date              TGLS.Open        TGLS.High         TGLS.Low    
##  Min.   :2012-05-10   Min.   : 2.440   Min.   : 2.540   Min.   : 2.15  
##  1st Qu.:2015-05-04   1st Qu.: 8.825   1st Qu.: 8.975   1st Qu.: 8.69  
##  Median :2018-04-24   Median :10.200   Median :10.300   Median :10.16  
##  Mean   :2018-04-23   Mean   :14.692   Mean   :14.969   Mean   :14.41  
##  3rd Qu.:2021-04-14   3rd Qu.:14.880   3rd Qu.:15.020   3rd Qu.:14.57  
##  Max.   :2024-04-05   Max.   :53.860   Max.   :54.400   Max.   :53.38  
##    TGLS.Close   
##  Min.   : 2.29  
##  1st Qu.: 8.84  
##  Median :10.18  
##  Mean   :14.69  
##  3rd Qu.:14.85  
##  Max.   :53.94

Gráfico de Línea

ggplot(TGLS_data, aes(x = Date, y = TGLS.Close)) +
  geom_line(color = "blue") +
  labs(title = "Precio de cierre diario de la Acción TGLS",
       x = "Fecha",
       y = "Precio de cierre (USD), miles") +
  theme_minimal()

Esta gráfica parece representar el precio en miles de USD de la acción de Tecnoglass en función del tiempo, desde mayo de 2012 hasta marzo de 2024. El eje vertical (Y) muestra el precio de cierre. La tendencia del precio comienza con fluctuaciones menores alrededor de 10, luego desciende lentamente hasta alcanzar un punto bajo cercano a 3 a comienzos de 2020. Después de este punto bajo, hay un fuerte incremento en el precio que alcanza una cota superior justo por encima de 50 a principios de 2023. Posteriormente, el precio vuelve a fluctuar pero se mantiene mayormente por encima del valor de 45 hasta marzo de 2024.

Gráfico de Velas

plot_ly(TGLS_data, x = ~Date, type = "candlestick",
        open = ~TGLS.Open, high = ~TGLS.High, low = ~TGLS.Low, close = ~TGLS.Close) %>%
  layout(title = "Gráfico interactivo de velas de la Acción TGLS",
         xaxis = list(title = "Fecha"),
         yaxis = list(title = "Precio de cierre (USD)"))

El grafíco de velas claramente muestra la misma tendencia del grafíco de lineas. Aquí se puede visualizar información sobre los cambios de precios que se producen en índices bursátiles de TGLS

Prueba de Dickey-Fuller

H_0: la serie de tiempo no es estacionaria H_1: la serie de tiempo es estacionaria

TGLS_Close <- TGLS_data$TGLS.Close
adf_result <- adf.test(TGLS_Close)
adf_result
## 
##  Augmented Dickey-Fuller Test
## 
## data:  TGLS_Close
## Dickey-Fuller = -0.51329, Lag order = 14, p-value = 0.9812
## alternative hypothesis: stationary

Dado que el p_valor es > 0.05 no rechazamos nuestra hipótesis inicial con una significancia de 0.05, por tanto, esto se trata de una serie no estacionaria.

acf(TGLS_data$TGLS.Close, lag.max = 1000, main = "Función de Autocorrelación",  ylim = c(-1, 1))

El gráfico ACF muestra que la correlación de la serie con sus rezagos disminuye lentamente, lo que podría implicar la presencia de una dependencia a largo plazo o una tendencia en la serie temporal.

par(mfrow=c(2, 3))
plot(diff(TGLS_data$TGLS.Close), main = "1st Order Diff", ylab = "")
acf(diff(TGLS_data$TGLS.Close), main = "ACF for 1st Order Diffe", lag.max = 800, ylim = c(-1, 1), ylab = "")
pacf(diff(TGLS_data$TGLS.Close), main = "PACF for 1st Order Diff", ylim = c(-1, 1), ylab = "")

plot(diff(diff(TGLS_data$TGLS.Close)), main = "2nd Order Diff", ylab = "")
acf(diff(diff(TGLS_data$TGLS.Close)), main = "ACF for 2nd Order Diff", lag.max = 800, ylim = c(-1, 1), ylab = "")
pacf(diff(diff(TGLS_data$TGLS.Close)), main = "PACF for 2nd Order Diff", ylim = c(-1, 1), ylab = "")

Nótese el decaimiento geométrico en la primera figura de autocorrelación, que baja desde la parte positiva con una tendencia lineal, el cual se interpreta como una autocorrelación asociada a una serie de tiempo no estacionaría, como indica la prueba de Dickey-Fuller. Al observar el gráfico de autocorrelación para la segunda diferenciación, la segunda autocorrelación entra en la zona negativa con bastante rapidez, lo que indica que la serie podría haber sido sobrediferenciada por tanto, nos quedamos con diferenciacion de primer orden

n_TGLS <- length(TGLS_data$TGLS.Close)
n_test <- 14
data<-TGLS_data$TGLS.Close
train_size <- n_TGLS - n_test

train <- TGLS_data$TGLS.Close[1:train_size]
dates_train <- TGLS_data$TGLS.date[1:train_size]
length(train)
## [1] 2981
test_2w <- TGLS_data$TGLS.Close[(train_size + 1):(train_size + n_test)]
dates_2w <- TGLS_data$TGLS.date[(train_size + 1):(train_size + n_test)]

print(paste("train:", length(train)))
## [1] "train: 2981"
print(paste("test_2w:", length(test_2w)))
## [1] "test_2w: 14"
train_df <- TGLS_data[["close"]][1:train_size]
test_2w_df <- TGLS_data[["TGLS.Close"]][(train_size + 1):(train_size + n_test)]
test_2w_df
##  [1] 45.42 47.55 50.43 52.90 52.26 53.47 53.60 52.68 52.03 51.55 50.75 52.58
## [13] 52.46 53.94

MODELO ARIMA

FORECAST CON HORIZONTE 14

arima_model <- auto.arima(data)
arima_model
## Series: data 
## ARIMA(2,1,2) 
## 
## Coefficients:
##           ar1      ar2     ma1     ma2
##       -1.0376  -0.9525  1.0462  0.9317
## s.e.   0.0201   0.0206  0.0247  0.0234
## 
## sigma^2 = 0.3607:  log likelihood = -2719.68
## AIC=5449.37   AICc=5449.39   BIC=5479.39
summary(arima_model)
## Series: data 
## ARIMA(2,1,2) 
## 
## Coefficients:
##           ar1      ar2     ma1     ma2
##       -1.0376  -0.9525  1.0462  0.9317
## s.e.   0.0201   0.0206  0.0247  0.0234
## 
## sigma^2 = 0.3607:  log likelihood = -2719.68
## AIC=5449.37   AICc=5449.39   BIC=5479.39
## 
## Training set error measures:
##                      ME      RMSE       MAE         MPE     MAPE     MASE
## Training set 0.01483875 0.6000438 0.2895799 0.007416315 1.805544 1.001643
##                     ACF1
## Training set 0.003926832
AIC_value <- AIC(arima_model)
BIC_value <- BIC(arima_model)



AIC_order <- arima_model$arma[c(1,6)]
BIC_order <- arima_model$arma[c(2,7)]


HQIC_value <- AIC(arima_model, k = log(length(train)))
HQIC_order <- arima_model$arma[c(3,8)]



print(paste("HQIC:", HQIC_value))
## [1] "HQIC: 5479.36874504143"
print("AIC Order:")
## [1] "AIC Order:"
print(AIC_order)
## [1] 2 1
print("BIC Order:")
## [1] "BIC Order:"
print(BIC_order)
## [1] 2 0
print("HQIC Order:")
## [1] "HQIC Order:"
print(HQIC_order)
## [1]  0 NA
  1. Modelo ARIMA: El modelo identificado es un ARIMA(0,1,0). Esto es un modelo de “random walk” sin constantes. El término ARIMA(0,1,0) indica que no hay componentes AR (Auto-Regressive) o MA (Moving Average) en el modelo, y que está diferenciando los datos una vez para hacer la serie temporal estacionaria.

  2. Estadísticas de bondad de ajuste:

    • log likelihood = -2680.93 sugiere el logaritmo de la verosimilitud del modelo ajustado.
    • AIC = 5363.87 y AICc = 5363.87 son relativamente grandes, lo que puede indicar que el modelo podría mejorarse (menos es mejor).
    • BIC = 5369.87 es otra medida de bondad de ajuste que penaliza más fuertemente modelos con más parámetros.
  3. Medidas de error:

    • ME: Promedio de los residuos. En este caso, es bastante bajo, 0.01106655.
    • RMSE: Mide la desviación de las predicciones del modelo de los valores reales. Aquí es 0.596425.
    • MAE (Error absoluto medio): Promedio de los valores absolutos de los errores. Es 0.2844515.
    • MPE (Error porcentual medio): Muestra el porcentaje promedio que las predicciones del modelo se desviaron de los valores reales. Es muy cercano a cero, lo que es bueno.
    • MAPE: Mide la precisión como un porcentaje. Es 1.790757.
    • MASE (Error absoluto medio escalado): Aquí es 0.9996751, lo que sugiere que este modelo es apenas mejor que un modelo naive.

Forecast del precio de la acción de TGLS

forecast_values <- forecast(arima_model, h = 14)
predictions <- forecast_values$mean
predictions
## Time Series:
## Start = 2996 
## End = 3009 
## Frequency = 1 
##  [1] 54.10021 54.10749 53.94734 54.10657 54.09389 53.95539 54.11118 54.08144
##  [9] 53.96392 54.11418 54.07021 53.97271 54.11575 54.06019
accuracy(forecast_values, x = test_2w)
##                       ME      RMSE       MAE          MPE     MAPE     MASE
## Training set  0.01483875 0.6000438 0.2895799  0.007416315 1.805544 1.001643
## Test set     -2.51289090 3.4229550 2.5128909 -5.103525221 5.103525 8.691970
##                     ACF1
## Training set 0.003926832
## Test set              NA
print(paste("Observados:", test_2w, "Predichos:", predictions))
##  [1] "Observados: 45.4199981689453 Predichos: 54.1002065742126"
##  [2] "Observados: 47.5499992370605 Predichos: 54.1074855996967"
##  [3] "Observados: 50.4300003051758 Predichos: 53.9473425322915"
##  [4] "Observados: 52.9000015258789 Predichos: 54.1065726171366"
##  [5] "Observados: 52.2599983215332 Predichos: 54.0938855315121"
##  [6] "Observados: 53.4700012207031 Predichos: 53.9553904891866"
##  [7] "Observados: 53.5999984741211 Predichos: 54.1111755445131"
##  [8] "Observados: 52.6800003051758 Predichos: 54.0814442809504"
##  [9] "Observados: 52.0299987792969 Predichos: 53.9639153506455"
## [10] "Observados: 51.5499992370605 Predichos: 54.1141799215741"
## [11] "Observados: 50.75 Predichos: 54.0702074430308"           
## [12] "Observados: 52.5800018310547 Predichos: 53.9727130671645"
## [13] "Observados: 52.4599990844727 Predichos: 54.1157540411748"
## [14] "Observados: 53.939998626709 Predichos: 54.0601947460011"

note que los valores predichos se mantienen en 42.680 y si bien se acerca alguno de los valores observados no es una buena prediccion general ya que se mantiene constante como se puede visualizar en el siguiente gráfico

plot_forecast(forecast_values,
              title = "Forecast",
              Xtitle = "year",
              Ytitle = "Miles de Dolares")
comparison_data <- data.frame(Observación_Real = test_2w, Predicción = predictions)
ggplot(comparison_data, aes(x = Observación_Real, y = Predicción)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  labs(title = "Correlación entre Observación Real y Predicción",
       x = "Observación Real",
       y = "Predicción") +
  theme_minimal()
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.
## `geom_smooth()` using formula = 'y ~ x'

Aqui podemos visualizar el comportamiento constante de la predicción con respecto a los datos reales.

Errores

checkresiduals(arima_model)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(2,1,2)
## Q* = 17.837, df = 6, p-value = 0.006653
## 
## Model df: 4.   Total lags used: 10

Gráfico de Residuos: Muestra los residuos Parecen centrarse alrededor de cero sin patrones claros o tendencias, lo cual es un buen indicio. Sin embargo, hay algunos picos que indican posibles valores atípicos o fluctuaciones anormales que el modelo no ha capturado.

Gráfico de Función de Autocorrelación (ACF): En este gráfico, la mayoría de las barras están dentro de los límites, lo que sugiere que no hay problemas significativos de autocorrelación.

  1. Histograma y Gráfico Q-Q: La distribución parece aproximadamente normal, pero con algunos datos que se desvían de la línea en el gráfico Q-Q, lo que podría indicar desviaciones leves de la normalidad.

  2. Prueba de Ljung-Box: El resultado de p-value = 4.104e-05 es menor que el nivel de significancia típico de 0.05, lo que sugiere que hay evidencia de autocorrelaciones residuales significativas a los 10 lags considerados, contradiciendo ligeramente lo que sugiere el gráfico ACF.

FORECAST CON HORIZONTE 21

n_TGLS <- length(TGLS_data$TGLS.Close)
n_test <- 21

train_size <- n_TGLS - n_test

train <- TGLS_data$TGLS.Close[1:train_size]
dates_train <- TGLS_data$TGLS.date[1:train_size]
length(train)
## [1] 2974
test_2w <- TGLS_data$TGLS.Close[(train_size + 1):(train_size + n_test)]
dates_2w <- TGLS_data$TGLS.date[(train_size + 1):(train_size + n_test)]

print(paste("train:", length(train)))
## [1] "train: 2974"
print(paste("test_2w:", length(test_2w)))
## [1] "test_2w: 21"
train_df <- TGLS_data[["close"]][1:train_size]
test_2w_df <- TGLS_data[["TGLS.Close"]][(train_size + 1):(train_size + n_test)]
test_2w_df
##  [1] 45.01 44.88 44.65 45.00 45.58 45.46 45.80 45.42 47.55 50.43 52.90 52.26
## [13] 53.47 53.60 52.68 52.03 51.55 50.75 52.58 52.46 53.94

MODELO ARIMA

arima_model21 <- auto.arima(data)
arima_model21
## Series: data 
## ARIMA(2,1,2) 
## 
## Coefficients:
##           ar1      ar2     ma1     ma2
##       -1.0376  -0.9525  1.0462  0.9317
## s.e.   0.0201   0.0206  0.0247  0.0234
## 
## sigma^2 = 0.3607:  log likelihood = -2719.68
## AIC=5449.37   AICc=5449.39   BIC=5479.39
summary(arima_model21)
## Series: data 
## ARIMA(2,1,2) 
## 
## Coefficients:
##           ar1      ar2     ma1     ma2
##       -1.0376  -0.9525  1.0462  0.9317
## s.e.   0.0201   0.0206  0.0247  0.0234
## 
## sigma^2 = 0.3607:  log likelihood = -2719.68
## AIC=5449.37   AICc=5449.39   BIC=5479.39
## 
## Training set error measures:
##                      ME      RMSE       MAE         MPE     MAPE     MASE
## Training set 0.01483875 0.6000438 0.2895799 0.007416315 1.805544 1.001643
##                     ACF1
## Training set 0.003926832
AIC_value <- AIC(arima_model21)
BIC_value <- BIC(arima_model21)
HQIC_value <- AIC(arima_model21, k = log(length(train)))


AIC_order <- arima_model21$arma[c(1,6)]
BIC_order <- arima_model21$arma[c(2,7)]
HQIC_order <- arima_model21$arma[c(3,8)]


print(paste("AIC:", AIC_value))
## [1] "AIC: 5449.36867457304"
print(paste("BIC:", BIC_value))
## [1] "BIC: 5479.39050239794"
print(paste("HQIC:", HQIC_value))
## [1] "HQIC: 5479.35699020814"
print("AIC Order:")
## [1] "AIC Order:"
print(AIC_order)
## [1] 2 1
print("BIC Order:")
## [1] "BIC Order:"
print(BIC_order)
## [1] 2 0
print("HQIC Order:")
## [1] "HQIC Order:"
print(HQIC_order)
## [1]  0 NA

Forecast del precio de la acción de TGLS

forecast_values21 <- forecast(arima_model21, h = 21)
print(paste("Observados:", test_2w, "Predichos:", predictions))
##  [1] "Observados: 45.0099983215332 Predichos: 54.1002065742126"
##  [2] "Observados: 44.8800010681152 Predichos: 54.1074855996967"
##  [3] "Observados: 44.6500015258789 Predichos: 53.9473425322915"
##  [4] "Observados: 45 Predichos: 54.1065726171366"              
##  [5] "Observados: 45.5800018310547 Predichos: 54.0938855315121"
##  [6] "Observados: 45.4599990844727 Predichos: 53.9553904891866"
##  [7] "Observados: 45.7999992370605 Predichos: 54.1111755445131"
##  [8] "Observados: 45.4199981689453 Predichos: 54.0814442809504"
##  [9] "Observados: 47.5499992370605 Predichos: 53.9639153506455"
## [10] "Observados: 50.4300003051758 Predichos: 54.1141799215741"
## [11] "Observados: 52.9000015258789 Predichos: 54.0702074430308"
## [12] "Observados: 52.2599983215332 Predichos: 53.9727130671645"
## [13] "Observados: 53.4700012207031 Predichos: 54.1157540411748"
## [14] "Observados: 53.5999984741211 Predichos: 54.0601947460011"
## [15] "Observados: 52.6800003051758 Predichos: 54.1002065742126"
## [16] "Observados: 52.0299987792969 Predichos: 54.1074855996967"
## [17] "Observados: 51.5499992370605 Predichos: 53.9473425322915"
## [18] "Observados: 50.75 Predichos: 54.1065726171366"           
## [19] "Observados: 52.5800018310547 Predichos: 54.0938855315121"
## [20] "Observados: 52.4599990844727 Predichos: 53.9553904891866"
## [21] "Observados: 53.939998626709 Predichos: 54.1111755445131"
plot_forecast(forecast_values21,
              title = "Forecast",
              Xtitle = "year",
              Ytitle = "Miles de Dolares")
# Extracción de las predicciones
predictions <- forecast_values21$mean
predictions
## Time Series:
## Start = 2996 
## End = 3016 
## Frequency = 1 
##  [1] 54.10021 54.10749 53.94734 54.10657 54.09389 53.95539 54.11118 54.08144
##  [9] 53.96392 54.11418 54.07021 53.97271 54.11575 54.06019 53.98160 54.11607
## [17] 54.05140 53.99043 54.11528 54.04381 53.99905
# Crear un dataframe con las observaciones reales y las predicciones
comparison_data <- data.frame(Observación_Real = test_2w, Predicción = predictions)
# Graficar la correlación entre la observación real y la predicción
ggplot(comparison_data, aes(x = Observación_Real, y = Predicción)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  labs(title = "Correlación entre Observación Real y Predicción",
       x = "Observación Real",
       y = "Predicción") +
  theme_minimal()
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.
## `geom_smooth()` using formula = 'y ~ x'

El modelo con 2 términos autorregresivos (AR), una diferenciación para hacer la serie temporal estacionaria y 2 términos de media móvil (MA), con un término adicional que representa una tendencia constante a lo largo del tiempo.

Estadísticas de bondad de ajuste:

Medidas de error:

El término ACF1 de -0.007330726 indica que la primera autocorrelación de los errores es muy baja, lo cual es deseable y sugiere que el modelo está capturando adecuadamente la estructura de dependencia en los datos.

Forecast:

Los valores predichos muestran un comportamiento prácticamente constante, con una variación mínima, lo cual se puede visualizar en la gráfica.

Errores

checkresiduals(arima_model21)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(2,1,2)
## Q* = 17.837, df = 6, p-value = 0.006653
## 
## Model df: 4.   Total lags used: 10

Prueba de Ljung-Box: La prueba da un valor de p = 0.01585, que es menor que 0.05, indicando que hay evidencia estadística de autocorrelaciones residuales significativas en los residuos a 10 lags. Esto sugiere que, a pesar de que la ACF no mostraba claras autocorrelaciones significativas, al realizar un test más riguroso, se detecta dependencia entre los residuos que no ha sido capturada por el modelo.

FORECAST CON HORIZONTE 28

n_TGLS <- length(TGLS_data$TGLS.Close)
n_test <- 28

train_size <- n_TGLS - n_test

train <- TGLS_data$TGLS.Close[1:train_size]
dates_train <- TGLS_data$TGLS.date[1:train_size]
length(train)
## [1] 2967
test_2w <- TGLS_data$TGLS.Close[(train_size + 1):(train_size + n_test)]
dates_2w <- TGLS_data$TGLS.date[(train_size + 1):(train_size + n_test)]

print(paste("train:", length(train)))
## [1] "train: 2967"
print(paste("test_2w:", length(test_2w)))
## [1] "test_2w: 28"
train_df <- TGLS_data[["close"]][1:train_size]
test_2w_df <- TGLS_data[["TGLS.Close"]][(train_size + 1):(train_size + n_test)]
test_2w_df
##  [1] 46.15 46.51 46.76 44.80 42.68 44.25 44.53 45.01 44.88 44.65 45.00 45.58
## [13] 45.46 45.80 45.42 47.55 50.43 52.90 52.26 53.47 53.60 52.68 52.03 51.55
## [25] 50.75 52.58 52.46 53.94

MODELO ARIMA

arima_model28 <- auto.arima(data)
arima_model28
## Series: data 
## ARIMA(2,1,2) 
## 
## Coefficients:
##           ar1      ar2     ma1     ma2
##       -1.0376  -0.9525  1.0462  0.9317
## s.e.   0.0201   0.0206  0.0247  0.0234
## 
## sigma^2 = 0.3607:  log likelihood = -2719.68
## AIC=5449.37   AICc=5449.39   BIC=5479.39
summary(arima_model28)
## Series: data 
## ARIMA(2,1,2) 
## 
## Coefficients:
##           ar1      ar2     ma1     ma2
##       -1.0376  -0.9525  1.0462  0.9317
## s.e.   0.0201   0.0206  0.0247  0.0234
## 
## sigma^2 = 0.3607:  log likelihood = -2719.68
## AIC=5449.37   AICc=5449.39   BIC=5479.39
## 
## Training set error measures:
##                      ME      RMSE       MAE         MPE     MAPE     MASE
## Training set 0.01483875 0.6000438 0.2895799 0.007416315 1.805544 1.001643
##                     ACF1
## Training set 0.003926832
AIC_value <- AIC(arima_model28)
BIC_value <- BIC(arima_model28)
HQIC_value <- AIC(arima_model28, k = log(length(train)))


AIC_order <- arima_model28$arma[c(1,6)]
BIC_order <- arima_model28$arma[c(2,7)]
HQIC_order <- arima_model28$arma[c(3,8)]


print(paste("AIC:", AIC_value))
## [1] "AIC: 5449.36867457304"
print(paste("BIC:", BIC_value))
## [1] "BIC: 5479.39050239794"
print(paste("HQIC:", HQIC_value))
## [1] "HQIC: 5479.3452076745"
print("AIC Order:")
## [1] "AIC Order:"
print(AIC_order)
## [1] 2 1
print("BIC Order:")
## [1] "BIC Order:"
print(BIC_order)
## [1] 2 0
print("HQIC Order:")
## [1] "HQIC Order:"
print(HQIC_order)
## [1]  0 NA

Forecast del precio de la acción de TGLS

forecast_values28 <- forecast(arima_model28, h = 28)
predictions <- forecast_values28$mean
accuracy(forecast_values28, x = test_2w)
##                       ME      RMSE       MAE           MPE      MAPE      MASE
## Training set  0.01483875 0.6000438 0.2895799   0.007416315  1.805544  1.001643
## Test set     -5.70867002 6.7832007 5.7086700 -12.443218164 12.443218 19.746018
##                     ACF1
## Training set 0.003926832
## Test set              NA
print(paste("Observados:", test_2w, "Predichos:", predictions))
##  [1] "Observados: 46.1500015258789 Predichos: 54.1002065742126"
##  [2] "Observados: 46.5099983215332 Predichos: 54.1074855996967"
##  [3] "Observados: 46.7599983215332 Predichos: 53.9473425322915"
##  [4] "Observados: 44.7999992370605 Predichos: 54.1065726171366"
##  [5] "Observados: 42.6800003051758 Predichos: 54.0938855315121"
##  [6] "Observados: 44.25 Predichos: 53.9553904891866"           
##  [7] "Observados: 44.5299987792969 Predichos: 54.1111755445131"
##  [8] "Observados: 45.0099983215332 Predichos: 54.0814442809504"
##  [9] "Observados: 44.8800010681152 Predichos: 53.9639153506455"
## [10] "Observados: 44.6500015258789 Predichos: 54.1141799215741"
## [11] "Observados: 45 Predichos: 54.0702074430308"              
## [12] "Observados: 45.5800018310547 Predichos: 53.9727130671645"
## [13] "Observados: 45.4599990844727 Predichos: 54.1157540411748"
## [14] "Observados: 45.7999992370605 Predichos: 54.0601947460011"
## [15] "Observados: 45.4199981689453 Predichos: 53.9816028779864"
## [16] "Observados: 47.5499992370605 Predichos: 54.1160666688405"
## [17] "Observados: 50.4300003051758 Predichos: 54.0514032462529"
## [18] "Observados: 52.9000015258789 Predichos: 53.990427096273" 
## [19] "Observados: 52.2599983215332 Predichos: 54.1152842226651"
## [20] "Observados: 53.4700012207031 Predichos: 54.0438104590461"
## [21] "Observados: 53.5999984741211 Predichos: 53.9990505467051"
## [22] "Observados: 52.6800003051758 Predichos: 54.1135683749867"
## [23] "Observados: 52.0299987792969 Predichos: 54.0373773826475"
## [24] "Observados: 51.5499992370605 Predichos: 54.0073597119529"
## [25] "Observados: 50.75 Predichos: 54.1110740576552"           
## [26] "Observados: 52.5800018310547 Predichos: 54.0320513809941"
## [27] "Observados: 52.4599990844727 Predichos: 54.0152616415377"
## [28] "Observados: 53.939998626709 Predichos: 54.1079478485877"
plot_forecast(forecast_values28,
              title = "Forecast",
              Xtitle = "year",
              Ytitle = "Miles de Dolares")
# Crear un dataframe con las observaciones reales y las predicciones
comparison_data <- data.frame(Observación_Real = test_2w, Predicción = predictions)
# Graficar la correlación entre la observación real y la predicción
ggplot(comparison_data, aes(x = Observación_Real, y = Predicción)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  labs(title = "Correlación entre Observación Real y Predicción",
       x = "Observación Real",
       y = "Predicción") +
  theme_minimal()
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.
## `geom_smooth()` using formula = 'y ~ x'

Modelo ARIMA: El modelo ajustado es un ARIMA(2,1,2), lo que indica dos términos autorregresivos (AR), una diferencia (I) para hacer la serie temporal estacionaria y dos términos de media móvil (MA). Los coeficientes autorregresivos son -1.0374 para ar1 y -0.9451 para ar2, y los coeficientes de media móvil son 1.0469 para ma1 y 0.9241 para ma2. Los coeficientes son significativos dado sus pequeños errores estándar asociados.

Estadísticas de bondad de ajuste:

Medidas de error del conjunto de entrenamiento:

ACF1 (Autocorrelación de primer orden de los residuos) = -0.009187806: Idealmente cerca de cero, lo que en este caso sugiere que no hay autocorrelación significativa en los residuos y que el modelo está capturando adecuadamente la estructura de dependencia en los datos.

Forecast: De nuevo, se predicen valores con poca variación (al rededor del 43.3) ## Errores

checkresiduals(arima_model28)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(2,1,2)
## Q* = 17.837, df = 6, p-value = 0.006653
## 
## Model df: 4.   Total lags used: 10

Prueba de Ljung-Box: La prueba arroja un valor de p = 0.01206, que está por debajo del umbral de significancia común de 0.05, lo que indica la presencia de autocorrelaciones en los residuos.

Comparación de Modelos

El modelo con una ventana de 28 días muestra una ligera ventaja en las estadísticas de bondad de ajuste, pero los tres modelos exhiben una precisión predictiva similar. Esto sugiere que, aunque el modelo de 28 días podría capturar la dinámica subyacente ligeramente mejor, la diferencia en el rendimiento predictivo no parece ser significativa en la práctica. Todos los modelos muestran evidencia de autocorrelaciones residuales y tienen residuos que parecen seguir una distribución razonablemente normal, aunque con algunos valores atípicos.

Rolling Forecast

rolling_forecast_single <- function(train_data, horizon) {
  
  train_data <- TGLS_data$TGLS.Close[1:(n_TGLS - horizon)]
  test_data <- TGLS_data$TGLS.Close[(n_TGLS - horizon + 1):n_TGLS]
  arima_model <- auto.arima(train_data)
  
  checkresiduals(arima_model)
  
  forecast_values <- forecast(arima_model, h = horizon)
  
  predicted <- forecast_values$mean
  observed <- test_data
  
  
  accuracy_metrics <- accuracy(forecast_values,x = observed)
  
  aic <- AIC(arima_model)
  bic <- BIC(arima_model)
  
  results_df <- data.frame(
    Horizon = horizon,
    AIC = aic,
    BIC = bic,
    MAPE = accuracy_metrics[2, "MAPE"],
    RMSE = accuracy_metrics[2, "RMSE"],
    ME = accuracy_metrics[2, "ME"]
  )
  
  
  return(list(predicted = predicted, results_df = results_df, forecast_values = forecast_values))
}

Rolling FORECAST CON HORIZONTE 14

horizon <- 14
forecast_result <- rolling_forecast_single(train_data, horizon)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(2,1,2) with drift
## Q* = 15.263, df = 6, p-value = 0.01831
## 
## Model df: 4.   Total lags used: 10
forecast<-forecast_result$forecast_values
print(forecast_result$results_df)
##   Horizon      AIC      BIC     MAPE     RMSE       ME
## 1      14 5358.536 5394.534 10.85934 6.060746 5.611865
forecast<-forecast_result$forecast_values
predictions <- forecast_values$mean
print(paste("Observados:", test_2w, "Predichos:", predictions))
##  [1] "Observados: 46.1500015258789 Predichos: 54.1002065742126"
##  [2] "Observados: 46.5099983215332 Predichos: 54.1074855996967"
##  [3] "Observados: 46.7599983215332 Predichos: 53.9473425322915"
##  [4] "Observados: 44.7999992370605 Predichos: 54.1065726171366"
##  [5] "Observados: 42.6800003051758 Predichos: 54.0938855315121"
##  [6] "Observados: 44.25 Predichos: 53.9553904891866"           
##  [7] "Observados: 44.5299987792969 Predichos: 54.1111755445131"
##  [8] "Observados: 45.0099983215332 Predichos: 54.0814442809504"
##  [9] "Observados: 44.8800010681152 Predichos: 53.9639153506455"
## [10] "Observados: 44.6500015258789 Predichos: 54.1141799215741"
## [11] "Observados: 45 Predichos: 54.0702074430308"              
## [12] "Observados: 45.5800018310547 Predichos: 53.9727130671645"
## [13] "Observados: 45.4599990844727 Predichos: 54.1157540411748"
## [14] "Observados: 45.7999992370605 Predichos: 54.0601947460011"
## [15] "Observados: 45.4199981689453 Predichos: 54.1002065742126"
## [16] "Observados: 47.5499992370605 Predichos: 54.1074855996967"
## [17] "Observados: 50.4300003051758 Predichos: 53.9473425322915"
## [18] "Observados: 52.9000015258789 Predichos: 54.1065726171366"
## [19] "Observados: 52.2599983215332 Predichos: 54.0938855315121"
## [20] "Observados: 53.4700012207031 Predichos: 53.9553904891866"
## [21] "Observados: 53.5999984741211 Predichos: 54.1111755445131"
## [22] "Observados: 52.6800003051758 Predichos: 54.0814442809504"
## [23] "Observados: 52.0299987792969 Predichos: 53.9639153506455"
## [24] "Observados: 51.5499992370605 Predichos: 54.1141799215741"
## [25] "Observados: 50.75 Predichos: 54.0702074430308"           
## [26] "Observados: 52.5800018310547 Predichos: 53.9727130671645"
## [27] "Observados: 52.4599990844727 Predichos: 54.1157540411748"
## [28] "Observados: 53.939998626709 Predichos: 54.0601947460011"
plot_forecast(forecast,
              title = "Forecast",
              Xtitle = "year",
              Ytitle = "Miles de Dolares")

AIC: 5352.497, BIC: 5382.487son bastante altos, lo que sugiere que el modelo podría ser más eficiente. MAPE (Error Porcentual Absoluto Medio): 2.54692% está en un rango razonable. MSE (Raíz del Error Cuadrático Medio) 5.54529 ME(Error Medio):4.266455 parece ser un valor bastante alto.

Rolling FORECAST CON HORIZONTE 21

horizon21<- 21
forecast_result21 <- rolling_forecast_single(train_data, horizon21)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(2,1,2)
## Q* = 15.506, df = 6, p-value = 0.01667
## 
## Model df: 4.   Total lags used: 10
forecast21<-forecast_result21$forecast_values
print(forecast_result21$results_df)
##   Horizon      AIC      BIC     MAPE     RMSE       ME
## 1      21 5349.877 5379.863 9.421123 6.039575 4.890664
# forecast_values
forecast21<-forecast_result21$forecast_values
predictions21 <- forecast_values21$mean
print(paste("Observados:", test_2w, "Predichos:", predictions21))
##  [1] "Observados: 46.1500015258789 Predichos: 54.1002065742126"
##  [2] "Observados: 46.5099983215332 Predichos: 54.1074855996967"
##  [3] "Observados: 46.7599983215332 Predichos: 53.9473425322915"
##  [4] "Observados: 44.7999992370605 Predichos: 54.1065726171366"
##  [5] "Observados: 42.6800003051758 Predichos: 54.0938855315121"
##  [6] "Observados: 44.25 Predichos: 53.9553904891866"           
##  [7] "Observados: 44.5299987792969 Predichos: 54.1111755445131"
##  [8] "Observados: 45.0099983215332 Predichos: 54.0814442809504"
##  [9] "Observados: 44.8800010681152 Predichos: 53.9639153506455"
## [10] "Observados: 44.6500015258789 Predichos: 54.1141799215741"
## [11] "Observados: 45 Predichos: 54.0702074430308"              
## [12] "Observados: 45.5800018310547 Predichos: 53.9727130671645"
## [13] "Observados: 45.4599990844727 Predichos: 54.1157540411748"
## [14] "Observados: 45.7999992370605 Predichos: 54.0601947460011"
## [15] "Observados: 45.4199981689453 Predichos: 53.9816028779864"
## [16] "Observados: 47.5499992370605 Predichos: 54.1160666688405"
## [17] "Observados: 50.4300003051758 Predichos: 54.0514032462529"
## [18] "Observados: 52.9000015258789 Predichos: 53.990427096273" 
## [19] "Observados: 52.2599983215332 Predichos: 54.1152842226651"
## [20] "Observados: 53.4700012207031 Predichos: 54.0438104590461"
## [21] "Observados: 53.5999984741211 Predichos: 53.9990505467051"
## [22] "Observados: 52.6800003051758 Predichos: 54.1002065742126"
## [23] "Observados: 52.0299987792969 Predichos: 54.1074855996967"
## [24] "Observados: 51.5499992370605 Predichos: 53.9473425322915"
## [25] "Observados: 50.75 Predichos: 54.1065726171366"           
## [26] "Observados: 52.5800018310547 Predichos: 54.0938855315121"
## [27] "Observados: 52.4599990844727 Predichos: 53.9553904891866"
## [28] "Observados: 53.939998626709 Predichos: 54.1111755445131"
plot_forecast(forecast21,
              title = "Forecast",
              Xtitle = "year",
              Ytitle = "Miles de Dolares")

Prueba de Ljung-Box: Un valor p de 0.01585, que es menor que 0.05, sugiere la presencia de autocorrelaciones significativas en los residuos, lo que indica que el modelo podría no estar capturando toda la estructura dependiente de los datos.

AIC: 5317.741 y BIC: 5353.715, que aunque son altos, son ligeramente más bajos que los del modelo de 14 días, lo que podría indicar un mejor equilibrio entre la bondad del ajuste y la simplicidad del modelo. MAPE: 6.020419%, que es más alto que en el modelo de 14 días, sugiriendo que el error porcentual promedio es mayor aquí. -RMSE: 3.664671, que es más bajo que en el modelo de 14 días, indicando una menor desviación promedio de las predicciones del modelo de los valores reales. - ME: 0.9406428, que sugiere que en promedio, las predicciones del modelo tienden a estar casi 1 unidad por encima de los valores reales, lo cual es información valiosa para ajustar pronósticos futuros.

Rolling FORECAST CON HORIZONTE 28

horizon28<- 28
forecast_result28 <- rolling_forecast_single(train_data, horizon28)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(2,1,3) with drift
## Q* = 19.136, df = 5, p-value = 0.001813
## 
## Model df: 5.   Total lags used: 10
forecast28<-forecast_result28$forecast_values
print(forecast_result28$results_df)
##   Horizon      AIC      BIC    MAPE     RMSE      ME
## 1      28 5317.284 5359.249 6.46935 3.817999 1.33028
forecast28<-forecast_result28$forecast_values
predictions28 <- forecast_values28$mean
print(paste("Observados:", test_2w, "Predichos:", predictions28))
##  [1] "Observados: 46.1500015258789 Predichos: 54.1002065742126"
##  [2] "Observados: 46.5099983215332 Predichos: 54.1074855996967"
##  [3] "Observados: 46.7599983215332 Predichos: 53.9473425322915"
##  [4] "Observados: 44.7999992370605 Predichos: 54.1065726171366"
##  [5] "Observados: 42.6800003051758 Predichos: 54.0938855315121"
##  [6] "Observados: 44.25 Predichos: 53.9553904891866"           
##  [7] "Observados: 44.5299987792969 Predichos: 54.1111755445131"
##  [8] "Observados: 45.0099983215332 Predichos: 54.0814442809504"
##  [9] "Observados: 44.8800010681152 Predichos: 53.9639153506455"
## [10] "Observados: 44.6500015258789 Predichos: 54.1141799215741"
## [11] "Observados: 45 Predichos: 54.0702074430308"              
## [12] "Observados: 45.5800018310547 Predichos: 53.9727130671645"
## [13] "Observados: 45.4599990844727 Predichos: 54.1157540411748"
## [14] "Observados: 45.7999992370605 Predichos: 54.0601947460011"
## [15] "Observados: 45.4199981689453 Predichos: 53.9816028779864"
## [16] "Observados: 47.5499992370605 Predichos: 54.1160666688405"
## [17] "Observados: 50.4300003051758 Predichos: 54.0514032462529"
## [18] "Observados: 52.9000015258789 Predichos: 53.990427096273" 
## [19] "Observados: 52.2599983215332 Predichos: 54.1152842226651"
## [20] "Observados: 53.4700012207031 Predichos: 54.0438104590461"
## [21] "Observados: 53.5999984741211 Predichos: 53.9990505467051"
## [22] "Observados: 52.6800003051758 Predichos: 54.1135683749867"
## [23] "Observados: 52.0299987792969 Predichos: 54.0373773826475"
## [24] "Observados: 51.5499992370605 Predichos: 54.0073597119529"
## [25] "Observados: 50.75 Predichos: 54.1110740576552"           
## [26] "Observados: 52.5800018310547 Predichos: 54.0320513809941"
## [27] "Observados: 52.4599990844727 Predichos: 54.0152616415377"
## [28] "Observados: 53.939998626709 Predichos: 54.1079478485877"
plot_forecast(forecast28,
              title = "Forecast",
              Xtitle = "year",
              Ytitle = "Miles de Dolares")

-Gráfico de Residuos: El gráfico muestra que los residuos fluctúan alrededor de cero y no parece haber patrones claros o tendencias persistentes. Sin embargo, hay algunos valores extremos notables.

-Gráfico de la Función de Autocorrelación (ACF): Existen varias barras que cruzan los límites de confianza, lo que puede sugerir la presencia de autocorrelación en los residuos a ciertos lags.

Prueba de Ljung-Box: El p-valor es 0.01206, que está por debajo del umbral común de 0.05. Esto significa que hay una significancia estadística en la autocorrelación de los residuos, lo que implica que el modelo podría no estar capturando toda la dependencia en los datos.

-AIC: 5297.55 y BIC: 5327.517 que son los más bajos entre los modelos. Esto sugiere que este modelo tiene un mejor equilibrio entre la complejidad del modelo y su capacidad para explicar los datos. -MAPE: 7.512977%, es el más alto de los modelos que hemos visto, indicando que los errores porcentuales son mayores en promedio para este modelo. - RMSE: 4.999994,sugiere una precisión razonable en términos de desviación de las predicciones del modelo de los valores reales. - ME: 3.676162, que es un error medio alto. Esto podría sugerir una tendencia sistemática en las predicciones del modelo.

Comparación final de Modelos

Los modelos de Rolling forecast parecen tener un mejor equilibrio en términos de estas métricas, lo cual es indicativo de un mejor ajuste general y una capacidad predictiva más fiable a pesar de los valores algo mayores en MAPE y ME, por tanto, aun que el modelo de rolling forecaste con una ventana de 28 tenga los valores mas altos de ME y MAPE, este destaca en términos de AIC/BIC, lo que sugiere un buen ajuste a los datos