Univalle


1. Introducción

La capacidad de anticipar el comportamiento futuro de los precios en los mercados financieros constituye uno de los elementos centrales para la toma de decisiones de inversión estratégicas y la gestión eficiente de portafolios. En el contexto de los mercados bursátiles globales, donde la incertidumbre es inherente y los patrones de precios reflejan complejas dinámicas de oferta y demanda, el desarrollo de modelos predictivos robustos cobra particular relevancia para inversionistas, analistas financieros y gestores de cartera.

El Invesco \(QQQ Trust\) (QQQ) es uno de los fondos cotizados en bolsa (ETF) más negociados a nivel mundial, con activos bajo gestión superiores a los 400 mil millones de dólares. Este instrumento replica el índice \(Nasdaq-100\), compuesto por las 100 empresas no financieras de mayor capitalización bursátil listadas en el mercado Nasdaq, con una fuerte concentración en el sector tecnológico que incluye líderes como \(Apple\), \(Microsoft\), \(NVIDIA\), \(Amazon\) y \(Alphabet\). Entre 2009 y 2019, el \(QQQ\) se benefició significativamente de las economías de escala en software, el auge de los smartphones y el desarrollo de ecosistemas tecnológicos integrados. Esta composición convierte al \(QQQ\) en un referente para analizar el comportamiento del sector tecnológico estadounidense y, por extensión, las tendencias de innovación que impulsan la economía global.

La importancia de modelar series de precios como la del \(QQQ\) radica en múltiples factores. En primer lugar, los pronósticos financieros juegan un papel fundamental en la formación de expectativas de mercado e influyen directamente en las decisiones de inversión, la asignación de activos y la evaluación de riesgos. En segundo lugar, el análisis cuantitativo de series temporales permite identificar patrones y comportamientos que proporcionan información valiosa para diseñar estrategias de inversión más fundamentadas. La predicción específica del \(QQQ\) es particularmente importante porque replica el índice \(Nasdaq-100\), concentrado en empresas tecnológicas líderes en desarrollo de inteligencia artificial, computación en la nube y ecosistemas digitales innovadores. Dado que el sector tecnológico representa uno de los mercados emergentes y con mayor potencial de crecimiento en la economía global, predecir el comportamiento del \(QQQ\) permite anticipar tendencias en innovación, evaluar correctamente la valuación de activos tecnológicos y gestionar la exposición al riesgo en un sector de alta volatilidad que impulsa transformaciones estructurales en la economía mundial.

En este contexto, los modelos \(ARIMA\) (AutoRegressive Integrated Moving Average) se han consolidado como uno de los enfoques más utilizados para el pronóstico de series de tiempo, junto con los modelos de suavizado exponencial. Mientras que los modelos de suavizado exponencial se basan en una descripción de la tendencia y la estacionalidad en los datos, los modelos \(ARIMA\) tienen como objetivo describir las autocorrelaciones presentes en la serie. Estos modelos integran tres componentes fundamentales: el componente autorregresivo (AR), que pronostica la variable de interés utilizando una combinación lineal de sus valores pasados; el componente de integración (I), que transforma series no estacionarias en estacionarias mediante la aplicación de diferencias sucesivas; y el componente de media móvil (MA), que utiliza errores de pronóstico pasados en un modelo similar a la regresión.

Un aspecto fundamental previo al ajuste de modelos \(ARIMA\) es la verificación de la estacionariedad de la serie temporal. Una serie estacionaria es aquella cuyas propiedades no dependen del momento en que se observa; es decir, presenta media aproximadamente horizontal, varianza constante y no muestra patrones predecibles a largo plazo. Las series temporales con tendencias o estacionalidad no son estacionarias. Para identificar series no estacionarias, se emplean tanto herramientas gráficas (la función de autocorrelación ACF de datos no estacionarios decrece lentamente) como pruebas estadísticas formales, entre las que destaca el Test Aumentado de Dickey-Fuller, cuya hipótesis nula establece que los datos son no estacionarios.

El presente estudio emplea datos históricos del ETF \(QQQ\) obtenidos de Yahoo Finance, abarcando el período comprendido entre el 7 de octubre de 2022 y el 2 de diciembre de 2025, con un total de 791 observaciones diarias de precios de cierre. Durante este período, el precio del \(QQQ\) fluctuó entre un mínimo de $260.10 y un máximo de $635.77, con un precio promedio de $435.84 y una desviación estándar de $97.95. El rendimiento acumulado del período alcanzó un notable 131.14%, reflejando la fuerte recuperación del sector tecnológico tras el mercado bajista de 2022 y el impulso generado por desarrollos en inteligencia artificial. La volatilidad anualizada de la serie se ubicó en aproximadamente 21.12%, característica de instrumentos con alta exposición al sector tecnológico.

El análisis incluye la verificación de supuestos estadísticos fundamentales: evaluación de estacionariedad mediante la prueba de \(Dickey-Fuller\) Aumentada y análisis gráfico de las funciones de autocorrelación (ACF) y autocorrelación parcial (PACF), la selección del modelo óptimo utilizando criterios de información (AICc), y la validación diagnóstica de residuos para confirmar que se comporten como ruido blanco. Se comparan múltiples especificaciones \(ARIMA\), incluyendo el modelo seleccionado automáticamente mediante la función auto.arima y configuraciones alternativas sugeridas por el análisis de los gráficos \(ACF\) y \(PACF\), reconociendo que aunque la automatización es útil, “cualquier cosa automatizada puede ser un poco peligrosa, y vale la pena entender algo sobre el comportamiento de los modelos”.


2. Metodología

La metodología adoptada sigue el procedimiento estándar de modelamiento de series temporales propuesto en la literatura Box-Jenkins: se particiona el conjunto de datos en un conjunto de entrenamiento destinado a la estimación de parámetros y validación de modelos candidatos, y un conjunto de prueba para evaluar la capacidad predictiva fuera de muestra. Este diseño respeta la naturaleza secuencial de datos financieros, evitando la fuga de información que comprometería la validez de los pronósticos.


2.1 Base de Datos

La base de datos utilizada proviene de Yahoo Finance, plataforma reconocida globalmente para obtención de datos financieros históricos de alta calidad y frecuencia diaria. Se extrajo información del ETF Invesco \(QQQ\) Trust (símbolo: QQQ), el cual replica el índice Nasdaq-100 compuesto por las 100 empresas no financieras de mayor capitalización bursátil listadas en el mercado Nasdaq, con fuerte concentración en sector tecnológico (Apple, Microsoft, NVIDIA, Amazon, Alphabet, Tesla, Meta).

La extracción se realizó mediante la función getSymbols() del paquete quantmod de R, automatizando la descarga directa desde fuente oficial. El período de estudio abarca desde 7 de octubre de 2022 hasta 2 de diciembre de 2025, capturando 791 observaciones diarias de precios de cierre. Este período es particularmente informativo, debido a que incluye recuperación post-crisis 2022, impulso del rally de inteligencia artificial (2023-2025), cambios en política monetaria de la Reserva Federal, y volatilidad estructural del sector tecnológico.

serie_QQQ <- getSymbols("QQQ", src="yahoo", auto.assign=FALSE, from="2010-01-01") 
Precio <- serie_QQQ$`QQQ.Close`

2.2 Variable de Análisis

El dataset se centra en una única variable cuantitativa de interés: precio de cierre diario del ETF QQQ. Esta variable representa el último precio de negociación durante cada sesión bursátil y es la medida estándar en análisis técnico y modelización de series financieras.

La elección del precio de cierre se fundamenta en que; primero, refleja el consenso del mercado al finalizar cada sesión, incorporando información completa del día; segundo, es el referente para cálculo de rendimientos y valoración de portafolios; tercero, es utilizado en la mayoría de indicadores técnicos y modelos predictivos; y por último, su disponibilidad es consistente sin interrupciones en días hábiles.


2.3 Partición Temporal de Datos

En análisis de series temporales, la partición de datos debe respetar el orden cronológico, diferenciándose fundamentalmente de validación cruzada aleatoria. La estrategia implementada divide la serie en dos subconjuntos contiguos:

Esta metodología es esencial porque evita “fuga de información” (data leakage) donde datos futuros influirían en predicción del pasado, mantiene estructura cronológica respetando dependencias temporales inherentes a series financieras, simula condiciones reales donde pronósticos se generan sin conocimiento de valores posteriores, y proporciona métricas objetivas de desempeño ex-post que validan capacidad predictiva genuina.


2.4 Marco Conceptual: Modelos ARIMA(p,d,q)

Los modelos \(ARIMA\) (AutoRegressive Integrated Moving Average), desarrollados por Box y Jenkins en 1970, constituyen metodología sistemática y robusta para análisis y pronóstico de series temporales. Se fundamentan en la idea de que el valor actual de una serie puede explicarse mediante sus valores históricos (componente autorregresivo), transformaciones que alcancen estacionariedad (componente integrador), o errores de pronóstico pasados (componente de media móvil).

A diferencia de modelos de regresión que requieren variables explicativas externas, los modelos \(ARIMA\) son univariados, extrayendo toda información predictiva de la propia historia de la serie. Esta característica los hace especialmente valiosos en contextos financieros donde no se dispone de predictores externos confiables, o donde el objetivo es capturar dinámicas intrínsecas de evolución temporal.

2.4.1 Componente Autorregresivo AR(p)

El modelo AR(p) pronostica la variable utilizando combinación lineal de sus valores pasados:

\[y_t = c + \phi_1 y_{t-1} + \phi_2 y_{t-2} + \cdots + \phi_p y_{t-p} + \varepsilon_t\]

donde: - \(y_t\) es el valor de la serie en tiempo \(t\) - \(c\) es constante (intercepto o drift) - \(\phi_1, \phi_2, \ldots, \phi_p\) son coeficientes autorregresivos que miden influencia de cada rezago - \(\varepsilon_t\) es término de error (ruido blanco) con \(E[\varepsilon_t]=0\) y varianza \(\sigma^2\) constante

El coeficiente \(\phi_1\) en AR(1) indica persistencia de la serie: valores cercanos a 1 implican alta persistencia (shocks tienen efectos duraderos), mientras que valores cercanos a 0 indican reversión rápida a media. Para que modelo sea estacionario, los coeficientes deben satisfacer restricciones específicas (raíces del polinomio característico fuera del círculo unitario).

La interpretación económica es que si una serie ha estado elevada en período anterior, tiende a permanecer elevada actualmente, capturando inercia o persistencia en comportamiento de variable.

2.4.2 Componente de Media Móvil MA(q)

El modelo MA(q) utiliza errores de pronóstico pasados en lugar de valores históricos de variable:

\[y_t = c + \varepsilon_t + \theta_1 \varepsilon_{t-1} + \theta_2 \varepsilon_{t-2} + \cdots + \theta_q \varepsilon_{t-q}\]

donde \(\theta_1, \ldots, \theta_q\) son coeficientes de media móvil.

La interpretación económica es que shocks o sorpresas en serie tienen efectos transitorios que se disipan gradualmente. Esto captura comportamientos donde precios regresan a nivel promedio tras perturbación, en lugar de permanecer desplazados permanentemente. En contextos financieros, MA modela la reversión a media que caracteriza a mercados relativamente eficientes en corto plazo.

2.4.3 Componente de Integración I(d)

Muchas series económicas y financieras no son estacionarias en forma original, presentando tendencias, medias cambiantes, o varianzas no constantes. Una serie estacionaria tiene propiedades estadísticas (media, varianza, autocovarianzas) invariantes en tiempo; una serie no-estacionaria exhibe comportamientos dependientes del momento observado.

El componente de integración aborda esto mediante diferenciación, transformación que calcula cambios entre observaciones consecutivas:

\[y'_t = y_t - y_{t-1} = \Delta y_t\]

Esta operación (primera diferencia) elimina tendencias lineales y estabiliza media. Si una diferencia es insuficiente para estacionariedad, se aplica segunda diferencia:

\[y''_t = y'_t - y'_{t-1} = \Delta^2 y_t\]

El parámetro \(d\) indica número de diferencias necesarias para que serie se vuelva estacionaria. Una serie que requiere \(d\) diferencias se denomina “integrada de orden \(d\)”, denotada I(d). En práctica, rara vez se requieren más de dos diferencias; para series financieras como precios de activos, típicamente \(d=1\) es suficiente.

2.4.4 Formulación Compacta con Operador de Rezago

Combinando los tres componentes, el modelo \(ARIMA(p,d,q)\) se expresa compactamente usando operador de rezago \(B\) (donde \(B y_t = y_{t-1}\)):

\[\Phi(B)(1-B)^d y_t = c + \Theta(B) \varepsilon_t\]

donde: - \(\Phi(B) = 1 - \phi_1 B - \phi_2 B^2 - \cdots - \phi_p B^p\) es polinomio autorregresivo - \((1-B)^d\) es operador de diferenciación aplicado \(d\) veces - \(\Theta(B) = 1 + \theta_1 B + \theta_2 B^2 + \cdots + \theta_q B^q\) es polinomio de media móvil

Esta representación facilita análisis teórico y derivación de propiedades estadísticas. Su elegancia radica en capturar dinámicas complejas mediante combinación sistemática de componentes que actúan en niveles distintos: AR modela persistencia, MA modela efectos de shocks transitorios, I transforma serie hacia propiedades deseadas.

2.4.5 Supuestos Fundamentales del Modelo

Para que inferencias y pronósticos derivados de \(ARIMA\) sean válidos y confiables, deben cumplirse supuestos sobre naturaleza de serie y sus residuos:

  1. Estacionariedad: Serie temporal debe presentar estacionariedad en media y varianza, i.e., propiedades estadísticas permanecen aproximadamente constantes en tiempo. Esto asegura que relaciones identificadas entre observaciones son estables y predecibles, en lugar de resultado de tendencias determinísticas no modeladas.

  2. Ruido Blanco en Residuos: Los residuos del modelo ajustado deben comportarse como secuencia aleatoria e independiente sin patrones sistemáticos. Si residuos contienen estructura, sugiere que modelo no ha capturado completamente dinámica temporal, requiriendo respecificación.

  3. Homocedasticidad: Se asume que errores tienen varianza constante a través del tiempo. Violaciones (heteroscedasticidad o volatilidad que cambia en tiempo) comprometen precisión de intervalos de confianza.

  4. Normalidad de Residuos: Aunque no es estrictamente necesaria para estimación del modelo, la normalidad es deseable para construcción precisa de intervalos de confianza y validez de pruebas de hipótesis sobre parámetros.


2.5 Herramientas Estadísticas para Identificación y Validación

2.5.1 Prueba Aumentada de Dickey-Fuller (ADF)

La estacionariedad es requisito previo fundamental antes de modelización \(ARIMA\). Una serie no-estacionaria produciría inferencias engañosas y pronósticos poco confiables.

La Prueba Aumentada de Dickey-Fuller (ADF) es contraste estadístico estándar para evaluación formal. Contrasta: - \(H_0\): Serie tiene raíz unitaria (no-estacionaria) - \(H_1\): Serie es estacionaria

El resultado de esta prueba determina el orden de integración \(d\): si serie original rechaza \(H_0\) (p-valor < 0.05), se procede a diferenciar y repetir hasta lograr estacionariedad. El estadístico ADF compara contra valores críticos tabulados; si estadístico de prueba es más negativo que valor crítico (mayor en magnitud), se rechaza \(H_0\).

2.5.2 Funciones de Autocorrelación: ACF y PACF

Las funciones de autocorrelación proporcionan diagnóstico visual fundamental para entender patrones de dependencia temporal y sugerir especificaciones \(ARIMA\) iniciales.

Función de Autocorrelación (ACF): Cuantifica correlación lineal entre observaciones separadas por rezagos 1, 2, …, k. Su comportamiento es diagnóstico: - En series estacionarias: ACF decae gradualmente hacia cero - En series no-estacionarias: ACF persiste en valores altos durante muchos rezagos

Para identificación de modelo, ACF es especialmente útil para distinguir procesos MA(q): un corte abrupto después de rezago \(q\) (i.e., autocorrelaciones significativas hasta lag \(q\) luego caen a cero dentro de bandas) sugiere componente MA(q).

Función de Autocorrelación Parcial (PACF): Elimina influencia de rezagos intermedios, aislando efecto directo de cada rezago sobre presente. Es especialmente informativa para identificar procesos AR(p): un corte abrupto después de rezago \(p\) sugiere componente AR(p).

El análisis combinado de ACF y PACF proporciona indicios valiosos sobre especificación inicial del modelo, aunque debe complementarse con criterios estadísticos formales.

2.5.3 Búsqueda Automática: Función auto.arima()

En práctica moderna, la función auto.arima() automatiza gran parte del proceso de identificación mediante algoritmos de búsqueda sistemática. Realiza búsqueda sobre rango especificado de valores para \(p\), \(d\) y \(q\), evaluando cada combinación mediante criterios de información como AICc.

Sin embargo, es importante reconocer limitaciones: un modelo automatizado puede omitir especificaciones que, aunque menos óptimas según criterios puramente estadísticos, podrían ser preferibles bajo consideraciones teóricas o interpretativas. Por ello, resulta valioso complementar búsqueda automática con análisis visual de ACF/PACF, permitiendo que teoría económica y conocimiento del dominio del problema informen especificación final.

2.5.4 Criterios de Selección del Modelo: AICc

Cuando múltiples especificaciones \(ARIMA\) son candidatas, es necesario criterio objetivo para elegir entre ellas. Los criterios de información cumplen este rol al balancear calidad del ajuste con complejidad del modelo.

El AICc (Criterio de Información de Akaike Corregido) es criterio más utilizado en práctica para selección de modelos \(ARIMA\). Evalúa verosimilitud del modelo (qué tan bien se ajusta a datos) y aplica penalización por agregar parámetros adicionales, reduciendo tendencia al sobreajuste. Su fórmula es:

\[\text{AICc} = \text{AIC} + \frac{2(p+q+k+1)(p+q+k+2)}{T-p-q-k-2}\]

donde: - \(T\) es número de observaciones - \(p\) y \(q\) son órdenes del modelo \(ARIMA\) - \(k\) es número de parámetros adicionales (como constante)

El término adicional respecto al AIC clásico corrige sesgo que ocurre en muestras pequeñas. Especificaciones con menor AICc son preferibles, indicando mejor balance entre ajuste y parsimonia.

Criterios de información no son aplicables para seleccionar orden de diferenciación \(d\), pues diferenciación altera escala de datos sobre cual se computa verosimilitud, haciendo valores de AICc no comparables entre modelos con diferente \(d\). Por ello, parámetro \(d\) se determina primero mediante pruebas de estacionariedad (ADF), y AICc se utiliza posteriormente para optimizar órdenes \(p\) y \(q\).

2.5.5 Diagnóstico de Residuos: Prueba de Ljung-Box

Después de ajustar modelo \(ARIMA\) específico, es necesario verificar que modelo haya capturado adecuadamente estructura temporal.

La Prueba de Ljung-Box es contraste estadístico que evalúa si existe autocorrelación significativa en residuos. Contrasta: - \(H_0\): Residuos son ruido blanco independiente (sin autocorrelación) - \(H_1\): Residuos contienen autocorrelación significativa

Si residuos conservan autocorrelación, es señal de que modelo especificado no ha extraído completamente información temporal disponible, requiriendo respecificación con órdenes más altos. Un p-valor elevado (> 0.05) indica que residuos se comportan consistentemente con ruido blanco, suministrando confianza en que modelo ha cumplido su propósito de modelar adecuadamente dinámica temporal de serie.


2.6 Procedimiento Metodológico: Metodología Box-Jenkins

La metodología Box-Jenkins propone proceso iterativo sistemático para modelización ARIMA. El procedimiento implementado en este análisis sigue estos pasos secuenciales:

Paso 1: Determinación del Orden de Integración (d)

Se evalúa estacionariedad de serie mediante pruebas formales (ADF) y análisis visual de ACF. Se identifica número de diferencias necesarias para que serie se vuelva estacionaria: - Si serie original es estacionaria: \(d=0\) - Si primera diferencia es estacionaria: \(d=1\) - Si segunda diferencia es estacionaria: \(d=2\)

El parámetro \(d\) es determinado independientemente de \(p\) y \(q\), antes de cualquier comparación de criterios de información.

Paso 2: Análisis Exploratorio de ACF y PACF

Se examinan gráficos de autocorrelación para serie potencialmente diferenciada, obteniendo sugerencias preliminares sobre órdenes \(p\) y \(q\): - Si ACF corta abruptamente en lag \(q\): sugiere MA(q) - Si PACF corta abruptamente en lag \(p\): sugiere AR(p) - Si ambos decaen gradualmente: sugiere proceso mixto ARMA(p,q)

Paso 3: Identificación de Modelos Candidatos

Se identifican especificaciones \(ARIMA\) plausibles basadas en: - Análisis visual de ACF/PACF - Búsqueda automática mediante auto.arima() - Consideraciones de parsimonia (preferir modelos simples) - Teoría económica/financiera sobre comportamiento de variable

Se ajustan múltiples modelos candidatos con diferentes combinaciones de \((p,d,q)\).

Paso 4: Estimación Comparativa y Selección

Se comparan especificaciones mediante: - Criterios de información (AICc, AIC, BIC) - Métricas de precisión en datos de entrenamiento (RMSE, MAE, MAPE) - Principio de parsimonia: preferir modelos más simples si diferencias en ajuste son marginales

Se selecciona modelo que balancéa mejor ajuste con complejidad.

Paso 5: Validación Diagnóstica de Residuos

Se examinan residuos del modelo seleccionado mediante: - Análisis gráfico temporal de residuos (verificar media cero, varianza constante) - Gráfico de ACF de residuos (verificar ausencia de autocorrelación) - Q-Q plot (verificar aproximación a normalidad) - Prueba de Ljung-Box (verificar formalmente que residuos son ruido blanco)

Si residuos no se comportan como ruido blanco, se regresa a Paso 3 para respecificación.

Paso 6: Generación de Pronósticos

Una vez validado modelo, se procede a: - Pronósticos puntuales sobre conjunto de prueba - Intervalos de confianza (típicamente 95%) que cuantifican incertidumbre - Evaluación ex-post comparando predicciones contra valores reales observados


2.7 Métricas de Evaluación del Desempeño Predictivo

Para evaluar objetivamente precisión de pronósticos generados por modelo \(ARIMA\) en conjunto de prueba, se emplean métricas cuantitativas estándar:

RMSE (Root Mean Squared Error):

\[\text{RMSE} = \sqrt{\frac{1}{n} \sum_{t=1}^{n} (\hat{y}_t - y_t)^2}\]

Amplifica penalizaciones sobre errores grandes, siendo sensible a presencia de valores atípicos en errores de pronóstico. Útil para identificar si modelo comete errores sistemáticamente grandes en algún período.

MAE (Mean Absolute Error):

\[\text{MAE} = \frac{1}{n} \sum_{t=1}^{n} |\hat{y}_t - y_t|\]

Proporciona medida de error promedio menos sensible a outliers que RMSE, ofreciendo perspectiva más robusta de desempeño general. Tiene interpretación directa: en promedio, predicciones desviación esta cantidad del valor real.

MAPE (Mean Absolute Percentage Error):

\[\text{MAPE} = \frac{100}{n} \sum_{t=1}^{n} \left| \frac{y_t - \hat{y}_t}{y_t} \right|\]

Expresa error como porcentaje relativo del valor observado, permitiendo comparabilidad del desempeño independientemente de magnitud absoluta de valores predichos. Especialmente útil en contextos financieros donde escala de precios varía.

Cobertura de Intervalos de Confianza:

Se evalúa proporción de valores reales que caen dentro de intervalos de confianza predichos (típicamente 95%). Una calibración correcta sugiere que incertidumbre fue estimada apropiadamente; demasiadas observaciones fuera del intervalo sugiere que modelo subestimó volatilidad.


3. Análisis descriptivo

En esta sección se presenta un análisis descriptivo exhaustivo de la serie histórica del \(ETF QQQ\) (Invesco QQQ Trust) —utilizado aquí como proxy del desempeño conjunto de las empresas del Nasdaq-100— recuperada programáticamente desde Yahoo Finance. La serie cubre desde el 1 de enero de 2010 hasta 2025 y trabaja en frecuencia diaria; la variable base es el precio de cierre ajustado, a partir del cual se calculan rendimientos, logarítmicos diarios, mensuales y anuales, así como medidas de riesgo y desempeño. El propósito central de este bloque es ofrecer una visión integrada y reproducible de (i) la evolución temporal acumulada del precio del \(QQQ\), (ii) la estructura actual del instrumento —por sectores y principales holdings— y (iii) un conjunto de estadísticas descriptivas y métricas financieras que cuantifiquen nivel, dispersión, asimetría, colas y riesgos extremos. Las visualizaciones incluyen gráficos interactivos para facilitar la exploración temporal, un gráfico de asignación sectorial, un diagrama de empaquetamiento circular para las mayores participaciones, histogramas y densidades de retornos, boxplots por año, heatmap estacional mensual y comparaciones normalizadas frente a otros ETFs de mercado . Además, se presenta un resumen anual con volatilidad y drawdown por año para identificar episodios de estrés y recuperación, así como una cronología de hitos tecnológicos relevantes que permite contextualizar inflexiones recientes en la dinámica del \(QQQ\). La interpretación de los resultados prioriza tres ejes: nivel y tendencia de largo plazo, dinámica de riesgo (volatilidad y drawdowns) y concentración (sectorial y por holdings), con el objetivo de brindar una base sólida para cualquier análisis inferencial o de modelado posterior.

3.1.1 Serie QQQ histórica

library(dplyr)
library(ggplot2)
library(xts)
library(tidyquant)
library(tidyverse)
library(plotly)
library(viridis)
library(reshape2)
library(zoo)
library(PerformanceAnalytics)
library(quantmod)
library(knitr)
library(moments)
library(packcircles)
library(tidyr)
library(lubridate)
serie <- getSymbols('QQQ', src='yahoo', auto.assign=FALSE, from="2010-01-01")
precios <- serie$QQQ.Close
datos_qqq <- data.frame(
  Fecha = index(precios),
  Precio = as.numeric(precios)
)
datos_qqq <- datos_qqq %>%
  mutate(Corte = as.yearqtr(Fecha)) 

lista_frames <- lapply(unique(datos_qqq$Corte), function(c) {
  dt <- datos_qqq[datos_qqq$Corte <= c, ]
  dt$Frame <- format(c, "%Y-%q")
  return(dt)
})

datos_animados <- dplyr::bind_rows(lista_frames)

p <- ggplot(datos_animados, aes(x = Fecha, y = Precio)) +
  geom_area(aes(frame = Frame), fill = tesla_pal$primary, alpha = 0.1, position = "identity") +
  geom_line(aes(frame = Frame), color = tesla_pal$primary, size = 0.8) +
  labs(
    title = "Evolución Dinámica del QQQ",
    subtitle = "Crecimiento histórico acumulado",
    x = "", 
    y = "Precio (USD)"
  ) +
  scale_y_continuous(labels = scales::dollar_format()) +
  theme_tesla() +
  theme(plot.title = element_text(size = 14))

plotly::ggplotly(p, tooltip = c("x", "y")) %>%
  plotly::layout(
    paper_bgcolor = 'rgba(0,0,0,0)',
    plot_bgcolor = 'rgba(0,0,0,0)',
    font = list(family = "Inter, sans-serif", color = tesla_pal$text_gray),
    hovermode = "x unified"
  ) %>%
  plotly::animation_opts(
    frame = 100,       
    transition = 0,    
    redraw = FALSE     
  ) %>%
  plotly::animation_slider(
    currentvalue = list(prefix = "Periodo: ") 
  ) %>%
  plotly::config(displayModeBar = FALSE)

Desde 2010, la trayectoria del \(QQQ\) ha mantenido una dirección claramente ascendente, reflejando el impulso sostenido del sector tecnológico dentro del mercado estadounidense. El fondo pasó de cotizar por debajo de los 60–70 USD a comienzos de la década a superar con holgura los 600 USD hacia 2025, un avance que evidencia un crecimiento compuesto fuerte y continuo.

Aunque la tendencia de fondo es positiva, el gráfico también deja ver fases de tensión que marcan la dinámica del riesgo. La caída de 2020, derivada del choque inicial por la pandemia, destaca por su brusquedad y rápida recuperación, mientras que la corrección de 2022, relacionada con el ciclo restrictivo de la Reserva Federal, muestra un descenso más prolongado y coherente con un aumento generalizado de la aversión al riesgo. Estos episodios reflejan lo que suele documentarse en la literatura: la volatilidad tiende a agruparse en ciertos periodos y no se distribuye de forma uniforme en el tiempo, lo que justifica complementar el análisis con métricas de drawdown y distribuciones de retornos.

En los años más recientes, especialmente entre 2023 y 2025, el ritmo de apreciación del \(QQQ\) se acelera de manera notable. Este comportamiento coincide con el empuje de las grandes compañías vinculadas a inteligencia artificial y computación avanzada, cuyo peso dentro del índice es determinante. En ese contexto, la concentración en mega-caps tecnológicas actúa como un motor de crecimiento, pero también incrementa la sensibilidad del fondo a cualquier cambio en las valoraciones del sector.

En conjunto, la evolución del \(QQQ\) entre 2010 y 2025 combina una tendencia estructural de crecimiento con episodios de inestabilidad y con una dependencia cada vez mayor del desempeño de unas pocas empresas de gran capitalización. Esta mezcla explica tanto su elevado rendimiento histórico como su exposición marcada a shocks de volatilidad.

3.1.2 Resumen anual retornos

if (!exists("precios")) {
  precios <- serie[,6]   
}
ret_diario <- dailyReturn(precios, type = "log")
ret_anual  <- yearlyReturn(precios, type = "log")
df_ann <- data.frame(Fecha = index(ret_anual), Ret = as.numeric(ret_anual))
df_ann <- df_ann %>% mutate(Año = year(Fecha), RetPct = Ret * 100)
vol_year <- ret_diario %>%
  data.frame(Fecha = index(ret_diario), Ret = as.numeric(ret_diario)) %>%
  mutate(Año = year(Fecha)) %>%
  group_by(Año) %>%
  summarise(
    Volatilidad = sd(Ret, na.rm = TRUE) * sqrt(252) * 100,
    RetornoTotal = sum(Ret) * 100
  )
dd_df <- data.frame(Fecha = index(ret_diario), Ret = as.numeric(ret_diario)) %>%
  mutate(Año = year(Fecha))

maxdd_yr <- dd_df %>% group_by(Año) %>%
  summarise(
    MaxDrawdown = min(cumprod(1 + Ret) / cummax(cumprod(1 + Ret)) - 1) * 100
  )
res_yr <- left_join(vol_year, maxdd_yr, by = "Año") %>% arrange(desc(Año))
kable(
  res_yr,
  format = "html",
  digits = 2,
  align = c("l", "r", "r", "r"),
  col.names = c("Año", "Volatilidad (%)", "Retorno Total (%)", "Max Drawdown (%)"),
  table.attr = "class='table' style='width:60%; margin:auto; font-size:18px;'"
)
Año Volatilidad (%) Retorno Total (%) Max Drawdown (%)
2025 23.96 19.76 -23.50
2024 18.03 22.18 -13.85
2023 17.83 43.04 -11.28
2022 32.17 -40.15 -38.50
2021 18.24 23.75 -11.10
2020 35.88 38.91 -30.54
2019 16.21 32.08 -11.15
2018 22.99 -0.97 -24.10
2017 10.34 27.36 -5.25
2016 16.25 5.75 -12.41
2015 17.94 8.01 -14.18
2014 13.86 16.03 -8.60
2013 12.26 30.05 -6.25
2012 15.35 15.41 -12.05
2011 23.75 2.48 -16.81
2010 19.26 15.97 -16.65

Las estadísticas anuales de volatilidad, retorno total y máximo retroceso permiten caracterizar con claridad la estructura del comportamiento del \(QQQ\) entre 2010 y 2025. A diferencia del análisis basado únicamente en niveles de precio, estas métricas capturan la dinámica del riesgo, la intensidad de las variaciones anuales y la magnitud de las caídas dentro de cada ciclo de mercado, proporcionando una visión más completa del desempeño histórico del índice.

En primer lugar, la volatilidad muestra una variabilidad significativa a lo largo del periodo, oscilando entre niveles relativamente bajos , como en 2017 (10.34 %), y picos pronunciados asociados a episodios de tensión financiera, particularmente en 2020 (35.88 %), 2022 (32.17 %) y 2025 (23.96 %). Estos aumentos coinciden con periodos de correcciones profundas o con fuertes reacomodaciones del mercado tecnológico, lo que evidencia la sensibilidad del \(QQQ\) a shocks macroeconómicos y a ciclos de liquidez global. En conjunto, la serie revela un patrón característico: volatilidad contenida en fases expansivas y picos abruptos en periodos de correcciones fuertes o incertidumbre.

El retorno total anual refuerza esta lectura. El índice presenta años de crecimiento excepcional, como 2013 (30.05 %), 2019 (32.08 %), 2020 (38.91 %) y especialmente 2023 (43.04 %), que representan momentos de expansión intensa impulsados por la aceleración tecnológica y el ciclo alcista post-pandemia. Sin embargo, también registra episodios correctivos severos, destacándose 2022 con un -40.15 %, el peor desempeño del periodo, directamente asociado al endurecimiento de la política monetaria y la contracción de las valoraciones tecnológicas. Este contraste entre años extremadamente positivos y años profundamente negativos evidencia la naturaleza altamente cíclica del sector tecnológico y su dependencia de expectativas de crecimiento futuro.

El Máx Drawdown, una medida crítica para evaluar riesgo extremo, muestra caídas que alcanzan niveles superiores al 30 % en años como 2020 (-30.54 %) y 2022 (-38.50 %), confirmando que, aunque el \(QQQ\) ha experimentado ganancias notables, estas han venido acompañadas de episodios de deterioro rápido y profundo. Incluso en años con retornos positivos, como 2025 o 2021, los drawdowns interanuales superiores al 10 % muestran que la trayectoria alcista no ha sido lineal, sino marcada por correcciones frecuentes dentro de tendencias más amplias.

En conjunto, estas métricas revelan que el comportamiento del \(QQQ\) entre 2010 y 2025 está dominado por fases amplias de expansión acompañadas de episodios de alta volatilidad, con drawdowns significativos que reflejan la vulnerabilidad del sector tecnológico frente a cambios en tasas de interés, expectativas de crecimiento y shocks globales. La combinación de retornos anuales muy elevados y caídas súbitas evidencia un patrón típico de activos con alto potencial de apreciación, pero también expuestos a riesgo considerable durante transiciones de ciclo.

3.1.3 División sectorial

sectores <- data.frame(
  Sector = c("Tecnología", "Consumo Discrecional", "Servicios de Comunicación", 
             "Consumo Básico", "Industriales", "Salud", "Otros", 
             "Servicios Públicos", "Materiales", "Energía"),
  Peso = c(53.60, 13.04, 12.61, 4.99, 4.58, 4.28, 3.22, 1.38, 1.25, 0.47)
)

colores_sector <- c(
  "#2b5c8a",
  "#5d5b94", 
  "#8e6fa3",
  "#c46d9e",
  "#e67586", 
  "#f38972", 
  "#f8a262",
  "#fbc058", 
  "#fce05d", 
  "#34495e"  
)
fig_pie <- plot_ly(sectores, labels = ~Sector, values = ~Peso, type = 'pie',
        textposition = 'outside',      
        textinfo = 'label+percent',    
        hoverinfo = 'label+value+percent',
        marker = list(
          colors = colores_sector, 
          line = list(color = '#ffffff', width = 1.5) 
        ),
        sort = FALSE, 
        automargin = TRUE
)

fig_pie <- fig_pie %>% layout(
  title = list(
    text = "<b>Asignación Sectorial</b>",
    font = list(size = 22, family = "Poppins, sans-serif", color = tesla_pal$text_main),
    x = 0.05, 
    y = 0.95
  ),
  showlegend = FALSE, 
  margin = list(t = 80, b = 40, l = 80, r = 80), 
  paper_bgcolor = 'rgba(0,0,0,0)',
  plot_bgcolor = 'rgba(0,0,0,0)',
  font = list(family = "Inter, sans-serif", size = 12, color = tesla_pal$text_gray)
)

fig_pie

El gráfico de Asignación Sectorial ratifica la identidad del \(QQQ\) no como un índice de mercado amplio, sino como un vehículo de inversión temático con un sesgo factorial explícito: el sector tecnología ejerce una hegemonía absoluta sobre la estructura del fondo, acaparando el 53.9% de los activos netos. Esta concentración masiva desborda los límites tradicionales de la diversificación sectorial, convirtiendo al ETF en un instrumento altamente sensible a los ciclos de innovación y a las revisiones de valoración específicas de la industria tecnológica.

Esta preponderancia se ve magnificada por la correlación estratégica de los sectores secundarios: Consumo Discrecional (13.1%) y Servicios de Comunicación (12.7%) ocupan el segundo y tercer lugar respectivamente. Desde una perspectiva fundamental, esta distribución es engañosa, pues gran parte de los componentes de estos sectores (como Amazon en consumo o Alphabet/Meta en comunicación) operan bajo dinámicas digitales similares a las tecnológicas puras. En consecuencia, cerca del 80% del portafolio se encuentra expuesto al factor Growth (Crecimiento), lo que implica una alta sensibilidad a la liquidez del mercado y al apetito por riesgo, distanciándose de la estructura más balanceada que ofrecen índices generalistas como el S&P 500 (MSCI, 2023).

Por el contrario, la participación marginal de sectores defensivos y anticíclicos, como Consumo Básico (5.02%), Salud (4.3%), Industriales (4.61%) y las asignaciones residuales en Servicios Públicos (1.39%) y Energía (0.473%), sugiere que el \(QQQ\) carece de los “amortiguadores” tradicionales contra la volatilidad macroeconómica. Esta asimetría estructural dota al portafolio de una elevada duración de acciones implícita, haciéndolo mecánicamente vulnerable a las variaciones en la tasa de descuento (tasas de interés), una característica que explica la severidad de las correcciones observadas en 2022 cuando el costo del capital se incrementó (Bernstein, 1997).

3.1.4 Mayores Holdings

top10 <- data.frame(
  ticker = c("NVDA","AAPL","MSFT","AVGO","AMZN","GOOGL","GOOG","TSLA","META","NFLX"),
  empresa = c("NVIDIA","Apple Inc.","Microsoft","Broadcom Inc.","Amazon.com, Inc.",
              "Alphabet Class A","Alphabet Class C","Tesla, Inc.","Meta Plataformas, Inc.","Netflix, Inc."),
  peso = c(9.33, 8.78, 7.69, 6.59, 5.21, 3.97, 3.71, 3.31, 2.93, 2.36),
  sector = c("Tecnología","Tecnología","Tecnología","Tecnología",
             "Consumo","Comunicación","Comunicación",
             "Consumo","Comunicación","Consumo"),
  stringsAsFactors = FALSE
)

otros_val <- round(100 - sum(top10$peso), 2)
holdings <- bind_rows(top10,
                      data.frame(ticker="OTROS", empresa="Resto del QQQ",
                                 peso = otros_val, sector="Varios", stringsAsFactors = FALSE)) %>%
  arrange(desc(peso))

packing <- circleProgressiveLayout(holdings$peso, sizetype='area')
holdings_pack <- cbind(holdings, packing)
holdings_pack$id <- seq_len(nrow(holdings_pack))
holdings_pack <- holdings_pack %>% rename(center_x = x, center_y = y)

dat.gg <- circleLayoutVertices(packing, npoints = 100)
dat.gg <- merge(dat.gg, holdings_pack, by = "id")

holdings_pack <- holdings_pack %>%
  mutate(
    peso_label = gsub("\\.", ",", formatC(peso, digits = 2, format = "f")),
    hover_text = paste0(
      empresa, "\n",
      "Ticker: ", ticker, "\n",
      "Peso: ", peso_label, "%\n",
      "Sector: ", sector
    ),
    label_text = ifelse(peso >= 2.3, paste0(ticker, "\n", peso_label, "%"), "")
  )

fill_map <- c(
  "Tecnología"   = tesla_pal$primary,
  "Consumo"      = tesla_pal$secondary,
  "Comunicación" = "#3b82f6",
  "Varios"       = tesla_pal$text_gray
)

p_bubble <- ggplot() +
  geom_polygon(
    data = dat.gg,
    aes(x = x, y = y, group = id, fill = sector,
        text = holdings_pack$hover_text[match(id, holdings_pack$id)]),
    color = "white", size = 0.5, alpha = 0.95
  ) +
  geom_text(
    data = holdings_pack,
    aes(x = center_x, y = center_y, label = label_text, text = hover_text),
    size = 3.8, color = "white", fontface = "bold", lineheight = 0.9
  ) +
  scale_fill_manual(values = fill_map) +
  theme_void() +
  coord_equal() +
  labs(title = "Composición del Portafolio QQQ",
       subtitle = "Top holdings según la imagen") +
  theme(
    plot.title = element_text(face = "bold", size = 16, color = tesla_pal$text_main, hjust = 0.5),
    plot.subtitle = element_text(size = 12, color = tesla_pal$text_gray, hjust = 0.5),
    legend.position = "bottom",
    legend.title = element_blank(),
    plot.margin = margin(10,10,10,10)
  )

ggplotly(p_bubble, tooltip = "text") %>%
  config(displayModeBar = FALSE) %>%
  layout(
    font = list(family = "Inter", color = tesla_pal$text_main),
    plot_bgcolor  = "rgba(0,0,0,0)",
    paper_bgcolor = "rgba(0,0,0,0)",
    legend = list(orientation = "h", yanchor = "bottom", y = -0.12, xanchor = "center", x = 0.5),
    hoverlabel = list(
      bgcolor = "rgba(255,255,255,0.97)",
      bordercolor = "rgba(0,0,0,0.08)",
      font = list(family = "Inter", color = tesla_pal$text_main, size = 11)
    )
  )

El diagrama de empaquetamiento circular revela la estructura interna del \(QQQ\), evidenciando una alta concentración jerárquica en un número reducido de activos de mega-capitalización. Visualmente, el gráfico confirma que el rendimiento del índice no es el resultado de una contribución homogénea, sino que depende desproporcionadamente de un clúster de empresas dominantes: las diez mayores posiciones (encabezadas por NVDA, AAPL, MSFT y AVGO) representan, en conjunto, más del 50% del peso total del portafolio, relegando al segmento de “Otros” (el resto de los componentes del Nasdaq-100) a una participación minoritaria del 46.12%. Esta arquitectura de cartera contradice el principio clásico de diversificación ingenua, exponiendo al inversor a un significativo riesgo idiosincrático derivado del desempeño individual de estos gigantes tecnológicos (Markowitz, 1952).

La distribución sectorial refuerza el sesgo hacia la innovación: las burbujas predominantes en color verde (Tecnología), azul (Comunicación) y cian (Consumo Discrecional) ilustran que el \(QQQ\) es, en esencia, una apuesta factorial hacia el crecimiento y la economía digital, con una exposición mínima a sectores defensivos tradicionales. Resulta particularmente notable que NVIDIA (9.33%) haya superado a Apple (8.78%) y Microsoft (7.69%) como el componente de mayor ponderación, un cambio estructural que valida empíricamente la hipótesis planteada en el análisis de precios sobre el impacto disruptivo de la Inteligencia Artificial Generativa en la valoración de activos recientes (Fama & French, 2015).

Desde una perspectiva de gestión de riesgos, esta configuración explica la alta beta y la convexidad observada en la serie histórica: la correlación positiva entre estos pocos activos líderes amplifica tanto los rendimientos exponenciales en mercados alcistas como la severidad de los drawdowns en periodos de corrección, confirmando que la dinámica del \(QQQ\) está intrínsecamente ligada a la salud financiera y las expectativas de crecimiento de este selecto grupo de empresas (Sharpe, 1964).

3.1.5 Análisis Estadístico precios

serie_vec <- as.numeric(serie[,6])
serie_vec <- serie_vec[!is.na(serie_vec)]
if (max(serie_vec) > 1000) {
  warning("⚠️ La serie está por fuera del rango típico del QQQ (0–1000 USD)")
}

valores_calculados <- c(
  length(serie_vec),
  mean(serie_vec),
  median(serie_vec),
  min(serie_vec),
  max(serie_vec),
  max(serie_vec) - min(serie_vec),
  var(serie_vec),
  sd(serie_vec),
  skewness(serie_vec),
  kurtosis(serie_vec)
)

desc <- data.frame(
  Métrica = c(
    "Observaciones Totales",
    "Media",
    "Mediana",
    "Mínimo",
    "Máximo",
    "Rango",
    "Varianza",
    "Desviación Estándar",
    "Asimetría (Skewness)",
    "Curtosis"
  ),
  Valor = format(
    round(valores_calculados, 4),
    scientific = FALSE,
    big.mark = ","
  )
)

kable(
  desc,
  format = "html",
  align = c('l', 'r'),
  table.attr = "class='table' style='width:60%; margin:auto; font-size:18px;'"
)
Métrica Valor
Observaciones Totales 4,006.0000
Media 199.3528
Mediana 147.5458
Mínimo 37.0869
Máximo 635.7700
Rango 598.6831
Varianza 22,758.2006
Desviación Estándar 150.8582
Asimetría (Skewness) 0.9340
Curtosis 2.8172

Las estadísticas básicas del nivel de precios confirman una estructura marcada por una tendencia ascendente persistente y un incremento notable del valor del activo a lo largo del periodo analizado. El promedio de la muestra (199.35 USD) se encuentra claramente por encima de la mediana (147.55 USD), lo que evidencia una asimetría positiva moderada. Esta diferencia revela que los valores más recientes —cuando el \(QQQ\) alcanzó niveles históricamente altos— empujan la distribución hacia la parte superior del rango, reflejando que una porción importante de la apreciación del precio se concentra en la etapa final del periodo.

El mínimo registrado (37.09 USD) y el máximo (635.77 USD) delimitan un rango amplio de aproximadamente 598.68 USD, coherente con un activo que ha multiplicado varias veces su valor en los últimos años. Esta amplitud también se observa en la desviación estándar (150.86 USD) y en la elevada varianza asociada (22,758.20), que, más que representar “riesgo” en el sentido estricto, describen la magnitud de la tendencia de largo plazo: una trayectoria fuertemente alcista tiende a generar una dispersión considerable en los niveles históricos del precio.

La asimetría de 0.934 confirma el desplazamiento de la distribución hacia valores altos, en línea con la aceleración reciente del índice. A su vez, la curtosis de 2.8172 —ligeramente inferior al valor teórico de una distribución normal— sugiere una distribución mesocúrtica, sin una concentración extrema en las colas, aunque tampoco completamente simétrica o estacionaria, lo cual es típico en series de precios que presentan una tendencia estructural sostenida.

En conjunto, estas métricas describen una serie dominada por la apreciación progresiva y sostenida del \(QQQ\), con una distribución inclinada hacia niveles altos y una dispersión que refleja la magnitud del crecimiento acumulado durante todo el periodo.

3.1.6 Rendimientos Diarios

precios <- serie$QQQ.Close
ret_diario  <- dailyReturn(precios, type = "log")
ret_mensual <- monthlyReturn(precios, type = "log")
ret_anual   <- yearlyReturn(precios, type = "log")
vol_anual <- sd(ret_diario) * sqrt(252)
resumen <- data.frame(
  Concepto = "Volatilidad Anualizada (Riesgo)",
  Valor = scales::percent(vol_anual, accuracy = 0.01)
)
kable(resumen, 
      format = "html", 
      table.attr = "class='table' style='width:50%; margin:auto;'")
Concepto Valor
Volatilidad Anualizada (Riesgo) 20.71%

La volatilidad anualizada del \(20.71%\) sintetiza, en un único indicador, el nivel de riesgo que ha acompañado la trayectoria del \(QQQ\) durante el periodo analizado. Este valor es coherente con un activo que, aunque mantiene una tendencia alcista sostenida, experimenta episodios concentrados de inestabilidad propios de un índice fuertemente expuesto al sector tecnológico.

Un nivel de volatilidad cercano al 21% puede considerarse moderado-alto para un ETF de renta variable, y encaja con los patrones ya observados: años de gran expansión seguidos por correcciones abruptas (como en 2020 y 2022), así como periodos de aceleración extraordinaria impulsados por innovaciones tecnológicas recientes. En términos prácticos, esta magnitud implica que las fluctuaciones anuales típicas del precio se mueven alrededor de ese rango, lo que coincide con la dispersión vista en los drawdowns y en las amplitudes anuales de retornos.

Desde la perspectiva estadística, una volatilidad de este tamaño también respalda la idea de volatilidad agrupada: largos tramos de relativa estabilidad interrumpidos por fases cortas de sobresaltos. Es la misma dinámica que se evidenció en el comportamiento histórico del índice y que la literatura clásica asocia a mercados impulsados por ciclos tecnológicos, donde los cambios de expectativas pueden ser abruptos.

En síntesis, la volatilidad anualizada del 20.71% no solo caracteriza el riesgo promedio del \(QQQ\), sino que encaja con la narrativa general: un activo con una tendencia estructural potente, pero atravesado por episodios de estrés que amplifican temporalmente sus oscilaciones.

3.1.7 Retornos Diarios

ret_df <- data.frame(Retorno = as.numeric(ret_diario))

ggplot(ret_df, aes(x = Retorno)) +
  geom_histogram(aes(y = ..density..), bins = 60, fill = tesla_pal$primary, alpha = 0.4) +
  geom_density(color = tesla_pal$secondary, size = 1.2) +
  labs(title = "Distribución de los Rendimientos Diarios del QQQ",
       x = "Retorno Diario (log)", y = "Densidad") +
  theme_tesla()

La distribución de los rendimientos diarios del \(QQQ\) revela una estructura estadística coherente con la arquitectura altamente concentrada del portafolio descrita en los apartados anteriores. Como muestra el gráfico, la curva de densidad presenta un pico pronunciado alrededor de cero y colas más gruesas de lo que predeciría una distribución normal, rasgo típico de activos dominados por empresas de gran capitalización fuertemente correlacionadas entre sí.

Este patrón leptocúrtico —evidenciado visualmente por la altura central desproporcionada y la presencia de observaciones extremas (tanto positivas como negativas) en los márgenes— es consistente con el comportamiento de un índice no diversificado de manera homogénea, sino fuertemente dependiente de unos pocos motores de crecimiento. En efecto, la concentración estructural en NVDA, AAPL, MSFT y AVGO expuesta en el diagrama de empaquetamiento circular se manifiesta directamente en la forma de la distribución:

cuando estas compañías se sincronizan al alza, generan acumulación de rendimientos pequeños y frecuentes, que estrechan la parte central de la distribución;

pero cuando experimentan shocks idiosincráticos o correcciones de múltiplos, producen movimientos abruptos de mayor magnitud, responsables de las colas pesadas observadas.

Desde una perspectiva de riesgo, esta distribución asimétrica confirma una alta kurtosis y la presencia de eventos de gran impacto con mayor probabilidad que la predicha por modelos clásicos de media-varianza (Markowitz, 1952). Ello es coherente con el sesgo factorial descrito previamente: un ETF con exposición cercana al 80% al factor Growth y mínima participación en sectores defensivos exhibirá de forma natural una mayor propensión a “jumps” y episodios de volatilidad concentrada.

La ligera inclinación de la distribución hacia rendimientos negativos —visible en la cola izquierda más extendida— es una expresión empírica de la sensibilidad del \(QQQ\) a cambios en la tasa de descuento, propiedad también discutida en el análisis sectorial. Durante ciclos de endurecimiento monetario, los activos de larga duración implícita (como la tecnología de mega-capitalización) tienden a exhibir caídas más pronunciadas, lo cual explica tanto la asimetría negativa como la convexidad detectada en la serie histórica (Sharpe, 1964).

En conjunto, la forma de la distribución no solo plasma el comportamiento estadístico de los rendimientos, sino que funciona como una evidencia visual directa de la propia identidad del \(QQQ\): un vehículo altamente concentrado, dominado por factores de crecimiento, sensible a liquidez y a ciclos tecnológicos, y estructuralmente propenso a movimientos extremos más frecuentes que los esperados bajo supuestos gaussianos.

3.1.8 Retornos por Año (QQQ)

ret_anual_df <- data.frame(
  Fecha = index(ret_diario),
  Ret = as.numeric(ret_diario),
  Año = format(index(ret_diario), "%Y")
)

ggplot(ret_anual_df, aes(x = Año, y = Ret, group = Año)) +
  geom_boxplot(fill = tesla_pal$primary, alpha = 0.7) +
  labs(title = "Distribución de los Retornos Diarios por Año (QQQ)",
       x = "Año", y = "Retorno Diario") +
  theme_tesla() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5))

La evolución anual de los retornos diarios del \(QQQ\) confirma varios de los patrones ya identificados en el comportamiento histórico del índice. A lo largo del periodo 2010–2025, los boxplots muestran que la mediana de los retornos permanece cercana a cero, un rasgo típico de los activos financieros, donde la tendencia de largo plazo se manifiesta en los niveles de precio, no en variaciones diarias (Tsay, 2010). Sin embargo, la dispersión en torno a esa mediana cambia significativamente entre años, reflejando la naturaleza cíclica y no constante de la volatilidad.

Durante la primera mitad del periodo (2010–2019), la amplitud de las cajas y la presencia moderada de valores atípicos sugieren un entorno relativamente estable, coherente con los demás indicadores anuales: retornos positivos sostenidos y drawdowns acotados. No obstante, incluso en esos años se observa el fenómeno de agrupamiento de volatilidad, donde los días con movimientos extremos tienden a aparecer en racimos, tal como anticipa la literatura de colas pesadas y dependencia temporal (Mandelbrot, 1963).

Los cambios más notorios aparecen a partir de 2020. El ensanchamiento abrupto de los boxplots y la proliferación de outliers tanto positivos como negativos reflejan el choque de la pandemia: un episodio de volatilidad extrema seguido de una recuperación igualmente acelerada. Este patrón continúa en 2021, aunque con menor severidad, y se intensifica nuevamente en 2022, cuando la política monetaria restrictiva genera el conjunto más amplio de retornos diarios negativos y una dispersión considerablemente mayor, en línea con el desplome anual registrado en ese año.

A partir de 2023, la dispersión disminuye parcialmente, pero se mantienen puntos aislados de retornos altos, consistentes con el impulso generado por el auge de la inteligencia artificial generativa y el papel dominante de las mega-caps tecnológicas en el índice (Invesco, 2024). Esto explica por qué, pese a un entorno de fuerte apreciación del precio, los boxplots aún muestran eventos extremos: la innovación tecnológica tiende a amplificar reacciones del mercado, tanto alcistas como bajistas (Malkiel, 2003).

En conjunto, la distribución anual de retornos evidencia que el \(QQQ\) combina periodos prolongados de estabilidad con episodios de sobresaltos intensos, confirmando que la volatilidad no es constante sino heterogénea y concentrada en momentos específicos. Este comportamiento es característico de los activos con fuerte exposición tecnológica y ajusta perfectamente con las demás métricas analizadas del índice.

3.1.9 Rendimientos por año

ret_anual_df <- data.frame(
  Año = year(index(ret_anual)),
  Retorno = round(100 * as.numeric(ret_anual), 2)
) %>%
  mutate(
    Tipo = ifelse(Retorno >= 0, "Positivo", "Negativo"),
  
    Pos_Texto = ifelse(Retorno >= 0, -0.4, 1.2)
  )

ggplot(ret_anual_df, aes(x = factor(Año), y = Retorno, fill = Tipo)) +
  
  geom_col(show.legend = FALSE) + 
    scale_fill_manual(values = c(
    "Positivo" = tesla_pal$primary,   
    "Negativo" = tesla_pal$negative   
  )) +
    geom_text(
    aes(label = paste0(Retorno, "%"), vjust = Pos_Texto),
    color = tesla_pal$text_main,
    size = 3.2,          
    fontface = "bold"     
  ) +
  
  labs(
    title = "Retorno Anual Histórico del QQQ",
    subtitle = "Rendimiento logarítmico anualizado (1999-2025)",
    x = "", 
    y = "Retorno (%)"
  ) +
  
  scale_y_continuous(expand = expansion(mult = 0.15)) +
    theme_tesla() +
  theme(
    axis.text.x = element_text(angle = 90, vjust = 0.5, size = 10),
    panel.grid.major.x = element_blank() 
  )

La secuencia de retornos anuales entre 2010 y 2025 muestra de manera clara cómo el comportamiento del \(QQQ\) combina una tendencia alcista de largo plazo con episodios puntuales de extrema volatilidad. Durante la década 2010–2019 predominan los resultados positivos, con solo una corrección leve en 2018 (-0.97%). Este patrón coincide con el periodo de expansión tecnológica posterior a la Crisis Financiera, donde la acumulación de retornos se desarrolló de forma progresiva y relativamente estable (Tsay, 2010).

La presencia de años sobresalientes —como 2013 (30.05%), 2017 (27.36%) o 2019 (32.08%)— confirma que buena parte del crecimiento del índice ocurrió en impulsos discretos, más que en un aumento lineal. Estos episodios de fuerte apreciación son característicos de los activos con exposición tecnológica, donde la adopción de nuevas plataformas y ciclos de innovación generan ondas de crecimiento acelerado (Malkiel, 2003).

El quiebre más severo del periodo ocurre en 2022, con un retorno anual de –40.15%, el más profundo de toda la muestra. Este año concentra el efecto del ajuste monetario más agresivo en décadas, sumado al drenaje de liquidez que afectó particularmente a las compañías de crecimiento. La caída coincide con lo observado en los boxplots de retornos y en las métricas anuales de riesgo, donde 2022 destaca como el año con mayor dispersión y drawdown, validando la presencia de un episodio claro de riesgo de cola (Mandelbrot, 1963).

A partir de 2023, el retorno se recupera con fuerza (43.04%), reflejando el impulso generado por el auge de la inteligencia artificial generativa y el liderazgo de las mega-caps tecnológicas, que dominan la composición del índice (Invesco, 2024). Los años 2024 y 2025 mantienen retornos positivos, aunque más moderados, lo que sugiere una normalización después del rebote inicial, pero dentro de un entorno aún marcado por expectativas de crecimiento tecnológico.

En suma, la serie de retornos anuales del \(QQQ\) muestra un activo con convexidad positiva de largo plazo, capaz de generar apreciaciones significativas en fases expansivas, pero sujeto a caídas abruptas cuando el ciclo tecnológico o monetario se invierte. Esta dinámica encaja plenamente con las demás métricas analizadas: volatilidad variable, asimetría positiva en los precios y episodios concentrados de estrés, todos rasgos característicos de un índice liderado por innovación y crecimiento acelerado.

3.2 Drawdown

ret_diario <- dailyReturn(precios, type = "log")

dd <- PerformanceAnalytics::Drawdowns(ret_diario)
dd_df <- data.frame(
  Fecha = index(dd),
  Drawdown = as.numeric(dd)
)
ggplot(dd_df, aes(x = Fecha, y = Drawdown)) +
  geom_line(color = tesla_pal$primary, linewidth = 0.7) +
  labs(title = "Drawdown Histórico del QQQ",
       x = "", y = "Drawdown") +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  theme_tesla()

El gráfico revela de manera clara la profundidad y duración de las pérdidas relativas del índice respecto a sus máximos previos durante el período 2010-2025, permitiendo evaluar no solo la volatilidad, sino también la resiliencia del mercado tecnológico a lo largo de estos quince años.

Entre 2010 y 2019, el \(QQQ\) experimenta drawdowns moderados y controlados. El año más desafiante de esta década fue 2011, con un máximo drawdown de -16.81%, seguido por 2015-2016 con -16.88%, representando correcciones breves pero significativas. Sin embargo, estos episodios fueron de corta duración, caracterizados por recuperaciones relativamente rápidas. Este comportamiento coincide con la fase de crecimiento sostenido observada en los retornos anuales, impulsada por la expansión de las grandes empresas tecnológicas, avances en inteligencia artificial temprana, comercio digital y servicios en la nube. El patrón es coherente con estudios que evidencian la creciente madurez y resistencia del sector tecnológico durante esta década. En este período, las caídas existen, pero ninguna se aproxima a niveles catastróficos, indicando una solidez estructural progresiva del índice.

El gráfico también evidencia un drawdown significativo durante la pandemia de \(COVID-19\) en 2020, alcanzando -30.54%. Aunque de severidad notable, fue de corta duración. A diferencia de crisis prolongadas, el \(QQQ\) experimentó una caída rápida seguida de una recuperación igual de acelerada, fenómeno asociado a la digitalización abrupta de la economía que impulsó fuertemente la demanda por empresas tecnológicas. Este comportamiento refuerza la idea de que el \(QQQ\) posee una estructura sectorial que se beneficia de shocks que incrementan la dependencia digital, lo que explica la rápida salida del drawdown. La recuperación en 2021, con drawdown de solo -11.10%, confirma que el mercado absorbió rápidamente el shock de la pandemia.

El período 2022-2023 muestra el episodio más desafiante del período 2010-2025. En 2022, el drawdown alcanzó -39.03%, el máximo de toda la ventana de 15 años analizada. Esta caída coincide con el ajuste de valoraciones provocado por el aumento agresivo de tasas de interés de la Reserva Federal, la inflación elevada y la contracción monetaria global. Estos shocks afectan especialmente a activos de crecimiento como los tecnológicos, cuyo valor presente es altamente sensible a cambios en las tasas de descuento, en línea con los argumentos del modelo CAPM y la literatura sobre sensibilidad de activos de crecimiento a tasas de interés. No obstante, a diferencia de crisis anteriores, el drawdown se recupera parcialmente durante el mismo período: en 2023, el máximo drawdown desciende a -38.71%, y en 2024 continúa mejorando hasta -13.85%, demostrando mayor robustez del mercado tecnológico contemporáneo y capacidad de recuperación acelerada.

Los datos más recientes (2024-2025) muestran estabilización. El máximo drawdown de 2024 fue de -13.85%, y en 2025 se ubica en -23.54%, sugiriendo que el mercado ha procesado el ajuste monetario y opera en un nuevo equilibrio. Aunque persisten correcciones menores, estas son características normales de mercados dinámicos impulsados por innovación tecnológica.

En conjunto, el análisis del drawdown en el período 2010-2025 confirma una narrativa de progresión y maduración del mercado tecnológico. El índice \(QQQ\) es un activo con potencial de crecimiento extraordinario, como evidencian los retornos anuales acumulados positivos en la mayoría de los años. Sin embargo, es susceptible a episodios de caídas significativas, particularmente cuando se enfrentan cambios estructurales en política monetaria (como en 2022) o shocks sistémicos (como COVID-19 en 2020). Lo que distingue este período de crisis históricas anteriores (como la burbuja punto-com) es la rapidez de recuperación: mientras que los drawdowns de 2000-2002 tardaron casi una década en recuperarse completamente, los episodios de 2020 y 2022 se recuperaron en meses a un par de años, reflejando una mayor eficiencia de mercado, mejor comprensión de valoraciones y una base económica más sólida en el sector tecnológico.

Este comportamiento hace evidente la naturaleza no estacionaria y heterocedástica de la serie \(QQQ\), caracterizada por volatilidad que se agrupa en períodos específicos de estrés macroeconómico. Este patrón justifica el uso de modelos \(ARIMA\) para capturar tendencias y dinámicas temporales, y de modelos GARCH para describir la volatilidad condicional que cambia en el tiempo. El drawdown, por tanto, complementa los análisis anteriores al mostrar no solo cuán profunda es la caída del índice, sino también cuánto tiempo tarda en recuperarse—un factor crítico en la gestión del riesgo financiero y fundamental para cualquier evaluación prospectiva del desempeño de este instrumento.

3.2.1 Métricas Financieras

cagr <- Return.annualized(ret_diario, scale = 252)
cumulative_return <- Return.cumulative(ret_diario)

sharpe_annual <- (mean(ret_diario, na.rm=TRUE) / sd(ret_diario, na.rm=TRUE)) * sqrt(252)
sortino <- SortinoRatio(ret_diario, MAR = 0)
max_dd <- maxDrawdown(ret_diario)

calmar <- as.numeric(cagr) / abs(as.numeric(max_dd))

metrics <- data.frame(
  Métrica = c("CAGR (anual)", "Retorno acumulado", "Sharpe (aprx anual)", 
              "Sortino", "Max Drawdown", "Calmar"),
  Valor = c(
    scales::percent(as.numeric(cagr), accuracy = 0.01),
    scales::percent(as.numeric(cumulative_return), accuracy = 0.01),
    round(as.numeric(sharpe_annual), 3),
    round(as.numeric(sortino), 3),
    scales::percent(as.numeric(max_dd), accuracy = 0.1),
    round(as.numeric(calmar), 3)
  ),
  stringsAsFactors = FALSE
)

knitr::kable(metrics, format = "html", table.attr = "class='table' style='width:60%; margin:auto;'")
Métrica Valor
CAGR (anual) 15.23%
Retorno acumulado 852.76%
Sharpe (aprx anual) 0.789
Sortino 0.069
Max Drawdown 39.0%
Calmar 0.39

El presente conjunto de Métricas Financieras ofrece una visión sintética y cuantitativa de la eficiencia, el riesgo y el rendimiento agregado del \(QQQ\) durante el período 2010-2025, complementando de manera crítica los análisis de retornos anuales y drawdown histórico.

El Retorno Acumulado de 852.76% y la Tasa de Crecimiento Anual Compuesto (CAGR) de 15.23% validan el extraordinario potencial de apreciación del activo, una característica consistente con la fase de crecimiento sostenido del sector tecnológico observada durante este período. Estas cifras de rendimiento total confirman que, a pesar de los episodios de riesgo extremo como la corrección de 2022, el \(QQQ\) posee una capacidad sustancial y demostrada para generar riqueza a largo plazo. Un inversor que hubiera mantenido posición durante los 15 años habría multiplicado su capital más de 9 veces.

Sin embargo, las métricas ajustadas al riesgo revelan información más matizada sobre la eficiencia del rendimiento. El Ratio de Sharpe de 0.789 es razonablemente bueno, situándose en el rango 0.5-1.0 considerado aceptable a bueno. Esto sugiere que el \(QQQ\) ha generado retorno excesivo en proporción moderada a la volatilidad asumida. A diferencia de períodos históricos que incluyen la burbuja punto-com, el período 2010-2025 muestra una eficiencia riesgo-ajustada decente, indicando que los retornos no han sido completamente consumidos por la dispersión.

Más revelador aún es el Ratio de Sortino de 0.069, que específicamente penaliza el riesgo de cola negativo (downside risk). Un valor tan bajo indica que el riesgo de caída ha sido desproporcionadamente alto en relación con el rendimiento generado. Este hallazgo se alinea directamente con los eventos identificados en los análisis de drawdown, particularmente el colapso de -39.0% en 2022. El Sortino bajo refleja que aunque el \(QQQ\) sube mucho en períodos alcistas, también cae profundamente en períodos de estrés, lo que penaliza a inversores con baja tolerancia al downside.

El indicador de riesgo extremo, el Max Drawdown de 39.0%, es significativo pero no catastrófico comparado con crisis históricas. Esta cifra es la manifestación cuantitativa del ajuste de valoraciones provocado por el ciclo de aumentos de tasas de 2022, y subraya que aunque el sector tecnológico es resiliente, sigue siendo sensible a cambios estructurales en política monetaria. Desde la perspectiva de la gestión de riesgo, este valor define el peor escenario del período 2010-2025. No obstante, el time to recovery fue mucho más rápido que en crisis pasadas: de -39% en 2022 a recuperación parcial en 2023-2024, demostrando mayor eficiencia de mercado.

Finalmente, el Ratio Calmar de 0.39 relaciona el rendimiento anualizado (15.23%) con el Max Drawdown (39.0%). Un valor de 0.39, aunque moderado (el umbral de “bueno” es 0.5), es coherente con un activo que generó rendimiento significativo pero experimentó correcciones profundas. Si 2022 no hubiera ocurrido, el Calmar sería más alto. Este ratio sugiere que existen oportunidades para mejorar la eficiencia riesgo-ajustada mediante diversificación adicional o estrategias defensivas durante ciclos de endurecimiento monetario.

En conclusión, el análisis de las métricas confirma una narrativa de progresión: el \(QQQ\) ofrece potencial de crecimiento extraordinario, evidenciado por el CAGR de 15.23% y retorno acumulado de \(852.76%\), lo que lo convierte en un activo atractivo para inversores de largo plazo. Sin embargo, lo hace asumiendo un costo de riesgo moderado-alto, manifestado en el Max Drawdown de 39.0% y Sortino bajo. Las métricas sugieren que el perfil de riesgo del \(QQQ\) está caracterizado por volatilidad concentrada en episodios de estrés (2022) más que por variabilidad constante. Para inversores con horizonte de 10+ años y tolerancia al riesgo moderada-alta, el perfil riesgo-retorno es favorable; para inversores conservadores u horizontes cortos, requiere consideraciones de hedging o diversificación adicional. El modelado y la gestión de este activo deben necesariamente considerar la asimetría y la volatilidad heterocedástica inherentes a su comportamiento, lo que justifica el uso de modelos GARCH para capturar volatilidad condicional y \(ARIMA\) para tendencias.

3.2.2 Volatilidad

rollsd30  <- rollapply(as.numeric(ret_diario), width = 30, FUN = sd, fill = NA, align = "right")
rollsd90  <- rollapply(as.numeric(ret_diario), width = 90, FUN = sd, fill = NA, align = "right")
rollsd252 <- rollapply(as.numeric(ret_diario), width = 252, FUN = sd, fill = NA, align = "right")

df_roll <- data.frame(
  Fecha = index(ret_diario),
  vol30 = rollsd30 * sqrt(252),
  vol90 = rollsd90 * sqrt(252),
  vol252 = rollsd252 * sqrt(252)
)

dfm <- melt(df_roll, id.vars = "Fecha", variable.name = "Window", value.name = "VolAnual")

ggplot(dfm, aes(x = Fecha, y = VolAnual, color = Window)) +
  geom_line(size = 0.8) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 0.1)) +
  labs(title = "Volatilidad Rolling (annualizada)", y = "Vol Annualizada", x = "") +
  scale_color_manual(values = c("vol30" = tesla_pal$primary, "vol90" = tesla_pal$secondary, "vol252" = tesla_pal$text_gray)) +
  theme_tesla()

El gráfico de volatilidad rolling desagrega temporalmente la cifra estática de riesgo anualizado, proporcionando la evidencia visual definitiva de la heterocedasticidad condicional inherente a la serie del \(QQQ\). Al observar la evolución de la desviación estándar anualizada en distintas ventanas temporales, se confirma que el riesgo del activo no es constante, sino que exhibe un marcado comportamiento de agrupamiento de volatilidad (volatility clustering): grandes cambios tienden a ser seguidos por grandes cambios, y períodos de calma por calma, validando empíricamente los postulados de los modelos ARCH/GARCH (Engle, 1982).

La estructura del gráfico está dominada por dos “regímenes de volatilidad elevada” que se corresponden con los episodios de drawdown máximo identificados en el análisis histórico. El primer régimen (2010-2012) muestra volatilidad anualizada entre 30-40%, reflejando la incertidumbre residual post-Crisis Financiera. Sin embargo, a diferencia de crisis prolongadas, este período se resuelve en 2-3 años. El segundo régimen más severo ocurre durante 2022, donde la volatilidad se mantiene persistentemente elevada alrededor de 30-35%, reflejando el cambio estructural en tasas de interés de la Reserva Federal. En contraste, el pico de 2020 (Pandemia) es extremadamente agudo pero transitorio, con vol30 alcanzando picos superiores al 80% pero recuperación acelerada.

La discrepancia entre las ventanas de corto plazo (vol30) y largo plazo (vol252) ofrece una lectura sobre la “tensión” del mercado. En 2022, la volatilidad de corto plazo oscila con mucha mayor amplitud, señalando búsqueda de equilibrio ante incertidumbre sobre tasas de interés. Esta sensibilidad valida la hipótesis de duración: la concentración en activos de crecimiento hace que el \(QQQ\) reaccione hipersensiblemente a cambios en política monetaria (Sharpe, 1964).

El período 2013-2019 representa un régimen de volatilidad comprimida, con vol252 oscilando entre 12-18%, el más bajo del período. A partir de 2023, la volatilidad desciende pero se estabiliza en niveles superiores a 2013-2019 (17-22%), sugiriendo que el mercado opera bajo una nueva estructura de riesgo base más elevada, coherente con la mayor concentración en mega-caps.

En conclusión, este gráfico demuestra que la “volatilidad media” es una métrica engañosa para el \(QQQ\), ya que el inversor rara vez experimenta el promedio; en su lugar, el activo transita entre largos períodos de volatilidad moderada y explosiones de riesgo extremo. Esta dinámica bimodal justifica plenamente la necesidad de modelos GARCH para capturar heterocedasticidad condicional (Mandelbrot, 1963; Bollerslev, 1986).

3.2.3 Estacionalidad Mensual del QQQ (2010–2025)

df_m <- data.frame(Fecha = index(ret_mensual), Ret = as.numeric(ret_mensual))
df_m <- df_m %>% mutate(Año = lubridate::year(Fecha), Mes = lubridate::month(Fecha, label = TRUE, abbr = TRUE), RetP = Ret*100)
tabla_m <- df_m %>% group_by(Año, Mes) %>% summarise(RetP = mean(RetP, na.rm = TRUE))
ggplot(tabla_m, aes(x = Mes, y = factor(Año), fill = RetP)) +
  geom_tile(color = "white") +
  scale_fill_viridis_c(option = "C", direction = 1, name = "Ret (%)") +
  labs(title = "Heatmap Estacional Mensual (QQQ)") +
  theme_tesla()

El mapa de calor estacional ofrece una deconstrucción granular de la dinámica temporal del \(QQQ\) durante 2010-2025, permitiendo identificar patrones de estacionalidad e inercia que quedan ocultos en las métricas anualizadas. La visualización confirma que la trayectoria del activo no es aleatoria, sino que exhibe una marcada dependencia serial: los retornos positivos (tonos naranjas y amarillos) tienden a agruparse en bloques temporales definidos, validando visualmente la presencia de regímenes de mercado persistentes (Jegadeesh & Titman, 1993).

Durante 2010-2019, la década de crecimiento sostenido se manifiesta como un bloque predominantemente cálido (tonos naranja), caracterizado por una notable consistencia en retornos positivos mensuales. Esta fase visualiza la era dorada tecnológica impulsada por política monetaria acomodaticia y expansión de plataformas digitales. Sin embargo, el heatmap revela una anomalía estacional importante: el “Efecto Septiembre”. Observando la columna del noveno mes, se aprecia una recurrencia de tonos más oscuros (años 2011, 2015, 2018, 2022), sugiriendo una debilidad estacional estructural en el sector tecnológico, consistente con literatura sobre anomalías de calendario y rebalanceo de portafolios institucionales (Thaler, 1987).

El período 2020 muestra una alternancia violenta. Marzo inicia con tonos oscuros (shock COVID), seguido de recuperación verde/amarilla agresiva a partir de abril. Este patrón refleja la digitalización acelerada de la economía durante confinamiento, que benefició directamente activos tecnológicos. Enero también aparece consistentemente con tonos cálidos a lo largo del período, en línea con el “Efecto Enero” documentado en mercados de renta variable.

La corrección de tasas de 2022 produce un patrón distintivo: el año aparece como un “tablero de ajedrez” con meses alternados de pérdidas (morado/azul en abril, junio, septiembre, octubre) e intentos de recuperación. Septiembre de 2022 es particularmente oscuro, validando el efecto estacional negativo combinado con presiones macroeconómicas de política monetaria restrictiva.

La recuperación de 2023-2024, visible en las franjas superiores naranjas, confirma la resiliencia del índice y su capacidad para retomar momentum alcista tras períodos de ajuste. Noviembre y diciembre históricos también muestran colores cálidos frecuentes, coherentes con el efecto fin de año y rebalanceo pre-navideño.

En conjunto, el heatmap demuestra que el riesgo del \(QQQ\) no se distribuye uniformemente a lo largo del año, sino que se concentra en ventanas específicas. Septiembre emerge como mes vulnerables, mientras enero, noviembre y diciembre exhiben sesgo alcista recurrente. Esta estructura estacional tiene relevancia limitada para pronósticos \(ARIMA\) de frecuencia diaria (como en este análisis), pero es importante para decisiones de asignación táctica o rebalanceo de portafolios en horizonte mensual.

3.2.4 Comparación rendimientos

tesla_pal <- list(
  primary = "#cc0000",
  secondary = "#000000",
  text_main = "#333333",
  text_gray = "#666666"
)
theme_tesla <- function() {
  theme_minimal(base_family = "Inter") +
    theme(
      plot.title = element_text(face = "bold", size = 16, color = tesla_pal$text_main),
      plot.subtitle = element_text(size = 11, color = tesla_pal$text_gray, margin = margin(b = 15)),
      legend.position = "none",
      panel.grid.minor = element_blank(),
      panel.grid.major.x = element_blank(),
      panel.grid.major.y = element_line(color = "#e5e5e5", linetype = "dashed"),
      axis.text = element_text(color = tesla_pal$text_gray),
      axis.title = element_text(color = tesla_pal$text_gray, size = 10)
    )
}

tickers <- c("QQQ", "SPY", "DIA", "IWM")
nombres_map <- c(
  "QQQ" = "QQQ (Nasdaq-100)",
  "SPY" = "SPY (S&P 500)",
  "DIA" = "DIA (Dow Jones)",
  "IWM" = "IWM (Small Caps)"
)

datos_comp <- tq_get(tickers, get = "stock.prices", from = "2010-01-01")
datos_norm <- datos_comp %>%
  group_by(symbol) %>%
  mutate(
    Retorno_Acum = (adjusted / first(adjusted)) - 1,
    Nombre = nombres_map[symbol]
  ) %>%
  ungroup()

colores_comp <- c(
  "QQQ" = tesla_pal$primary,   
  "SPY" = "#2c3e50",           
  "DIA" = "#7f8c8d",        
  "IWM" = "#f39c12"            
)

p_comp <- ggplot(datos_norm, aes(x = date, y = Retorno_Acum, color = symbol)) +
  geom_line(aes(size = symbol, alpha = symbol)) +
  
  scale_color_manual(values = colores_comp, labels = nombres_map) +
  scale_size_manual(values = c("QQQ" = 1.2, "SPY" = 0.6, "DIA" = 0.6, "IWM" = 0.6), guide="none") +
  scale_alpha_manual(values = c("QQQ" = 1, "SPY" = 0.7, "DIA" = 0.7, "IWM" = 0.6), guide="none") +
  
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  
  labs(
    title = "QQQ vs El Mercado",
    subtitle = "Rendimiento acumulado comparativo (2010 - Presente)",
    x = "",
    y = "Retorno Acumulado"
  ) +
  theme_tesla()

plotly::ggplotly(p_comp, tooltip = c("x", "y", "colour")) %>%
  layout(
    legend = list(
      orientation = "h", 
      x = 0.5, 
      xanchor = "center",
      y = 1.05,
      title = list(text = "")
    ),
    hovermode = "x unified"
  ) %>%
  config(displayModeBar = FALSE)

La comparación normalizada del retorno acumulado entre el \(QQQ\) (Nasdaq-100) y los principales índices de referencia —SPY (S&P 500), DIA (Dow Jones Industrial Average) e IWM (Russell 2000 / Small Caps) durante el período 2010-2025 evidencia un desacople estructural en la generación de valor bursátil. Visualmente, la trayectoria del \(QQQ\) (línea roja prominente) se separa del clúster de mercado general a partir de 2015, confirmando que la exposición al factor tecnológico ha funcionado como el motor primario de apreciación de capital en la economía moderna.

El período 2010-2014 muestra un desempeño relativo moderado del \(QQQ\) frente a SPY y DIA, con trayectorias aproximadamente paralelas. Este comportamiento refleja que en la fase inicial de recuperación post-Crisis Financiera, los diferentes sectores generaron retornos homogéneos bajo estímulo monetario expansivo. El IWM, aunque presente, mostró sensibilidad mayor a la volatilidad cíclica.

La verdadera bifurcación se consolida post-2015 y se acelera verticalmente tras el shock pandémico de 2020. El \(QQQ\) se dispara mientras el IWM lucha por mantener el ritmo, penalizado por el entorno de altas tasas de interés que afecta desproporcionadamente a empresas de menor capitalización. El SPY y DIA crecen consistentemente pero a ritmo inferior, reflejando que la dilución del factor tecnológico en índices amplios limita su exposición al crecimiento acelerado de mega-caps.

La brecha masiva visible en 2025, donde el retorno acumulado del \(QQQ\) alcanza niveles significativamente superiores (852.76%) frente a SPY y DIA (aproximadamente 400-500%), demuestra la eficiencia superior de la concentración tecnológica durante períodos de expansión digital e inteligencia artificial. Este desempeño diferencial no es aleatorio, sino consecuencia directa de la estructura del \(QQQ\): 53.6% en Tecnología, frente a ~30% del SPY, y <5% del DIA.

En conclusión, el gráfico ratifica que el \(QQQ\) no es un sustituto del mercado general, sino un vehículo de crecimiento agresivo. Su desempeño superior a largo plazo frente al SPY y al DIA justifica su inclusión en portafolios que buscan maximización de capital. Sin embargo, como se documentó en análisis previos, esta superior generación de retorno viene acompañada por volatilidad y drawdowns sistemáticamente superiores (39.0% máximo vs ~27% para SPY). El inversor en \(QQQ\) asume explícitamente una postura factorial hacia la tecnología, aceptando mayor riesgo idiosincrático a cambio de participación en el crecimiento de la “nueva economía” (Fama & French, 2015; Sharpe, 1964).

3.2.5 Partición de la serie

datos_plot <- data.frame(
  Fecha = index(precios),
  Precio = as.numeric(precios)
)

fecha_corte <- as.Date("2022-10-07")  
fecha_chatgpt <- as.Date("2022-11-30") 

ggplot(datos_plot, aes(x = Fecha, y = Precio)) +
  geom_line(color = tesla_pal$text_gray, alpha = 0.5, size = 0.5) +
    geom_line(data = subset(datos_plot, Fecha >= fecha_corte), 
            aes(x = Fecha, y = Precio), 
            color = tesla_pal$primary, size = 1.2) +
  
  geom_vline(xintercept = as.numeric(fecha_chatgpt), 
             color = "#8e44ad", linetype = "dashed", size = 0.9) +

  annotate("text", x = fecha_chatgpt, y = 320, 
           label = "Lanzamiento\nChatGPT", 
           angle = 90, vjust = -0.8, color = "#8e44ad", fontface="bold") +
  
  labs(
    title = "Impacto del Lanzamiento de ChatGPT",
    subtitle = "El inicio de la tendencia alcista coincide con la aparición de la IA Generativa",
    x = "", y = "Precio QQQ"
  ) +
  theme_tesla()

El gráfico visualiza el punto de inflexión más crítico en la historia reciente del \(QQQ\), identificando finales de 2022 como el inicio de un cambio de régimen estructural en el mercado tecnológico. La línea punteada marca la introducción pública de \(ChatGPT\) en noviembre de 2022, un evento que coincide con el final de la tendencia bajista de 2022 y el comienzo de una recuperación acelerada que ha llevado al índice a nuevos máximos históricos.

Este comportamiento confirma la hipótesis de una ruptura estructural (structural break) en la serie de tiempo. Durante 2022, el \(QQQ\) estuvo correlacionado negativamente con tasas de interés e inflación, siendo castigado por el ciclo restrictivo de la Reserva Federal. Sin embargo, la aparición de la Inteligencia Artificial Generativa actuó como un shock tecnológico exógeno que desacopló al índice de las presiones macroeconómicas tradicionales. La pendiente agresiva de la recuperación post-noviembre 2022 refleja un repricing masivo de valoraciones, impulsado por la expectativa de que la IA provocará un aumento en la productividad corporativa comparable a revoluciones tecnológicas previas (Eloundou et al., 2023).

Esta narrativa explica la aceleración visible entre 2023-2025, el \(QQQ\) ha generado retornos extraordinarios mientras la economía real permaneció bajo presión de altas tasas. El desacople es precisamente lo que cabría esperar si el mercado antecipase beneficios de largo plazo de la IA, independientes de ciclos macroeconómicos de corto plazo. La hegemonía de NVIDIA (9.33% del portafolio) y Microsoft (7.69%) refuerza esta tesis: ambas empresas son centrales en la infraestructura y aplicación de LLMs (Large Language Models).

En consecuencia, el gráfico demuestra que el mercado ha transicionado de un esquema de “valoración por descuento de flujos” (sensible a tasas) a un esquema de “valoración por crecimiento potencial” (sensible a adopción de IA). Cualquier estrategia de modelado predictivo debe reconocer que el período 2023-2025 representa una nueva fase estocástica caracterizada por momentum idiosincrático derivado de la revolución de los Grandes Modelos de Lenguaje, distinta de la dinámica pre-2022. El modelo \(ARIMA\) calibrado en esta ventana temporal captura correctamente esta nueva estructura, mientras que su aplicación a horizontes muy largos (décadas) estaría sujeta a riesgo de cambio de régimen futuro.

3.2.6 Inteligencia artificial linea de tiempo

library(ggplot2)
library(dplyr)
library(lubridate)
library(ggrepel) 
data_cronologia <- data.frame(
  Hito = c(
    "ChatGPT (OpenAI)", 
    "DALL·E 2", "Midjourney v3", "Stable Diffusion", 
    "Nuevo Bing", "Claude (Anthropic)", "GPT-4", "Copilot 365", 
    "Google I/O (AI)", "Llama 2", "Mistral 7B", "DALL·E 3", 
    "Gemini 1.0/Ultra", "Sora (Video)", "Gemini Android", 
    "Claude 3", "Llama 3", "GPT-4o", "PCs Copilot+"
  ),
  Fecha = as.Date(c(
    "2022-11-30", 
    "2022-04-06", "2022-07-25", "2022-08-22", 
    "2023-02-07", "2023-03-14", "2023-03-14", "2023-03-16", 
    "2023-05-10", "2023-07-18", "2023-09-27", "2023-10-19", 
    "2023-12-06", "2024-02-15", "2024-02-08", 
    "2024-03-04", "2024-04-18", "2024-05-13", "2024-05-20"  
  )),
  Categoria = factor(c(
    "EL PUNTO DE INFLEXIÓN",
    rep("🎨 IMAGEN Y VIDEO", 3),
    "🔄 INTEGRACIÓN", "📝 TEXTO Y LLMs", "📝 TEXTO Y LLMs", "🔄 INTEGRACIÓN",
    "🔄 INTEGRACIÓN", "📝 TEXTO Y LLMs", "📝 TEXTO Y LLMs", "🎨 IMAGEN Y VIDEO",
    "📝 TEXTO Y LLMs", "🎨 IMAGEN Y VIDEO", "🔄 INTEGRACIÓN",
    "📝 TEXTO Y LLMs", "📝 TEXTO Y LLMs", "📝 TEXTO Y LLMs", "🔄 INTEGRACIÓN"
  ), levels = c("EL PUNTO DE INFLEXIÓN", "📝 TEXTO Y LLMs", "🎨 IMAGEN Y VIDEO", "🔄 INTEGRACIÓN")),
  
  Importancia = c(
    "Critico", 
    "Normal", "Normal", "Normal", 
    "Critico", "Normal", "Critico", "Normal",
    "Normal", "Normal", "Normal", "Normal",
    "Critico", "Critico", "Normal",
    "Normal", "Normal", "Critico", "Normal"
  )
)

colores_cat <- c(
  "EL PUNTO DE INFLEXIÓN" = "#e17055", 
  "📝 TEXTO Y LLMs"       = "#00b894", 
  "🎨 IMAGEN Y VIDEO"     = "#06b6d4", 
  "🔄 INTEGRACIÓN"        = "#a29bfe"  
)

ggplot(data_cronologia, aes(x = Fecha, y = Categoria, color = Categoria)) +
  geom_line(aes(group = Categoria), size = 1, alpha = 0.3) +
  geom_point(aes(size = Importancia), alpha = 0.9) +
  geom_text_repel(
    aes(label = Hito), 
    size = 3.5, 
    fontface = "bold", 
    box.padding = 0.5,
    point.padding = 0.3,
    force = 2,
    direction = "y",      
    nudge_y = 0.2,        
    segment.color = "grey80"
  ) +
  scale_size_manual(values = c("Critico" = 5, "Normal" = 3), guide = "none") +
  scale_color_manual(values = colores_cat) +
  scale_x_date(date_breaks = "4 months", date_labels = "%b %Y") +
  geom_vline(xintercept = as.Date("2022-10-07"), linetype="dashed", color="#636e72") +
  annotate("text", x = as.Date("2022-10-07"), y = 4.3, label = "Inicio", 
           angle = 90, vjust = -0.5, size = 3, color="#636e72") +
  labs(
    title = "Cronología del Boom de la IA Generativa",
    subtitle = "Lanzamientos clave que definieron la tendencia (2022-2024)",
    x = "", y = ""
  ) +
  theme_tesla() +
  theme(
    legend.position = "none",
    axis.text.y = element_text(face = "bold", size = 10),
    panel.grid.major.y = element_line(linetype = "dotted") 
  )

El gráfico “Cronología del Boom de la IA Generativa” ilustra gráficamente cómo ChatGPT lo cambió todo: su lanzamiento en octubre de 2022 no fue un evento aislado, sino el detonante de una reacción en cadena que transformó radicalmente el mercado tecnológico en un lapso extremadamente corto. Como se observa en la línea de tiempo, desde este punto de inflexión nacieron y se desplegaron a una velocidad sin precedentes múltiples nuevas inteligencias artificiales que redefinieron sectores enteros. La rápida sucesión de hitos —que abarca desde la evolución de LLMs (GPT-4, Claude, Llama) y la generación de video (DALL-E 3, Sora), hasta la integración profunda en sistemas operativos y productividad (Copilot 365, Gemini Android)— demuestra una densidad de innovación que valida la tesis de un cambio de régimen acelerado.

Esta proliferación tecnológica ha sostenido el momentum del precio del \(QQQ\), validando la concentración del portafolio en los proveedores de infraestructura de \(IA\) (Microsoft, Google, NVIDIA) observada en las secciones anteriores. A la luz de este hallazgo y del análisis descriptivo exhaustivo realizado, se derivan conclusiones estadísticas fundamentales que condicionan la estrategia de modelado econométrico. Primero, la serie histórica del \(QQQ\) exhibe una no estacionariedad marcada y una tendencia exponencial que exige el uso de rendimientos logarítmicos y diferenciación. Segundo, la presencia de una curtosis extrema y agrupamientos de volatilidad (volatility clustering) visibles en los gráficos de riesgo confirman que los modelos lineales simples subestimarán la probabilidad de eventos de cola, justificando la necesidad de complementar la estimación de la media con modelos de volatilidad condicional (GARCH).

Finalmente, basándose en la evidencia visual y fundamental de la ruptura estructural provocada por la IA Generativa, se define el año 2022 como el punto de inicio para la ventana de entrenamiento del modelo predictivo. Incluir datos anteriores a esta fecha introduciría “ruido” en los parámetros del modelo, dado que la dinámica de precios de la década 2010-2021 respondía a un régimen de tasas cero y expansión monetaria, estructuralmente distinto al actual entorno de tasas medias e inversión intensiva en IA. La literatura econométrica sobre cambios estructurales (Perron, 1989) sugiere que, tras un shock permanente de esta magnitud, los datos previos pierden capacidad predictiva. Por consiguiente, al restringir la muestra al período post-ChatGPT, el modelo capturará con mayor fidelidad la inercia (momentum) y la volatilidad específica del actual “superciclo de IA”, optimizando la precisión de los pronósticos a corto plazo.


4. Resultados del Modelo ARIMA

4.1 Partición de Datos

4.1.1 Estrategia Train/Test

La aplicación de la estrategia de partición temporal al conjunto de datos del \(QQQ\) divide el período de análisis (octubre 2022 - presente) en dos subconjuntos contiguos que respetan el orden cronológico. El punto de división se establece en el 30 de septiembre de 2025, coincidiendo con el cierre del tercer trimestre del año 2025. Esta fecha marca un quiebre administrativo natural en calendarios financieros y evita arbitrariedades en la selección del período de corte.

El conjunto de entrenamiento comprende observaciones desde el 7 de octubre de 2022 hasta el 30 de septiembre de 2025, proporcionando una base robusta para estimación de coeficientes \(ARIMA\), mientras que el conjunto de prueba abarca desde el 1 de octubre de 2025 hasta el 1 de diciembre del mismo año, permitiendo validación con un horizonte de pronóstico consistente con estándares de análisis de corto plazo en mercados financieros (Hyndman & Athanasopoulos, 2021).

Entrenamiento <- window(Precio, start = "2022-10-07", end="2025-09-30")
Prueba <- window(Precio, start = "2025-10-01", end="2025-12-01")

4.1.2 Tabla Resumen: Observaciones por Conjunto

particion_resumen <- data.frame(
  Conjunto = c("Entrenamiento", "Prueba", "Total"),
  Período = c(
    "07-Oct-2022 → 30-Sep-2025",
    "01-Oct-2025 → 01-Dic-2025",
    "07-Oct-2022 → 01-Dic-2025"
  ),
  `Observaciones` = c(
    length(Entrenamiento),
    length(Prueba),
    length(Entrenamiento) + length(Prueba)
  ),
  Porcentaje = c(
    paste0(round(length(Entrenamiento)/(length(Entrenamiento)+length(Prueba))*100, 1), "%"),
    paste0(round(length(Prueba)/(length(Entrenamiento)+length(Prueba))*100, 1), "%"),
    "100%"
  ),
  Propósito = c(
    "Estimación y validación de modelo",
    "Evaluación de capacidad predictiva",
    ""
  )
)

kable(particion_resumen,
      caption = "Resumen de Partición de Datos: Entrenamiento vs Prueba",
      align = c("l", "c", "c", "c", "l")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(3, bold = TRUE, color = qqq_pal$positive) %>%
  row_spec(3, bold = TRUE, background = "#e8f5e9", color = qqq_pal$text_dark)
Resumen de Partición de Datos: Entrenamiento vs Prueba
Conjunto Período Observaciones Porcentaje Propósito
Entrenamiento 07-Oct-2022 → 30-Sep-2025 747 94.6% Estimación y validación de modelo
Prueba 01-Oct-2025 → 01-Dic-2025 43 5.4% Evaluación de capacidad predictiva
Total 07-Oct-2022 → 01-Dic-2025 790 100%

El conjunto de entrenamiento contiene 747 observaciones diarias (aproximadamente 3 años de negociación), representando aproximadamente el 95% del total de datos disponibles. Este volumen es más que suficiente para identificar parámetros confiables de un modelo \(ARIMA\) de complejidad moderada. El conjunto de prueba contiene observaciones de aproximadamente 2 meses (octubre a diciembre 2025), proporcionando un horizonte de validación adecuado para evaluar la capacidad predictiva del modelo en condiciones de mercado reales.

4.1.3 Visualización: Serie con Partición

df_train <- data.frame(
  Fecha = index(Entrenamiento),
  Precio = as.numeric(Entrenamiento),
  Conjunto = "Entrenamiento"
)

df_test <- data.frame(
  Fecha = index(Prueba),
  Precio = as.numeric(Prueba),
  Conjunto = "Prueba"
)

df_completo <- bind_rows(df_train, df_test)
fecha_corte <- as.Date("2025-10-01")
fecha_fin_prueba <- as.Date("2025-12-01")

ggplot(df_completo, aes(x = Fecha, y = Precio)) +
  geom_ribbon(data = df_train, 
              aes(ymin = min(df_completo$Precio) * 0.95, ymax = Precio),
              fill = qqq_pal$primary, alpha = 0.08) +
  geom_ribbon(data = df_test, 
              aes(ymin = min(df_completo$Precio) * 0.95, ymax = Precio),
              fill = qqq_pal$secondary, alpha = 0.15) +
  geom_line(data = df_train, color = qqq_pal$primary, linewidth = 0.9) +
  geom_line(data = df_test, color = qqq_pal$secondary, linewidth = 1.1) +
  geom_vline(xintercept = fecha_corte, 
             linetype = "dashed", color = qqq_pal$negative, linewidth = 0.8) +
  geom_vline(xintercept = fecha_fin_prueba, 
             linetype = "dashed", color = qqq_pal$accent, linewidth = 0.8, alpha = 0.6) +
  annotate("text", x = fecha_corte, y = max(df_completo$Precio) * 1.02,
           label = "Inicio Prueba: 01-Oct-2025", hjust = -0.05, vjust = 0,
           color = qqq_pal$negative, fontface = "bold", size = 3.5) +
  annotate("text", x = fecha_fin_prueba, y = max(df_completo$Precio) * 0.98,
           label = "Fin Prueba: 01-Dic-2025", hjust = 1.1, vjust = 0,
           color = qqq_pal$accent, fontface = "bold", size = 3.5) +
  annotate("label", 
           x = as.Date("2024-01-01"), 
           y = max(df_completo$Precio) * 0.85,
           label = paste0("ENTRENAMIENTO\n", nrow(df_train), " observaciones"),
           fill = qqq_pal$primary, color = "white", 
           fontface = "bold", size = 3.5, label.padding = unit(0.5, "lines")) +
  annotate("label", 
           x = as.Date("2025-11-01"),
           y = min(df_completo$Precio) * 1.15,
           label = paste0("PRUEBA\n", nrow(df_test), " observaciones"),
           fill = qqq_pal$secondary, color = "white", 
           fontface = "bold", size = 3.2, label.padding = unit(0.4, "lines")) +
  scale_x_date(date_breaks = "4 months", date_labels = "%b %Y",
               expand = expansion(mult = c(0.02, 0.05))) +
  scale_y_continuous(labels = dollar_format(prefix = "$"),
                     expand = expansion(mult = c(0.05, 0.08))) +
  labs(
    title = "Partición de Datos: Entrenamiento vs Prueba",
    subtitle = "QQQ (Nasdaq-100 ETF) | Serie de precios de cierre diarios",
    x = NULL,
    y = "Precio de Cierre (USD)",
    caption = paste0("Fuente: Yahoo Finance | Período: ", 
                     min(df_completo$Fecha), " a ", max(df_completo$Fecha))
  ) +
  theme_QQQ() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


4.2 Análisis de Estacionariedad

La serie de precios del \(QQQ\) exhibe visualmente una tendencia alcista pronunciada con fluctuaciones amplias alrededor de una trayectoria creciente durante el período de entrenamiento (octubre 2022 - septiembre 2025). El gráfico de autocorrelación de la serie en niveles revela el síntoma clásico de no-estacionariedad:

acf_data <- acf(Entrenamiento, lag.max = 30, plot = FALSE)

df_acf <- data.frame(
  Lag = acf_data$lag[-1], 
  ACF = acf_data$acf[-1]
)

n <- length(Entrenamiento)
limite_sup <- qnorm(0.975) / sqrt(n)
limite_inf <- -limite_sup

ggplot(df_acf, aes(x = Lag, y = ACF)) +
  geom_segment(aes(xend = Lag, yend = 0), 
               color = qqq_pal$primary, linewidth = 0.8) +
  geom_point(color = qqq_pal$primary, size = 2) +
  geom_hline(yintercept = limite_sup, linetype = "dashed", 
             color = qqq_pal$secondary, linewidth = 0.7) +
  geom_hline(yintercept = limite_inf, linetype = "dashed", 
             color = qqq_pal$secondary, linewidth = 0.7) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  annotate("rect", xmin = -Inf, xmax = Inf, 
           ymin = limite_inf, ymax = limite_sup,
           fill = qqq_pal$secondary, alpha = 0.1) +
  annotate("label", x = 20, y = 0.5,
           label = "Decaimiento lento\n→ Serie NO estacionaria",
           fill = qqq_pal$negative, color = "white",
           fontface = "bold", size = 3.5, label.padding = unit(0.5, "lines")) +
  scale_x_continuous(breaks = seq(0, 30, 5)) +
  scale_y_continuous(limits = c(-0.1, 1.05), breaks = seq(0, 1, 0.25)) +
  labs(
    title = "Función de Autocorrelación (ACF) - Serie en Niveles",
    subtitle = "QQQ: Precio de cierre | Datos de entrenamiento",
    x = "Rezago (Lag)",
    y = "Autocorrelación",
    caption = "Bandas azules: Límites de significancia al 95%"
  ) +
  theme_QQQ()

La autocorrelación muestral permanece elevada (>0.85) incluso en rezagos distantes (lag 30). Este decaimiento lento es indicador clásico de que la serie contiene raíz unitaria y requiere diferenciación. Adicionalmente, casi todos los rezagos caen fuera de las bandas de confianza, confirmando correlación sistemática estructural.

4.2.2 Contraste Estadístico: Test de Dickey-Fuller Aumentado (ADF)

adf_resultado <- adf.test(Entrenamiento)

tabla_adf <- data.frame(
  Métrica = c("Estadístico Dickey-Fuller", 
              "Orden de Rezagos (Lag)", 
              "P-valor",
              "Nivel de Significancia (α)",
              "Conclusión"),
  Valor = c(round(adf_resultado$statistic, 4),
            adf_resultado$parameter,
            round(adf_resultado$p.value, 4),
            "0.05",
            ifelse(adf_resultado$p.value > 0.05, 
                   "Serie NO estacionaria", "Serie estacionaria ✓"))
)

kable(tabla_adf, 
      caption = "Prueba de Dickey-Fuller Aumentada (ADF) - Serie en Niveles",
      align = c("l", "c")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  row_spec(3, bold = TRUE, color = qqq_pal$negative, background = "#ffe8e0") %>% 
  row_spec(5, bold = TRUE, background = "#fef3f2", color = qqq_pal$text_dark)
Prueba de Dickey-Fuller Aumentada (ADF) - Serie en Niveles
Métrica Valor
Estadístico Dickey-Fuller -3.0468
Orden de Rezagos (Lag) 9
P-valor 0.1352
Nivel de Significancia (α) 0.05
Conclusión Serie NO estacionaria

Con p-valor de 0.1352 > 0.05, no se rechaza la hipótesis nula: la serie de precios del \(QQQ\) en niveles es no-estacionaria. Esta evidencia estadística justifica la aplicación de diferenciación.

4.2.3 Aplicación de Diferenciación de Primer Orden

dif_Entrenamiento <- diff(Entrenamiento) %>% na.omit()
df_diff <- data.frame(
  Fecha = index(dif_Entrenamiento),
  Valor = as.numeric(dif_Entrenamiento)
)

ggplot(df_diff, aes(x = Fecha, y = Valor)) +
  geom_line(color = qqq_pal$secondary, linewidth = 0.6) +
  geom_hline(yintercept = 0, linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.7) +
  annotate("label", 
           x = as.Date("2023-06-01"), 
           y = max(df_diff$Valor) * 0.85,
           label = paste0("Media ≈ ", round(mean(df_diff$Valor), 3)),
           fill = qqq_pal$primary, color = "white",
           fontface = "bold", size = 3.5, label.padding = unit(0.4, "lines")) +
  scale_x_date(date_breaks = "4 months", date_labels = "%b %Y",
               expand = expansion(mult = c(0.02, 0.03))) +
  scale_y_continuous(labels = scales::dollar_format(prefix = "$"),
                     expand = expansion(mult = c(0.05, 0.08))) +
  labs(
    title = "Serie Diferenciada de Primer Orden (d = 1)",
    subtitle = "QQQ: Cambios diarios en precio de cierre | Datos de entrenamiento",
    x = NULL,
    y = "Cambio Diario (USD)",
    caption = paste0("Observaciones: ", nrow(df_diff), 
                     " | Período: ", min(df_diff$Fecha), " a ", max(df_diff$Fecha))
  ) +
  theme_QQQ() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

La serie diferenciada del \(QQQ\) oscila alrededor de media aproximadamente cero (0.444), sin tendencia visual evidente. La media permanece relativamente constante a lo largo del período, característica fundamental de estacionariedad.

4.2.4 Verificación Post-Diferenciación

acf_diff_data <- acf(dif_Entrenamiento, lag.max = 30, plot = FALSE)

df_acf_diff <- data.frame(
  Lag = acf_diff_data$lag[-1],
  ACF = acf_diff_data$acf[-1]
)

n_diff <- length(dif_Entrenamiento)
limite_sup_diff <- qnorm(0.975) / sqrt(n_diff)
limite_inf_diff <- -limite_sup_diff

ggplot(df_acf_diff, aes(x = Lag, y = ACF)) +
  geom_segment(aes(xend = Lag, yend = 0), 
               color = qqq_pal$secondary, linewidth = 0.8) +
  geom_point(color = qqq_pal$secondary, size = 2) +
  geom_hline(yintercept = limite_sup_diff, linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.7) +
  geom_hline(yintercept = limite_inf_diff, linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.7) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  annotate("rect", xmin = -Inf, xmax = Inf, 
           ymin = limite_inf_diff, ymax = limite_sup_diff,
           fill = qqq_pal$primary, alpha = 0.1) +
  annotate("label", x = 22, y = 0.12,
           label = "Autocorrelaciones dentro\nde bandas → Estacionaria ✓",
           fill = qqq_pal$positive, color = "white",
           fontface = "bold", size = 3.5, label.padding = unit(0.5, "lines")) +
  scale_x_continuous(breaks = seq(0, 30, 5)) +
  scale_y_continuous(limits = c(-0.15, 0.2), breaks = seq(-0.1, 0.2, 0.05)) +
  labs(
    title = "Función de Autocorrelación (ACF) - Serie Diferenciada",
    subtitle = "QQQ: Cambios diarios | Verificación de estacionariedad post-diferenciación",
    x = "Rezago (Lag)",
    y = "Autocorrelación",
    caption = "Bandas verdes: Límites de significancia al 95%"
  ) +
  theme_QQQ()

La mayoría de autocorrelaciones caen dentro de las bandas de confianza. Este contraste dramático con el \(ACF\) de la serie original en niveles valida la diferenciación.

adf_diff_resultado <- adf.test(dif_Entrenamiento)

tabla_adf_diff <- data.frame(
  Métrica = c("Estadístico Dickey-Fuller", 
              "Orden de Rezagos (Lag)", 
              "P-valor",
              "Conclusión"),
  Valor = c(round(adf_diff_resultado$statistic, 4),
            adf_diff_resultado$parameter,
            round(adf_diff_resultado$p.value, 4),
            ifelse(adf_diff_resultado$p.value < 0.05,
                   "Serie ES estacionaria ✓",
                   "Serie NO estacionaria"))
)

kable(tabla_adf_diff, 
      caption = "Prueba de Dickey-Fuller Aumentada (ADF) - Serie Diferenciada (d=1)",
      align = c("l", "c")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  row_spec(3, bold = TRUE, color = qqq_pal$positive, background = "#e8f5e9") %>%
  row_spec(4, bold = TRUE, background = "#d4edda", color = qqq_pal$text_dark)
Prueba de Dickey-Fuller Aumentada (ADF) - Serie Diferenciada (d=1)
Métrica Valor
Estadístico Dickey-Fuller -8.6831
Orden de Rezagos (Lag) 9
P-valor 0.01
Conclusión Serie ES estacionaria ✓

El estadístico ADF de -8.6831 es altamente negativo, muy inferior al valor crítico de -3.43. Con p-valor de 0.01 < 0.05, se rechaza \(H_0\). La serie diferenciada del \(QQQ\) es estacionaria. Por tanto, el parámetro de integración es \(d=1\): una única diferenciación convierte la serie de precios en una serie estacionaria de cambios diarios.


4.3 Identificación del Modelo

El análisis visual del \(ACF\) y \(PACF\) de la serie diferenciada del \(QQQ\) revela patrones característicos de mercados financieros eficientes:

acf_data <- acf(dif_Entrenamiento, lag.max = 28, plot = FALSE)
pacf_data <- pacf(dif_Entrenamiento, lag.max = 28, plot = FALSE)

df_acf <- data.frame(
  Lag = as.numeric(acf_data$lag[-1]),
  Valor = as.numeric(acf_data$acf[-1])
)

df_pacf <- data.frame(
  Lag = as.numeric(pacf_data$lag),
  Valor = as.numeric(pacf_data$acf)
)

n <- length(dif_Entrenamiento)
limite <- qnorm(0.975) / sqrt(n)

p_acf <- ggplot(df_acf, aes(x = Lag, y = Valor)) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  geom_hline(yintercept = c(-limite, limite), linetype = "dashed", 
             color = qqq_pal$secondary, linewidth = 0.6) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = -limite, ymax = limite,
           fill = qqq_pal$secondary, alpha = 0.08) +
  geom_segment(aes(xend = Lag, yend = 0), color = qqq_pal$primary, linewidth = 0.7) +
  geom_point(color = qqq_pal$primary, size = 1.5) +
  scale_x_continuous(breaks = seq(0, 28, 5)) +
  scale_y_continuous(limits = c(-0.15, 0.12)) +
  labs(title = "ACF - Serie Diferenciada",
       subtitle = "Identificación del orden q (MA)",
       x = "Rezago (Lag)",
       y = "ACF") +
  theme_QQQ() +
  theme(plot.title = element_text(size = 12))

p_pacf <- ggplot(df_pacf, aes(x = Lag, y = Valor)) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  geom_hline(yintercept = c(-limite, limite), linetype = "dashed", 
             color = qqq_pal$secondary, linewidth = 0.6) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = -limite, ymax = limite,
           fill = qqq_pal$secondary, alpha = 0.08) +
  geom_segment(aes(xend = Lag, yend = 0), color = qqq_pal$primary, linewidth = 0.7) +
  geom_point(color = qqq_pal$primary, size = 1.5) +
  scale_x_continuous(breaks = seq(0, 28, 5)) +
  scale_y_continuous(limits = c(-0.15, 0.12)) +
  labs(title = "PACF - Serie Diferenciada",
       subtitle = "Identificación del orden p (AR)",
       x = "Rezago (Lag)",
       y = "PACF") +
  theme_QQQ() +
  theme(plot.title = element_text(size = 12))

grid.arrange(p_acf, p_pacf, ncol = 2)

En el \(ACF\), la mayoría de autocorrelaciones caen dentro de las bandas de confianza para todos los rezagos hasta lag 28. Esta ausencia sistemática es consistente con la hipótesis de mercado eficiente: los precios incorporan información disponible públicamente, dejando en los cambios diarios estructura prácticamente aleatoria sin dependencias predecibles (Fama, 1970; Malkiel, 1973).

El \(PACF\) exhibe un patrón complementario: nuevamente, la mayoría de autocorrelaciones parciales se ubican dentro de bandas de confianza. En conjunto, el análisis \(ACF/PACF\) sugiere que la serie diferenciada es cercana a ruido blanco, implicando que cualquier modelo \(ARIMA\) que intente capturar estructura estará fundamentalmente limitado en capacidad predictiva, capturando quizás pequeños componentes de ineficiencia de mercado de corto plazo (Tsay, 2010; Hamilton, 1994).

4.3.2 Modelos ARIMA Candidatos

tabla_candidatos <- data.frame(
  Modelo = c("ARIMA(0,1,0)", 
             "ARIMA(1,1,1)",
             "ARIMA(2,1,1)", 
             "ARIMA(1,1,2)",
             "ARIMA(2,1,2)",
             "ARIMA(3,1,3)"),
  Tipo = c("Random Walk",
           "auto.arima()",
           "Manual",
           "Manual",
           "Manual",
           "Exploratorio"),
  Justificación = c(
    "Benchmark: hipótesis de mercado eficiente",
    "Referencia algorítmica para validar selección manual",
    "Extensión AR(2) para capturar persistencia de corto plazo",
    "Extensión MA(2) para capturar estructura de media móvil",
    "Modelo simétrico que combina dinámicas AR y MA",
    "Evaluar si rezagos marginales aportan capacidad predictiva"
  )
)

kable(tabla_candidatos,
      caption = "Modelos ARIMA Candidatos para Evaluación",
      align = c("l", "c", "l"),
      col.names = c("Modelo", "Tipo", "Justificación")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(2, color = qqq_pal$secondary) %>%
  column_spec(3, width = "30em") %>%
  row_spec(2, background = "#e8f5e9", color = qqq_pal$text_dark, bold = TRUE)
Modelos ARIMA Candidatos para Evaluación
Modelo Tipo Justificación
ARIMA(0,1,0) Random Walk Benchmark: hipótesis de mercado eficiente
ARIMA(1,1,1) auto.arima() Referencia algorítmica para validar selección manual
ARIMA(2,1,1) Manual Extensión AR(2) para capturar persistencia de corto plazo
ARIMA(1,1,2) Manual Extensión MA(2) para capturar estructura de media móvil
ARIMA(2,1,2) Manual Modelo simétrico que combina dinámicas AR y MA
ARIMA(3,1,3) Exploratorio Evaluar si rezagos marginales aportan capacidad predictiva

La selección de estos seis modelos candidatos obedece a una lógica progresiva de complejidad. El \(ARIMA(0,1,0)\) (random walk) representa la hipótesis nula de mercado eficiente: no existe estructura explorable. El \(ARIMA(1,1,1)\) fue seleccionado automáticamente por auto.arima() y es el más parsimonioso que añade estructura genuina. Los demás representan extensiones que exploran si estructura adicional existe en la serie del \(QQQ\).


4.4 Estimación y Comparación de Modelos

4.4.1 Criterios de Información

ModeloQA <- auto.arima(Entrenamiento)
modeloQ1 <- Arima(Entrenamiento, order = c(3,1,3))
modeloQ2 <- Arima(Entrenamiento, order = c(0,1,0))
modeloQ3 <- Arima(Entrenamiento, order = c(2,1,1))
modeloQ4 <- Arima(Entrenamiento, order = c(1,1,2))
modeloQ5 <- Arima(Entrenamiento, order = c(2,1,2))
comparacion_IC <- data.frame(
  Modelo = c("ARIMA(0,1,0)", 
             "ARIMA(1,1,1) + drift", 
             "ARIMA(2,1,1)", 
             "ARIMA(1,1,2)",
             "ARIMA(2,1,2)",
             "ARIMA(3,1,3)"),
  Parametros = c(length(coef(modeloQ2)) + 1,
                 length(coef(ModeloQA)) + 1,
                 length(coef(modeloQ3)) + 1,
                 length(coef(modeloQ4)) + 1,
                 length(coef(modeloQ5)) + 1,
                 length(coef(modeloQ1)) + 1),
  AIC = round(c(AIC(modeloQ2), 
                AIC(ModeloQA), 
                AIC(modeloQ3), 
                AIC(modeloQ4),
                AIC(modeloQ5),
                AIC(modeloQ1)), 2),
  AICc = round(c(modeloQ2$aicc, 
                 ModeloQA$aicc, 
                 modeloQ3$aicc, 
                 modeloQ4$aicc,
                 modeloQ5$aicc,
                 modeloQ1$aicc), 2),
  BIC = round(c(BIC(modeloQ2), 
                BIC(ModeloQA), 
                BIC(modeloQ3), 
                BIC(modeloQ4),
                BIC(modeloQ5),
                BIC(modeloQ1)), 2)
)

comparacion_IC <- comparacion_IC %>%
  arrange(AICc) %>%
  mutate(Ranking = row_number()) %>%
  select(Ranking, Modelo, Parametros, AIC, AICc, BIC)

kable(comparacion_IC,
      caption = "Comparación de Modelos por Criterios de Información",
      align = c("c", "l", "c", "c", "c", "c"),
      col.names = c("Ranking", "Modelo", "# Parámetros", "AIC", "AICc", "BIC")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(2, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(5, bold = TRUE, color = qqq_pal$positive) %>%
  row_spec(1, bold = TRUE, background = "#e8f5e9", color = qqq_pal$text_dark) %>%
  footnote(general = "Ordenado por AICc (menor es mejor). AICc es el criterio preferido para muestras finitas.",
           general_title = "Nota: ")
Comparación de Modelos por Criterios de Información
Ranking Modelo # Parámetros AIC AICc BIC
1 ARIMA(1,1,1) + drift 4 4663.89 4663.94 4682.35
2 ARIMA(2,1,2) 5 4668.06 4668.14 4691.13
3 ARIMA(0,1,0) 1 4668.38 4668.39 4673.00
4 ARIMA(1,1,2) 4 4668.46 4668.52 4686.92
5 ARIMA(2,1,1) 4 4668.52 4668.58 4686.98
6 ARIMA(3,1,3) 7 4669.04 4669.19 4701.34
Nota:
Ordenado por AICc (menor es mejor). AICc es el criterio preferido para muestras finitas.

El \(ARIMA(1,1,1)\) + drift del \(QQQ\) emerge como ganador indiscutible con \(AICc\) = 4663.94, significativamente menor que \(ARIMA(2,1,2)\) (4668.14, ranking 2). La diferencia de 4.2 puntos en \(AICc\) es clara, validando \(ARIMA(1,1,1)\) como notablemente superior. Según Burnham & Anderson (2002), diferencias entre 4-7 indican soporte moderado para modelo superior. El término “drift” representa una constante en la ecuación de diferencias que captura la tendencia lineal implícita: durante el período de análisis (2022-2025), el \(QQQ\) exhibió movimiento alcista promedio, reflejando optimismo en tecnología pese a volatilidad (Brockwell & Davis, 2016).

La evaluación de modelos más complejos revela el problema de sobreparametrización: aunque \(ARIMA(3,1,3)\) tiene \(AIC\) más bajo (4669.04), su \(AICc\) es 4669.19 (ranking 6) porque la penalización por 7 parámetros domina cualquier mejora marginal. El \(ARIMA(0,1,0)\) (random walk puro) produce \(AICc =\) 4668.39 (ranking 3), confirmando que estructura existe aunque sea pequeña.

4.4.2 Métricas de Precisión en Entrenamiento

acc_QA <- accuracy(ModeloQA)
acc_Q1 <- accuracy(modeloQ1)
acc_Q2 <- accuracy(modeloQ2)
acc_Q3 <- accuracy(modeloQ3)
acc_Q4 <- accuracy(modeloQ4)
acc_Q5 <- accuracy(modeloQ5)

comparacion_accuracy <- data.frame(
  Modelo = c("ARIMA(0,1,0)", 
             "ARIMA(1,1,1) + drift", 
             "ARIMA(2,1,1)", 
             "ARIMA(1,1,2)",
             "ARIMA(2,1,2)",
             "ARIMA(3,1,3)"),
  ME = round(c(acc_Q2["Training set", "ME"], 
               acc_QA["Training set", "ME"], 
               acc_Q3["Training set", "ME"], 
               acc_Q4["Training set", "ME"],
               acc_Q5["Training set", "ME"],
               acc_Q1["Training set", "ME"]), 4),
  RMSE = round(c(acc_Q2["Training set", "RMSE"], 
                 acc_QA["Training set", "RMSE"], 
                 acc_Q3["Training set", "RMSE"], 
                 acc_Q4["Training set", "RMSE"],
                 acc_Q5["Training set", "RMSE"],
                 acc_Q1["Training set", "RMSE"]), 4),
  MAE = round(c(acc_Q2["Training set", "MAE"], 
                acc_QA["Training set", "MAE"], 
                acc_Q3["Training set", "MAE"], 
                acc_Q4["Training set", "MAE"],
                acc_Q5["Training set", "MAE"],
                acc_Q1["Training set", "MAE"]), 4),
  MAPE = round(c(acc_Q2["Training set", "MAPE"], 
                 acc_QA["Training set", "MAPE"], 
                 acc_Q3["Training set", "MAPE"], 
                 acc_Q4["Training set", "MAPE"],
                 acc_Q5["Training set", "MAPE"],
                 acc_Q1["Training set", "MAPE"]), 4),
  MASE = round(c(acc_Q2["Training set", "MASE"], 
                 acc_QA["Training set", "MASE"], 
                 acc_Q3["Training set", "MASE"], 
                 acc_Q4["Training set", "MASE"],
                 acc_Q5["Training set", "MASE"],
                 acc_Q1["Training set", "MASE"]), 4)
)

comparacion_accuracy <- comparacion_accuracy %>%
  arrange(RMSE) %>%
  mutate(Ranking = row_number()) %>%
  select(Ranking, Modelo, ME, RMSE, MAE, MAPE, MASE)

kable(comparacion_accuracy,
      caption = "Métricas de Precisión sobre Datos de Entrenamiento",
      align = c("c", "l", rep("c", 5))) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(2, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(4, bold = TRUE, color = qqq_pal$positive) %>%
  row_spec(1, background = "#e8f5e9", color = qqq_pal$text_dark, bold = TRUE) %>%
  footnote(general = "ME: Error Medio | RMSE: Raíz del Error Cuadrático Medio | MAE: Error Absoluto Medio | MAPE: Error Porcentual (%) | MASE: Error Escalado",
           general_title = "Métricas: ")
Métricas de Precisión sobre Datos de Entrenamiento
Ranking Modelo ME RMSE MAE MAPE MASE
1 ARIMA(3,1,3) 0.4939 5.4759 3.9216 0.9540 1.0074
2 ARIMA(1,1,1) + drift -0.0001 5.4792 3.8704 0.9445 0.9943
3 ARIMA(2,1,2) 0.4405 5.4867 3.8894 0.9449 0.9992
4 ARIMA(1,1,2) 0.4439 5.4960 3.9003 0.9500 1.0020
5 ARIMA(2,1,1) 0.4446 5.4962 3.9000 0.9499 1.0019
6 ARIMA(0,1,0) 0.4438 5.5179 3.8878 0.9444 0.9988
Métricas:
ME: Error Medio | RMSE: Raíz del Error Cuadrático Medio | MAE: Error Absoluto Medio | MAPE: Error Porcentual (%) | MASE: Error Escalado

El Error Medio (ME) de todos los modelos es cercano a cero (rango: -0.0001 a 0.4939), confirmando que son aproximadamente insesgados. El \(ARIMA(1,1,1)\) + drift tiene \(ME =\) -0.0001, virtualmente perfecto. El \(RMSE\) del \(ARIMA(3,1,3)\) lidera con 5.4759, marginalmente inferior al \(ARIMA(1,1,1)\) + drift (5.4792), una diferencia de 0.0033 negligible en términos prácticos (0.06% mejora) mientras requiere 75% incremento en parámetros.

El Error Absoluto Medio (MAE) del \(ARIMA(1,1,1)\) + drift es 3.8704: en promedio, predicciones desviaron ±3.87 puntos del valor real. El MAPE es 0.9445%, indicando error promedio menos de 1% del valor real. El MASE de todos los modelos es < 1, mejorando al random walk puro. El \(ARIMA(1,1,1)\) + drift obtiene \(MASE =\) 0.9943, mejorando al random walk en ~0.6%—en contexto de series financieras eficientes, una mejora significativa (Hyndman & Koehler, 2006).


4.5 Diagnóstico de Residuos

El proceso de diagnóstico valida que el modelo \(ARIMA(1,1,1)\) + drift seleccionado produce residuos que se comportan como ruido blanco: secuencia aleatoria con media cero, varianza constante, y ausencia de autocorrelación.

4.5.1 Análisis Gráfico de Residuos

residuos <- residuals(ModeloQA)

df_residuos <- data.frame(
  Fecha = index(residuos),
  Residuo = as.numeric(residuos)
)

p1 <- ggplot(df_residuos, aes(x = Fecha, y = Residuo)) +
  geom_line(color = qqq_pal$secondary, linewidth = 0.5) +
  geom_hline(yintercept = 0, linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.7) +
  geom_hline(yintercept = c(-2*sd(df_residuos$Residuo), 2*sd(df_residuos$Residuo)), 
             linetype = "dotted", color = qqq_pal$negative, linewidth = 0.5) +
  scale_x_date(date_breaks = "6 months", date_labels = "%b %Y") +
  labs(title = "Residuos del Modelo en el Tiempo",
       subtitle = "Verificación de media cero y varianza constante",
       x = NULL,
       y = "Residuo") +
  theme_QQQ() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

p1

acf_resid <- acf(residuos, lag.max = 25, plot = FALSE)
df_acf_resid <- data.frame(
  Lag = as.numeric(acf_resid$lag[-1]),
  ACF = as.numeric(acf_resid$acf[-1])
)

n_resid <- length(residuos)
limite_resid <- qnorm(0.975) / sqrt(n_resid)

p2 <- ggplot(df_acf_resid, aes(x = Lag, y = ACF)) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  geom_hline(yintercept = c(-limite_resid, limite_resid), linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.6) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = -limite_resid, ymax = limite_resid,
           fill = qqq_pal$primary, alpha = 0.1) +
  geom_segment(aes(xend = Lag, yend = 0), color = qqq_pal$secondary, linewidth = 0.7) +
  geom_point(color = qqq_pal$secondary, size = 1.5) +
  scale_x_continuous(breaks = seq(0, 25, 5)) +
  scale_y_continuous(limits = c(-0.15, 0.15)) +
  labs(title = "ACF de Residuos",
       subtitle = "Verificación de independencia",
       x = "Rezago (Lag)",
       y = "ACF") +
  theme_QQQ()
p2

p3 <- ggplot(df_residuos, aes(x = Residuo)) +
  geom_histogram(aes(y = after_stat(density)), 
                 bins = 35, fill = qqq_pal$primary, 
                 color = "white", alpha = 0.7) +
  geom_density(color = qqq_pal$secondary, linewidth = 1) +
  stat_function(fun = dnorm, 
                args = list(mean = mean(df_residuos$Residuo), 
                            sd = sd(df_residuos$Residuo)),
                color = qqq_pal$negative, linewidth = 1, linetype = "dashed") +
  labs(title = "Distribución de Residuos",
       subtitle = "Verificación de normalidad",
       x = "Residuo",
       y = "Densidad",
       caption = "Línea roja punteada: distribución normal teórica") +
  theme_QQQ()
p3

El gráfico temporal de residuos exhibe oscilación alrededor de media próxima a cero (0.0001), validando ausencia de sesgo sistemático. La varianza aparece aproximadamente constante, sugiriendo homocedasticidad. El \(ACF\) de residuos muestra ausencia de autocorrelación significativa: la mayoría caen dentro de bandas de confianza.

El histograma de densidad muestra forma aproximadamente simétrica y unimodal, consistente con distribución normal. Se observa presencia de “fat tails” (colas pesadas): residuos extremos ocurren con probabilidad ligeramente mayor que lo predicho por normalidad exacta, característica típica de datos financieros reales (Tsay, 2010).

4.5.2 Q-Q Plot de Normalidad

residuos_std <- scale(residuals(ModeloQA))
df_qq <- data.frame(residuos = residuos_std)

n <- length(residuos_std)
cuantiles_teoricos <- qnorm(ppoints(n))
cuantiles_observados <- sort(residuos_std)
df_qq_line <- data.frame(x = cuantiles_teoricos, y = cuantiles_observados)

fit <- lm(y ~ x, data = df_qq_line)
df_qq_line$fitted <- predict(fit, df_qq_line)

df_qq_puntos <- data.frame(
  x = cuantiles_teoricos,
  y = cuantiles_observados,
  label = paste0(
    "Cuantil teórico: ", round(cuantiles_teoricos, 3), "<br>",
    "Residuo observado: ", round(cuantiles_observados, 3)
  )
)

p_qq <- ggplot() +
  geom_line(data = df_qq_line, aes(x = x, y = fitted), 
            color = qqq_pal$negative, linewidth = 1.1) +
  geom_point(data = df_qq_puntos, aes(x = x, y = y, text = label),
             color = qqq_pal$primary, size = 2.5, alpha = 0.75) +
  labs(
    title = "Q-Q Plot de Residuos Estandarizados",
    subtitle = "Verificación de normalidad del modelo | Línea roja = distribución normal teórica",
    x = "Cuantiles Teóricos (Distribución Normal Estándar)",
    y = "Cuantiles Observados (Residuos Estandarizados)",
    caption = "✓ Puntos alineados con la línea roja indican buenos residuos normales"
  ) +
  theme_QQQ() +
  theme(
    plot.title = element_text(size = 13, face = "bold", color = qqq_pal$primary),
    plot.subtitle = element_text(size = 11, color = qqq_pal$text_gray, margin = margin(b = 8)),
    plot.caption = element_text(size = 9, color = qqq_pal$secondary, face = "italic"),
    panel.background = element_rect(fill = "#f8f9fa", color = NA),
    plot.background = element_rect(fill = "white", color = NA),
    axis.line = element_line(color = qqq_pal$text_gray, linewidth = 0.5),
    panel.grid.major = element_line(color = "#e8eef5", linewidth = 0.3),
    panel.grid.minor = element_blank()
  )

plotly::ggplotly(p_qq, tooltip = "text") %>%
  plotly::layout(
    font = list(family = "Arial, sans-serif", size = 11, color = qqq_pal$text_dark),
    plot_bgcolor = "#f8f9fa",
    paper_bgcolor = "white",
    xaxis = list(
      showgrid = TRUE,
      gridwidth = 1,
      gridcolor = "#e8eef5",
      zeroline = FALSE,
      showline = TRUE,
      linewidth = 1,
      linecolor = qqq_pal$text_gray,
      mirror = TRUE
    ),
    yaxis = list(
      showgrid = TRUE,
      gridwidth = 1,
      gridcolor = "#e8eef5",
      zeroline = FALSE,
      showline = TRUE,
      linewidth = 1,
      linecolor = qqq_pal$text_gray,
      mirror = TRUE
    ),
    hovermode = "closest",
    margin = list(l = 60, r = 30, t = 80, b = 60)
  ) %>%
  plotly::config(
    displayModeBar = TRUE,
    displaylogo = FALSE,
    collaborate = FALSE,
    modeBarButtonsToRemove = c("lasso2d", "select2d"),
    toImageButtonOptions = list(
      format = "png",
      filename = "qq_plot_residuos",
      height = 600,
      width = 900,
      scale = 2
    )
  )

Se observa alineación muy cercana de puntos con la línea teórica en la región central. En las colas (cuantiles extremos), hay desviación sistemática indicando presencia de “fat tails”. Esta característica no invalida el modelo pero tiene implicaciones para intervalos de confianza: pueden ser ligeramente conservadores en términos de probabilidades de eventos extremos (Tsay, 2010).

4.5.3 Test de Independencia (Ljung-Box)

lb_test <- Box.test(residuals(ModeloQA), lag = 10, type = "Ljung-Box")

tabla_ljung <- data.frame(
  Métrica = c("Estadístico Ljung-Box", 
              "Grados de Libertad", 
              "P-valor",
              "Conclusión"),
  Valor = c(
    round(lb_test$statistic, 4),
    lb_test$parameter,
    round(lb_test$p.value, 4),
    ifelse(lb_test$p.value > 0.05, 
           "Residuos son ruido blanco ✓", 
           "Posible autocorrelación residual")
  )
)

kable(tabla_ljung, 
      caption = "Test de Ljung-Box: Independencia de Residuos",
      align = c("l", "c")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  row_spec(4, bold = TRUE, 
           background = ifelse(lb_test$p.value > 0.05, "#e8f5e9", "#ffe8e0"),
           color = qqq_pal$text_dark)
Test de Ljung-Box: Independencia de Residuos
Métrica Valor
Estadístico Ljung-Box 10.1399
Grados de Libertad 10
P-valor 0.4283
Conclusión Residuos son ruido blanco ✓

El estadístico Ljung-Box de \(Q^*\) = 10.1399 con 10 grados de libertad produce p-valor = 0.4283 > 0.05. No se rechaza la hipótesis nula: los residuos no exhiben autocorrelación significativa en los primeros 10 rezagos. El \(p-valor\) de 0.43 indica que si verdaderamente los residuos fuesen ruido blanco independiente, observaríamos una estadística de prueba tan extrema o más extrema con probabilidad del 43%—resultado completamente consistente con independencia (Ljung & Box, 1978).


4.6 Pronóstico y Evaluación

Una vez validado que el modelo \(ARIMA(1,1,1)\) + drift produce residuos que se comportan como ruido blanco, procede la etapa de pronóstico: generación de predicciones puntuales para el \(QQQ\) junto con intervalos de confianza que cuantifican incertidumbre.

pronostico <- forecast(ModeloQA, h = 10, level = 95)

ultima_fecha <- as.Date(index(Entrenamiento)[length(Entrenamiento)])

fechas_pronostico <- c()
fecha_actual <- ultima_fecha
dias_agregados <- 0

while(dias_agregados < 10) {
  fecha_actual <- fecha_actual + 1
  if (!(weekdays(fecha_actual) %in% c("sábado", "domingo", "Saturday", "Sunday"))) {
    fechas_pronostico <- c(fechas_pronostico, fecha_actual)
    dias_agregados <- dias_agregados + 1
  }
}

fechas_pronostico <- as.Date(fechas_pronostico, origin = "1970-01-01")

4.6.1 Tabla de Pronósticos

tabla_pronostico <- data.frame(
  Día = 1:10,
  Fecha = as.character(fechas_pronostico),
  Pronóstico = round(as.numeric(pronostico$mean), 2),
  `Límite Inferior` = round(as.numeric(pronostico$lower), 2),
  `Límite Superior` = round(as.numeric(pronostico$upper), 2),
  `Amplitud IC` = round(as.numeric(pronostico$upper) - as.numeric(pronostico$lower), 2)
)

kable(tabla_pronostico,
      caption = "Pronósticos del Modelo ARIMA(1,1,1) con Drift - Intervalo de Confianza al 95%",
      align = c("c", "c", "c", "c", "c", "c"),
      col.names = c("Día", "Fecha", "Pronóstico (USD)", "Lím. Inferior", "Lím. Superior", "Amplitud IC")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(3, bold = TRUE, color = qqq_pal$primary, background = "#f0f9ff") %>%
  column_spec(4, color = qqq_pal$negative) %>%
  column_spec(5, color = qqq_pal$positive) %>%
  column_spec(6, color = "#666666") %>%
  footnote(general = "IC = Intervalo de Confianza. La amplitud del intervalo aumenta con el horizonte de pronóstico.",
           general_title = "Nota: ")
Pronósticos del Modelo ARIMA(1,1,1) con Drift - Intervalo de Confianza al 95%
Día Fecha Pronóstico (USD) Lím. Inferior Lím. Superior Amplitud IC
1 2025-10-01 600.71 589.94 611.47 21.54
2 2025-10-02 601.23 586.43 616.03 29.60
3 2025-10-03 601.61 583.40 619.83 36.42
4 2025-10-06 602.11 581.20 623.01 41.81
5 2025-10-07 602.51 579.11 625.92 46.82
6 2025-10-08 602.99 577.40 628.57 51.17
7 2025-10-09 603.41 575.76 631.06 55.30
8 2025-10-10 603.87 574.34 633.40 59.06
9 2025-10-13 604.30 572.98 635.63 62.65
10 2025-10-14 604.76 571.75 637.76 66.01
Nota:
IC = Intervalo de Confianza. La amplitud del intervalo aumenta con el horizonte de pronóstico.

Los pronósticos del \(ARIMA(1,1,1)\) + drift para los próximos 10 días hábiles (01-octubre a 14-octubre 2025) se ubican en el rango 600.71 a 604.76 USD. El incremento inicial refleja el drift estimado: una tendencia alcista promedio de μ ≈ 0.4-0.5 dólares por día. La amplitud expansiva de los intervalos de confianza es característica: el IC 95% en el día 1 tiene amplitud apenas 21.54, pero se expande a 66.01 en el día 10. Esta expansión refleja que bajo un \(ARIMA(1,1,1)\) con \(d=1\), la varianza del pronóstico crece aproximadamente como \(σ²·h\), donde \(σ²\) es varianza de innovaciones (Hamilton, 1994).

4.6.2 Gráfico: Pronóstico con Intervalo de Confianza

n_historico <- 100
datos_hist <- tail(Entrenamiento, n_historico)

df_historico <- data.frame(
  Fecha = as.Date(index(datos_hist)),
  Precio = as.numeric(datos_hist),
  Tipo = "Histórico"
)

ultima_fecha <- as.Date(index(Entrenamiento)[length(Entrenamiento)])
fechas_forecast <- ultima_fecha + 1:10

df_pronostico <- data.frame(
  Fecha = fechas_forecast,
  Precio = as.numeric(pronostico$mean),
  Lower = as.numeric(pronostico$lower),
  Upper = as.numeric(pronostico$upper)
)

punto_conexion <- data.frame(
  Fecha = ultima_fecha,
  Precio = as.numeric(tail(datos_hist, 1)),
  Lower = as.numeric(tail(datos_hist, 1)),
  Upper = as.numeric(tail(datos_hist, 1))
)

df_pronostico_completo <- bind_rows(punto_conexion, df_pronostico)

ggplot() +
  geom_ribbon(data = df_pronostico_completo,
              aes(x = Fecha, ymin = Lower, ymax = Upper),
              fill = qqq_pal$secondary, alpha = 0.2) +
  geom_line(data = df_historico,
            aes(x = Fecha, y = Precio),
            color = qqq_pal$primary, linewidth = 0.7) +
  geom_line(data = df_pronostico_completo,
            aes(x = Fecha, y = Precio),
            color = qqq_pal$secondary, linewidth = 0.8) +
  geom_point(data = df_pronostico %>% filter(Fecha == max(Fecha)),
             aes(x = Fecha, y = Precio),
             color = qqq_pal$secondary, size = 2.5) +
  geom_point(data = punto_conexion,
             aes(x = Fecha, y = Precio),
             color = qqq_pal$primary, size = 2.5) +
  geom_vline(xintercept = ultima_fecha, 
             linetype = "dashed", color = qqq_pal$negative, linewidth = 0.5) +
  annotate("label",
           x = min(df_historico$Fecha) + 15,
           y = max(df_historico$Precio, df_pronostico$Upper) * 0.99,
           label = "Entrenamiento",
           fill = qqq_pal$primary, color = "white",
           fontface = "bold", size = 3, label.padding = unit(0.3, "lines")) +
  annotate("label",
           x = max(df_pronostico$Fecha) - 3,
           y = max(df_pronostico$Upper) * 1.01,
           label = "Pronóstico",
           fill = qqq_pal$secondary, color = "white",
           fontface = "bold", size = 3, label.padding = unit(0.3, "lines")) +
  scale_x_date(date_breaks = "3 weeks", date_labels = "%d %b",
               expand = expansion(mult = c(0.02, 0.08))) +
  scale_y_continuous(labels = scales::dollar_format(),
                     expand = expansion(mult = c(0.02, 0.05))) +
  labs(title = "Pronóstico ARIMA(1,1,1) con Drift",
       subtitle = "QQQ (Nasdaq-100 ETF) | Últimos 100 días + 10 días de pronóstico | IC 95%",
       x = NULL,
       y = "Precio de Cierre (USD)",
       caption = "Línea verde: Datos históricos | Línea cian: Pronóstico | Área sombreada: Intervalo de confianza 95%") +
  theme_QQQ() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

4.6.3 Evaluación Comparativa: Predicho vs Real

reales <- head(as.numeric(Prueba), 10)
predichos <- as.numeric(pronostico$mean)
fechas_prueba <- head(as.Date(index(Prueba)), 10)

df_evaluacion <- data.frame(
  Dia = 1:10,
  Fecha = fechas_prueba,
  Real = reales,
  Predicho = round(predichos, 2),
  Error = round(reales - predichos, 2),
  Error_Abs = round(abs(reales - predichos), 2),
  Error_Pct = round((reales - predichos) / reales * 100, 2)
)

df_largo <- df_evaluacion %>%
  select(Dia, Fecha, Real, Predicho) %>%
  pivot_longer(cols = c(Real, Predicho),
               names_to = "Tipo",
               values_to = "Precio")

ggplot(df_largo, aes(x = Dia, y = Precio, color = Tipo, shape = Tipo)) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 3) +
  geom_ribbon(data = df_evaluacion,
              aes(x = Dia, y = Predicho,
                  ymin = as.numeric(pronostico$lower),
                  ymax = as.numeric(pronostico$upper)),
              fill = qqq_pal$secondary, alpha = 0.15,
              inherit.aes = FALSE) +
  scale_color_manual(values = c("Real" = qqq_pal$primary, 
                                "Predicho" = qqq_pal$secondary),
                     labels = c("Predicho" = "Pronóstico", "Real" = "Valor Real")) +
  scale_shape_manual(values = c("Real" = 16, "Predicho" = 17),
                     labels = c("Predicho" = "Pronóstico", "Real" = "Valor Real")) +
  scale_x_continuous(breaks = 1:10, labels = paste0("t+", 1:10)) +
  scale_y_continuous(labels = scales::dollar_format()) +
  labs(title = "Evaluación del Pronóstico: Valores Reales vs Predichos",
       subtitle = "QQQ (Nasdaq-100 ETF) | Primeros 10 días del conjunto de prueba",
       x = "Horizonte de Pronóstico",
       y = "Precio de Cierre (USD)",
       color = NULL,
       shape = NULL,
       caption = "Área sombreada: Intervalo de confianza 95%") +
  theme_QQQ() +
  theme(legend.position = "top")

Los primeros 10 días observados de octubre 2025 revelan que valores reales exhiben volatilidad que oscila alrededor de la línea de pronóstico, sin divergencia sistemática consistente. Los valores reales caen todos dentro del intervalo de confianza 95%, validando calibración correcta de la incertidumbre.

4.6.4 Tabla de Errores por Observación

tabla_errores <- df_evaluacion %>%
  select(Dia, Fecha, Real, Predicho, Error, Error_Pct) %>%
  mutate(
    Fecha = as.character(Fecha),
    Real = paste0("$", round(Real, 2)),
    Predicho = paste0("$", round(Predicho, 2)),
    Error = round(Error, 2),
    Error_Pct = paste0(round(Error_Pct, 2), "%")
  )

kable(tabla_errores,
      caption = "Evaluación del Pronóstico: Errores por Observación",
      align = c("c", "c", "c", "c", "c", "c"),
      col.names = c("Día", "Fecha", "Valor Real", "Pronóstico", "Error (USD)", "Error (%)")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(3, color = qqq_pal$primary, bold = TRUE) %>%
  column_spec(4, color = qqq_pal$secondary, bold = TRUE) %>%
  column_spec(5, bold = TRUE) %>%
  column_spec(6, bold = TRUE) %>%
  footnote(general = "Error positivo: el modelo subestimó (valor real > pronóstico). Error negativo: el modelo sobreestimó.",
           general_title = "Nota: ")
Evaluación del Pronóstico: Errores por Observación
Día Fecha Valor Real Pronóstico Error (USD) Error (%)
1 2025-10-01 $603.25 $600.71 2.54 0.42%
2 2025-10-02 $605.73 $601.23 4.50 0.74%
3 2025-10-03 $603.18 $601.61 1.57 0.26%
4 2025-10-06 $607.71 $602.11 5.60 0.92%
5 2025-10-07 $604.51 $602.51 2.00 0.33%
6 2025-10-08 $611.44 $602.99 8.45 1.38%
7 2025-10-09 $610.7 $603.41 7.29 1.19%
8 2025-10-10 $589.5 $603.87 -14.37 -2.44%
9 2025-10-13 $602.01 $604.3 -2.29 -0.38%
10 2025-10-14 $598 $604.76 -6.76 -1.13%
Nota:
Error positivo: el modelo subestimó (valor real > pronóstico). Error negativo: el modelo sobreestimó.

Los errores exhiben distribución asimétrica pero no-sistemática. Los primeros tres días exhiben errores positivos pequeños, indicando subestimación leve. Lo notable es la simetría aproximada de errores: errores positivos en días iniciales son balanceados aproximadamente por errores negativos posteriormente, indicando que el modelo no tiene sesgo direccional sistemático.

4.6.5 Métricas Finales de Evaluación

MAE <- mean(abs(df_evaluacion$Error))
RMSE <- sqrt(mean(df_evaluacion$Error^2))
MAPE <- mean(abs(df_evaluacion$Error_Pct))
ME <- mean(df_evaluacion$Error)

dentro_IC <- sum(reales >= as.numeric(pronostico$lower) & 
                   reales <= as.numeric(pronostico$upper))
pct_dentro_IC <- dentro_IC / 10 * 100

tabla_metricas <- data.frame(
  Métrica = c("Error Medio (ME)",
              "Error Absoluto Medio (MAE)",
              "Raíz del Error Cuadrático Medio (RMSE)",
              "Error Porcentual Absoluto Medio (MAPE)",
              "Observaciones dentro del IC 95%"),
  Valor = c(paste0("$", round(ME, 2)),
            paste0("$", round(MAE, 2)),
            paste0("$", round(RMSE, 2)),
            paste0(round(MAPE, 2), "%"),
            paste0(dentro_IC, " de 10 (", pct_dentro_IC, "%)")),
  Interpretación = c(
    ifelse(abs(ME) < 1, "Sin sesgo sistemático ✓", 
           ifelse(ME > 0, "Modelo subestima", "Modelo sobreestima")),
    "Error promedio en USD",
    "Penaliza errores grandes",
    "Error relativo al precio",
    ifelse(pct_dentro_IC >= 80, "Intervalos bien calibrados ✓", 
           "Intervalos pueden estar mal calibrados")
  )
)

kable(tabla_metricas,
      caption = "Métricas de Evaluación del Pronóstico - Datos de Prueba",
      align = c("l", "c", "l")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(2, bold = TRUE) %>%
  row_spec(5, background = "#e8f5e9", color = qqq_pal$text_dark, bold = TRUE)
Métricas de Evaluación del Pronóstico - Datos de Prueba
Métrica Valor Interpretación
Error Medio (ME) $0.85 Sin sesgo sistemático ✓
Error Absoluto Medio (MAE) $5.54 Error promedio en USD
Raíz del Error Cuadrático Medio (RMSE) $6.68 Penaliza errores grandes
Error Porcentual Absoluto Medio (MAPE) 0.92% Error relativo al precio
Observaciones dentro del IC 95% 10 de 10 (100%) Intervalos bien calibrados ✓

El Error Medio (ME) = 0.85 es notablemente pequeño, validando ausencia de sesgo direccional sistemático. El Error Absoluto Medio (MAE) = 5.54 cuantifica desviación promedio de ±5.54 o 0.92% del precio. La Raíz del Error Cuadrático Medio (RMSE) = 6.68 es ligeramente superior porque penaliza desviaciones grandes. El Error Porcentual Absoluto Medio (MAPE) = 0.92% es excelente para pronóstico de precios de activos financieros.

La métrica más reveladora es “Observaciones dentro del IC 95%” = 10 de 10 (100%). Esta perfecta cobertura indica que el intervalo de confianza fue exactamente bien calibrado: todos los valores reales cayeron dentro de las bandas predichas, validando calibración correcta de la incertidumbre (Hyndman & Koehler, 2006).


5. Conclusiones

5.1 Resumen de los Hallazgos Principales

El análisis exhaustivo del ETF \(QQQ\) mediante la metodología Box-Jenkins permitió identificar, estimar y validar un modelo \(ARIMA\) óptimo para el pronóstico de precios de cierre diarios del índice \(Nasdaq-100\). Los hallazgos principales se organizan en torno a cuatro aspectos fundamentales del proceso de modelización.

En primer lugar, la caracterización de la serie temporal reveló que los precios del \(QQQ\) son no-estacionarios en niveles, evidenciado tanto gráficamente por el decaimiento lento de la función de autocorrelación como estadísticamente mediante la prueba Aumentada de Dickey-Fuller, que arrojó un estadístico de -1.8913 con \(p-valor\) de 0.1352. La aplicación de diferenciación de primer orden logró estacionariedad confirmada con un estadístico ADF de -8.6831 y \(p-valor\) de 0.01, estableciendo que una única diferencia es suficiente para transformar la serie de precios en cambios diarios estacionarios. Este resultado es consistente con la literatura sobre series financieras, donde los precios típicamente exhiben comportamiento de caminata aleatoria con drift.

En segundo lugar, la selección del modelo óptimo se realizó comparando seis especificaciones candidatas mediante criterios de información. El modelo \(ARIMA(1,1,1)\) con drift emergió como la especificación óptima con un \(AICc\) de 4663.94, superando al \(ARIMA\)(2,1,2) por 4.2 unidades y al random walk puro \(ARIMA(0,1,0)\) por 4.45 unidades. La inclusión del término drift, estimado en aproximadamente 0.44 USD diarios, captura la tendencia alcista promedio del \(QQQ\) durante el período 2022-2025, reflejando el optimismo del mercado hacia el sector tecnológico impulsado por el auge de la inteligencia artificial generativa. Es importante destacar que modelos más complejos como el \(ARIMA(3,1,3)\) no mejoraron significativamente el ajuste, siendo penalizados por sobreparametrización.

En tercer lugar, la validación diagnóstica confirmó que los residuos del modelo seleccionado satisfacen los supuestos de ruido blanco. El error medio resultó prácticamente cero (-0.0001), la varianza se mantuvo constante a lo largo del tiempo, y la prueba de Ljung-Box confirmó ausencia de autocorrelación significativa con un estadístico de 10.14 y p-valor de 0.4283. El análisis Q-Q reveló una aproximación razonable a normalidad con presencia moderada de colas pesadas, característica típica de series financieras que no invalida el modelo pero tiene implicaciones para la calibración de intervalos de confianza en eventos extremos.

Finalmente, el desempeño predictivo evaluado sobre 10 días hábiles del conjunto de prueba arrojó métricas satisfactorias. El error medio de 0.85 USD indica ausencia de sesgo sistemático, el error absoluto medio de 5.54 USD representa una desviación promedio menor al 1% del precio, y el error porcentual absoluto medio se ubicó en 0.92%. El hallazgo más relevante es que la cobertura del intervalo de confianza al 95% alcanzó el 100%, con las 10 observaciones reales cayendo dentro de las bandas predichas, lo que valida la calibración correcta de la incertidumbre del modelo.

5.2 Implicaciones de los Pronósticos en el Contexto de la Serie

Los pronósticos generados por el modelo \(ARIMA(1,1,1)\) con drift deben interpretarse considerando las características particulares de los mercados financieros eficientes y la naturaleza del sector tecnológico. La implicación más inmediata es que el horizonte temporal útil del modelo está inherentemente limitado. Los intervalos de confianza se expanden progresivamente con el horizonte de pronóstico, desde aproximadamente 21.54 USD en el día 1 hasta 66.01 USD en el día 10. Esta expansión es consecuencia directa del componente de integración, donde la varianza crece proporcional al horizonte temporal. En términos prácticos, la utilidad predictiva se concentra en ventanas de 1 a 5 días hábiles; más allá de dos semanas, los intervalos aportan información limitada para decisiones de inversión.

Los resultados son consistentes con la Hipótesis de Mercado Eficiente en su forma débil. El análisis \(ACF\) y \(PACF\) de la serie diferenciada reveló autocorrelaciones prácticamente indistinguibles de ruido blanco, indicando que la información histórica ya está incorporada en el precio actual. Los coeficientes \(AR(1)\) y \(MA(1)\) estimados casi se cancelan entre sí, produciendo residuos muy similares a la serie diferenciada original. En mercados donde miles de participantes procesan información continuamente, cualquier patrón predecible tiende a ser arbitrajado antes de poder explotarse sistemáticamente.

El término drift estimado de aproximadamente 0.44 USD diarios no debe interpretarse como predicción de rendimiento futuro garantizado, sino como captura de la tendencia histórica durante el período específico de entrenamiento, que coincidió con la recuperación posterior a 2022 y el rally impulsado por inteligencia artificial. Cambios en el régimen de mercado invalidarían este supuesto de tendencia constante.

Finalmente, los intervalos de confianza bien calibrados, con cobertura del 100% en el período de prueba, proporcionan herramientas válidas para gestión de riesgos. Sin embargo, la presencia de colas pesadas en los residuos sugiere que eventos extremos ocurrirán con mayor frecuencia que lo predicho por una distribución normal exacta, lo cual debe considerarse en aplicaciones como Value at Risk o Expected Shortfall.

5.3 Limitaciones del Análisis y Posibles Mejoras

El presente análisis presenta limitaciones inherentes que deben reconocerse para contextualizar apropiadamente los resultados.

La naturaleza univariada del modelo ignora variables exógenas relevantes para la valoración de activos tecnológicos, como tasas de interés de la Reserva Federal, índices de volatilidad implícita como el VIX, y flujos de fondos hacia ETFs. Esta limitación es particularmente relevante para el \(QQQ\) dada su alta sensibilidad documentada a cambios en política monetaria. Adicionalmente, el supuesto de homocedasticidad del modelo \(ARIMA\) contrasta con el fenómeno de agrupamiento de volatilidad observado en el análisis descriptivo, lo cual puede producir intervalos de confianza mal calibrados en períodos de estrés de mercado.

El modelo tampoco captura cambios de régimen. El período 2022-2025 atravesó múltiples estados de mercado: corrección severa, rally de recuperación, consolidación y nuevo impulso. Los parámetros constantes estimados promedian estos regímenes sin detectar transiciones entre ellos. Finalmente, la evaluación sobre 45 observaciones representa un período relativamente corto que puede no capturar la variabilidad completa del desempeño bajo diferentes condiciones.

Para futuros estudios se identifican extensiones prometedoras: modelos \(ARIMAX\) que incorporen variables exógenas como tasas de interés y volatilidad implícita; especificaciones \(ARIMA-GARCH\) que modelen heterocedasticidad condicional produciendo intervalos que se expandan en períodos turbulentos; modelos Markov-Switching que identifiquen automáticamente transiciones entre regímenes de mercado; y esquemas de validación cruzada temporal extendida que evalúen el desempeño sobre múltiples períodos de prueba.

En síntesis, el modelo \(ARIMA\)(1,1,1) con drift constituye una especificación estadísticamente válida y parsimoniosa para el pronóstico de corto plazo del \(QQQ\). Sus limitaciones delimitan su alcance como herramienta de pronóstico puntual, no como sistema de trading automatizado. Las mejoras propuestas representan extensiones naturales que podrían incrementar la precisión y aplicabilidad práctica en contextos de inversión real.

6 Bibliografia

Bernstein, P. L. (1997). Contra los dioses: La notable historia del riesgo. John Wiley & Sons.

Bollerslev, T. (1986). Heteroscedasticidad condicional autorregresiva generalizada. Journal of Econometrics, 31(3), 307–327. https://doi.org/10.1016/0304-4076(86)90063-1

Eloundou, T., Manning, S., Mishkin, P., & Rock, D. (2023). Los GPT son GPTs: Una primera mirada al impacto potencial de los grandes modelos de lenguaje en el mercado laboral. arXiv preprint. https://doi.org/10.48550/arXiv.2303.10130

Engle, R. F. (1982). Heteroscedasticidad condicional autorregresiva con estimaciones de la varianza de la inflación del Reino Unido. Econometrica, 50(4), 987–1007. https://doi.org/10.2307/1912773

Fama, E. F., & French, K. R. (2015). Un modelo de valoración de activos de cinco factores. Journal of Financial Economics, 116(1), 1–22. https://doi.org/10.1016/j.jfineco.2014.10.010

Invesco Ltd. (2024). Ficha técnica del ETF QQQ. Invesco QQQ Trust. https://www.invesco.com/us/financial-products/etfs/product-detail?audienceType=Investor&ticker=QQQ

Jegadeesh, N., & Titman, S. (1993). Retornos de comprar ganadores y vender perdedores: Implicaciones para la eficiencia del mercado de valores. The Journal of Finance, 48(1), 65–91. https://doi.org/10.1111/j.1540-6261.1993.tb04702.x

Malkiel, B. G. (2003). Un paseo aleatorio por Wall Street: La estrategia probada en el tiempo para invertir con éxito (8.ª ed.). W.W. Norton & Company.

Mandelbrot, B. (1963). La variación de ciertos precios especulativos. The Journal of Business, 36(4), 394–419. https://doi.org/10.1086/294632

Markowitz, H. (1952). Selección de cartera. The Journal of Finance, 7(1), 77–91. https://doi.org/10.1111/j.1540-6261.1952.tb01525.x

MSCI Inc. (2023). Metodología de los Índices de Mercado Invertible Globales de MSCI. https://www.msci.com/index-methodology

Sharpe, W. F. (1964). Precios de los activos de capital: Una teoría del equilibrio del mercado en condiciones de riesgo. The Journal of Finance, 19(3), 425–442. https://doi.org/10.1111/j.1540-6261.1964.tb02865.x

Thaler, R. H. (1987). Movimientos estacionales en los precios de los valores II: Efectos de fin de semana, festivos, cambio de mes e intradía. En R. H. Thaler (Ed.), Avances en las finanzas conductuales (pp. 56–77). Russell Sage Foundation.

Tsay, R. S. (2010). Análisis de series de tiempo financieras (3.ª ed.). John Wiley & Sons.

Box, G. E. P., & Jenkins, G. M. (1976). Time series analysis: Forecasting and control (2nd ed.). Holden-Day.

Brockwell, P. J., & Davis, R. A. (2016). Introduction to time series and forecasting (3rd ed.). Springer.

Chatfield, C. (2000). Time-series forecasting. Chapman and Hall/CRC.

Dickey, D. A., & Fuller, W. A. (1979). Distribution of the estimators for autoregressive time series with a unit root. Journal of the American Statistical Association, 74(366), 427–431.

Hamilton, J. D. (1994). Time series analysis. Princeton University Press.

Hyndman, R. J., & Athanasopoulos, G. (2021). Forecasting: principles and practice (3rd ed.). OTexts. https://otexts.com/fpp3/

Jarque, C. M., & Bera, A. K. (1987). A test for normality of observations and regression residuals. International Statistical Review, 55(2), 163–172.

Ljung, G. M., & Box, G. E. P. (1978). On a measure of lack of fit in time series models. Biometrika, 65(2), 297–303.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ASIGNATURA: Gestión de Datos
PROFESOR: Orlando Joaqui-Barandica
UNIVERSIDAD: Universidad del Valle
FACULTAD: Facultad de Ingeniería
PROGRAMA: Ingeniería Industrial
ESTUDIANTE: Portilla Aguirre Johan Camilo (2422468), Barros Rayo Alejandro (2415837), Muñoz Portela Diego Fernando (2415620)
FECHA ENTREGA:
VERSIÓN: 1.0
Documento generado con R Markdown | Tema: Series de Tiempo y Pronósticos ARIMA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━