Integrantes:

  • Mayra Narváez López
  • Jhon Mauricio Balanta
  • Jose Luis Jimenez
  • Luis Ángel Vidal Z

1. Introducción y Carga de Datos

Este reporte documenta la transformación del Dataset Inicial (datos brutos de mercado) al Dataset Final listo para el uso en modelos.

Ventana: 2021-2026 (5 años).

Activos: 10 acciones.

# Identificar duplicados}
# 1. Definimos los activos (se pueden editar).
# Incluimos Acciones, ETFs e Índices
tickers <- c("AAPL", "MSFT", "GOOGL", "AMZN", "TSLA", 
             "NVDA", "META", "BRK-B", "V", "JPM", 
             "WMT", "MA", "PG", "UNH", "HD", 
             "BAC", "DIS", "ADBE", "NFLX", "XOM")

# 2. Descarga automática de los últimos 5 años
# tq_get descarga: symbol, date, open, high, low, close, volume, adjusted
raw_data_yahoo <- tq_get(tickers,
                         get  = "stock.prices",
                         from = "2021-01-01",
                         to   = "2026-02-17")

# 3. Adaptamos al formato de nuestro Dataset Analítico
raw_data <- raw_data_yahoo %>%
  rename(ticker = symbol, price = adjusted) %>%
  select(ticker, date, price, volume) %>%
  mutate(currency = "USD") # Yahoo Finance entrega USD para estos tickers


# Vista previa del Dataset Inicial
kable(head(raw_data), caption = "Dataset Inicial (Muestra)")
Dataset Inicial (Muestra)
ticker date price volume currency
AAPL 2021-01-04 125.8567 143301900 USD
AAPL 2021-01-05 127.4128 97664900 USD
AAPL 2021-01-06 123.1239 155088000 USD
AAPL 2021-01-07 127.3252 109578200 USD
AAPL 2021-01-08 128.4242 105158200 USD
AAPL 2021-01-11 125.4385 100384500 USD

2. Diccionario de Datos

Este diccionario garantiza que cualquier usuario del dataset entienda el nivel y la unidad de medida:

Diccionario de Datos del Dataset Analítico
Variable Descripcion Unidad Fuente Llave
ticker Simbolo del activo Texto Yahoo Finance Si
date Fecha de cierre ISO 8601 Yahoo Finance Si
price Precio ajustado USD Yahoo Finance No
volume Volumen diario Unidades Yahoo Finance No
id_key Llave unica Texto Generada Si

3. Pipeline de Calidad y Trazabilidad (Bitácora)

3.1. Check 1: Llave Única (Ticker + Date)

Buscamos duplicados para asegurar que no existan dos precios para el mismo activo el mismo día.

# Identificar duplicados
duplicados <- raw_data %>% 
  group_by(ticker, date) %>% 
  filter(n() > 1)

# Acción: Eliminar duplicados si existieran
clean_data <- raw_data %>% 
  distinct(ticker, date, .keep_all = TRUE)

Bitácora: Se detectaron 0 duplicados. Acción: Se aplicó distinct() para asegurar la unicidad de la llave.

3.2. Check 2: Tipos de Datos Correctos

clean_data <- clean_data %>%
  mutate(
    date = as.Date(date),
    price = as.numeric(price),
    volume = as.numeric(volume),
    ticker = as.character(ticker)
  )

Bitácora: Se validó que date sea clase Date y price/volume sean numéricos para permitir cálculos matemáticos.

3.2. Check 3: Control de Missing Values (NAs)

# Conteo de NAs por columna
resumen_na <- colSums(is.na(clean_data))
cantidad_faltantes <- sum(resumen_na)


# Acción: Eliminar registros con precios faltantes
clean_data <- clean_data %>% drop_na(price)

Bitácora: Se encontraron 0 valores nulos. Decisión: Eliminación de filas incompletas para evitar errores en el cálculo de retornos.

3.2. Check 4: Rangos Lógicos y Consistencia

Validamos que los precios sean positivos y el volumen no sea negativo.

errores_logicos <- clean_data %>% 
  filter(price <= 0 | volume < 0)

# Filtrado de valores imposibles
clean_data <- clean_data %>% 
  filter(price > 0 & volume >= 0)

Bitácora: Se detectaron 0 valores fuera de rango lógico. Acción: Eliminados del dataset final.

4. Dataset Analítico Final

Creamos la llave final y presentamos el producto listo para su uso en modelos financieros.

final_dataset <- clean_data %>%
  mutate(id_key = paste0(ticker, date)) %>%
  select(id_key, ticker, date, price, volume, currency)

# Muestra aleatoria de 10 filas del dataset final
kable(final_dataset[sample(nrow(final_dataset), 10), ], 
      caption = "Muestra Aleatoria del Dataset Analítico Finalizado")
Muestra Aleatoria del Dataset Analítico Finalizado
id_key ticker date price volume currency
MSFT2023-08-08 MSFT 2023-08-08 319.20337 22327600 USD
JPM2021-05-20 JPM 2021-05-20 142.46533 10426000 USD
WMT2021-02-09 WMT 2021-02-09 45.41651 15906900 USD
META2022-01-28 META 2022-01-28 299.61707 21871600 USD
TSLA2025-05-14 TSLA 2025-05-14 347.67999 136997300 USD
DIS2022-12-30 DIS 2022-12-30 84.88110 23231000 USD
UNH2022-11-30 UNH 2022-11-30 512.96533 9688900 USD
JPM2021-02-16 JPM 2021-02-16 127.38265 12130600 USD
BAC2022-01-21 BAC 2022-01-21 40.34799 71303600 USD
AAPL2025-10-17 AAPL 2025-10-17 251.81003 49147000 USD

5. Visualización de Validación

Como última prueba de calidad, visualizamos la serie de tiempo para detectar anomalías visuales.

library(plotly)

# 1. Aseguramos que el ticker sea un factor para controlar el orden
final_dataset$ticker <- as.factor(final_dataset$ticker)
lista_tickers <- levels(final_dataset$ticker)
n_tickers <- length(lista_tickers)

# 2. Crear el gráfico base
p <- plot_ly(final_dataset, x = ~date, y = ~price, color = ~ticker, 
             type = 'scatter', mode = 'lines',
             hovertemplate = "<b>%{fullData.name}</b><br>Precio: %{y:.2f} USD<extra></extra>")

# 3. Crear los botones de forma dinámica y sincronizada
botones <- lapply(1:n_tickers, function(i) {
  # Creamos un vector de FALSE de tamaño n
  visibilidad <- rep(FALSE, n_tickers)
  # Solo la posición actual es TRUE
  visibilidad[i] <- TRUE
  
  list(
    method = "restyle",
    args = list("visible", visibilidad),
    label = lista_tickers[i]
  )
})

# 4. Añadir el botón "Todos"
botones <- c(list(list(
  method = "restyle",
  args = list("visible", rep(TRUE, n_tickers)),
  label = "Todos los activos"
)), botones)

# 5. Configurar Layout
p %>% layout(
  title = "Explorador Dinámico de Activos",
  yaxis = list(title = "Precio (USD)", fixedrange = FALSE),
  updatemenus = list(
    list(
      y = 0.9, x = -0.1,
      active = 0, # Define que el primer botón (Todos) esté presionado al inicio
      buttons = botones
    )
  )
)