# ============================================================
# LIBRERÍAS GLOBALES
# ============================================================




library(quantmod)
library(PerformanceAnalytics)
library(ggplot2)
library(reshape2)
library(plotly)
library(quadprog)
library(kableExtra)
library(scales)
library(dplyr)
library(tidyr)
library(lubridate)
library(DT)

# Paleta de colores corporativa
colores <- c("KO" = "#F40000", "JNJ" = "#D62728", "NFLX" = "#1f77b4")
colores_port <- c("KO" = "#E74C3C", "JNJ" = "#E67E22", "NFLX" = "#3498DB")
# ============================================================
# PUNTO 1: DESCARGA DE DATOS Y PRECIOS HISTÓRICOS
# ============================================================
tickers <- c("KO", "JNJ", "NFLX")
getSymbols(tickers, from = "2016-04-30", to = "2026-04-30", src = "yahoo")
## [1] "KO"   "JNJ"  "NFLX"
# Precios de cierre ajustados
precios <- do.call(merge, lapply(tickers, function(x) Ad(get(x))))
colnames(precios) <- tickers

# Evolución de precios normalizados (Base 100)
precios_norm <- sweep(precios, 2, as.numeric(precios[1,]), "/") * 100
precios_df <- data.frame(Fecha = index(precios_norm), coredata(precios_norm))
precios_long <- pivot_longer(precios_df, cols = -Fecha, names_to = "Activo", values_to = "Precio")

# Gráfico interactivo de evolución de precios
p1 <- ggplot(precios_long, aes(x = Fecha, y = Precio, color = Activo)) +
  geom_line(size = 0.8) +
  scale_color_manual(values = colores_port) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "bottom",
    panel.grid.minor = element_blank()
  ) +
  labs(
    title = "Evolución de Precios Normalizados (Base 100 = Abril 2016)",
    subtitle = "KO | JNJ | NFLX — S&P 500 Components",
    x = "Fecha", y = "Precio Normalizado",
    caption = "Fuente: Yahoo Finance | Elaboración propia"
  )

ggplotly(p1) %>%
  layout(hovermode = "x unified",
         legend = list(orientation = "h", y = -0.2))
# Tabla de análisis fundamental resumido
fund_data <- data.frame(
  Criterio = c("Sector", "Industria", "Capitalización (aprox.)",
               "P/E Ratio (TTM)", "Margen Operativo", "ROE",
               "Dividend Yield", "Deuda/Patrimonio",
               "Crecimiento Ingresos (5Y)", "Calificación S&P"),
  KO = c("Consumo Básico", "Bebidas No Alcohólicas",
          "$265B USD", "22x", "28.5%", "38.2%",
          "3.1%", "Moderada", "4.2% CAGR", "A+"),
  JNJ = c("Salud", "Farmacéutica/Dispositivos Médicos",
           "$380B USD", "15x", "24.1%", "27.8%",
           "3.0%", "Baja", "5.8% CAGR", "AAA"),
  NFLX = c("Comunicaciones", "Entretenimiento/Streaming",
             "$310B USD", "35x", "22.3%", "32.1%",
             "0%", "Moderada-Alta", "18.5% CAGR", "BB+")
)

fund_data %>%
  kbl(
    caption = "Tabla 1.1: Métricas Fundamentales Comparativas (Abril 2026)",
    align = c("l", "c", "c", "c"),
    col.names = c("Criterio", "Coca-Cola (KO)",
                  "Johnson & Johnson (JNJ)", "Netflix (NFLX)")
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE
  ) %>%
  row_spec(0, bold = TRUE, background = "#2C3E50", color = "white") %>%
  column_spec(1, bold = TRUE, background = "#ECF0F1") %>%
  column_spec(2, background = "#FDEBD0") %>%
  column_spec(3, background = "#D5F5E3") %>%
  column_spec(4, background = "#D6EAF8")
Tabla 1.1: Métricas Fundamentales Comparativas (Abril 2026)
Criterio Coca-Cola (KO) Johnson & Johnson (JNJ) Netflix (NFLX)
Sector Consumo Básico Salud Comunicaciones
Industria Bebidas No Alcohólicas Farmacéutica/Dispositivos Médicos Entretenimiento/Streaming
Capitalización (aprox.) $265B USD $380B USD $310B USD
P/E Ratio (TTM) 22x 15x 35x
Margen Operativo 28.5% 24.1% 22.3%
ROE 38.2% 27.8% 32.1%
Dividend Yield 3.1% 3.0% 0%
Deuda/Patrimonio Moderada Baja Moderada-Alta
Crecimiento Ingresos (5Y) 4.2% CAGR 5.8% CAGR 18.5% CAGR
Calificación S&P A+ AAA BB+
# ============================================================
# PUNTO 2: RETORNOS Y ESTADÍSTICAS
# ============================================================

# Retornos logarítmicos diarios
retornos <- na.omit(diff(log(precios)))

# Estadísticas
ret_promedio_diario <- colMeans(retornos)
ret_anualizado <- ret_promedio_diario * 252
vol_diaria <- apply(retornos, 2, sd)
vol_anualizada <- vol_diaria * sqrt(252)
rf_anual <- 0.04

# Tabla estadísticas base
tabla_est <- data.frame(
  Activo = tickers,
  N_Observaciones = nrow(retornos),
  Ret_Diario_Prom = percent(ret_promedio_diario, accuracy = 0.001),
  Ret_Anual = percent(ret_anualizado, accuracy = 0.01),
  Vol_Diaria = percent(vol_diaria, accuracy = 0.001),
  Vol_Anual = percent(vol_anualizada, accuracy = 0.01),
  Sharpe_Indiv = round((ret_anualizado - rf_anual) / vol_anualizada, 4),
  row.names = NULL
)

tabla_est %>%
  kbl(
    caption = "Tabla 2.1: Estadísticas de Retorno y Riesgo (2016–2026)",
    align = "c",
    col.names = c("Activo", "N Obs.", "Ret. Diario",
                  "Ret. Anual", "Vol. Diaria",
                  "Vol. Anual", "Sharpe Ratio")
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center"
  ) %>%
  row_spec(0, bold = TRUE, background = "#2C3E50", color = "white") %>%
  add_header_above(c(" " = 2,
                     "Retornos" = 2,
                     "Volatilidad" = 2,
                     "Eficiencia" = 1))
Tabla 2.1: Estadísticas de Retorno y Riesgo (2016–2026)
Retornos
Volatilidad
Eficiencia
Activo N Obs. Ret. Diario Ret. Anual Vol. Diaria Vol. Anual Sharpe Ratio
KO 2512 0.035% 8.78% 1.147% 18.22% 0.2623
JNJ 2512 0.039% 9.79% 1.160% 18.42% 0.3146
NFLX 2512 0.091% 22.99% 2.660% 42.22% 0.4498
# Matriz de Varianza-Covarianza Anualizada
matriz_cov_anual <- cov(retornos) * 252

# Matriz de Correlaciones
matriz_cor <- cor(retornos)

# Tabla covarianza
as.data.frame(round(matriz_cov_anual, 6)) %>%
  kbl(caption = "Tabla 2.2: Matriz de Varianza-Covarianza Anualizada") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = FALSE, position = "center"
  ) %>%
  row_spec(0, bold = TRUE, background = "#1A5276", color = "white") %>%
  column_spec(1, bold = TRUE, background = "#D6EAF8")
Tabla 2.2: Matriz de Varianza-Covarianza Anualizada
KO JNJ NFLX
KO 0.033179 0.016742 0.009346
JNJ 0.016742 0.033922 0.009340
NFLX 0.009346 0.009340 0.178244
# Heatmap de correlaciones
melted_cor <- melt(matriz_cor)
p_cor <- ggplot(melted_cor, aes(x = Var1, y = Var2, fill = value)) +
  geom_tile(color = "white", size = 1.2) +
  geom_text(aes(label = round(value, 3)),
            color = "white", size = 5, fontface = "bold") +
  scale_fill_gradient2(
    low = "#2980B9", mid = "#ECF0F1", high = "#C0392B",
    midpoint = 0.5, limits = c(0, 1),
    name = "Correlación"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.text = element_text(face = "bold", size = 12),
    plot.title = element_text(face = "bold", hjust = 0.5, size = 14),
    panel.grid = element_blank()
  ) +
  labs(
    title = "Mapa de Calor: Matriz de Correlaciones",
    subtitle = "Retornos diarios 2016–2026",
    x = NULL, y = NULL,
    caption = "Correlaciones calculadas sobre retornos logarítmicos diarios"
  )

ggplotly(p_cor)
# Crecimiento acumulado de $1 invertido
acumulados <- exp(apply(retornos, 2, cumsum))
acumulados_df <- data.frame(
  Fecha = index(retornos),
  as.data.frame(acumulados)
)
acumulados_long <- pivot_longer(
  acumulados_df, cols = -Fecha,
  names_to = "Activo", values_to = "Valor"
)

p_acum <- ggplot(acumulados_long, aes(x = Fecha, y = Valor, color = Activo)) +
  geom_line(size = 0.9) +
  scale_color_manual(values = colores_port) +
  scale_y_continuous(labels = dollar_format(prefix = "$")) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "bottom"
  ) +
  labs(
    title = "Crecimiento de $1 USD Invertido (2016–2026)",
    subtitle = "Retornos logarítmicos acumulados",
    x = "Fecha", y = "Valor Acumulado (USD)",
    caption = "Fuente: Yahoo Finance | Elaboración propia"
  )

ggplotly(p_acum) %>%
  layout(
    hovermode = "x unified",
    legend = list(orientation = "h", y = -0.2)
  )
## PUNTO 3 - OPTIMIZACIÓN MEDIA-VARIANZA (Mejorado con Frontera Eficiente)


#optimizacion_portafolio
# ============================================================
# PUNTO 3: OPTIMIZACIÓN MEDIA-VARIANZA
# ============================================================

capital_total <- 20000000
rf_anual <- 0.04
mu <- ret_anualizado
sigma <- matriz_cov_anual
n <- length(tickers)

# ---- Frontera Eficiente ----
n_puntos <- 200
frontera <- data.frame(
  Retorno = numeric(n_puntos),
  Riesgo = numeric(n_puntos),
  Sharpe = numeric(n_puntos),
  w_KO = numeric(n_puntos),
  w_JNJ = numeric(n_puntos),
  w_NFLX = numeric(n_puntos)
)

retornos_objetivo <- seq(min(mu) * 0.8, max(mu) * 1.2, length.out = n_puntos)
Amat_base <- cbind(rep(1, n), diag(n))
bvec_base <- c(1, rep(0, n))

contador <- 0
for (i in seq_along(retornos_objetivo)) {
  tryCatch({
    res <- solve.QP(
      Dmat = 2 * sigma,
      dvec = rep(0, n),
      Amat = cbind(mu, Amat_base),
      bvec = c(retornos_objetivo[i], bvec_base),
      meq = 2
    )
    w <- res$solution
    if (all(w >= -1e-6)) {
      w <- pmax(w, 0)
      w <- w / sum(w)
      contador <- contador + 1
      p_ret <- sum(w * mu)
      p_sd <- sqrt(t(w) %*% sigma %*% w)[1,1]
      frontera[contador, ] <- c(p_ret, p_sd,
                                 (p_ret - rf_anual) / p_sd,
                                 w[1], w[2], w[3])
    }
  }, error = function(e) NULL)
}

frontera <- frontera[1:contador, ]

# ---- Portafolio Óptimo de Sharpe ----
idx_sharpe <- which.max(frontera$Sharpe)
optimo <- frontera[idx_sharpe, ]
pesos_finales <- as.numeric(c(optimo$w_KO, optimo$w_JNJ, optimo$w_NFLX))
names(pesos_finales) <- tickers

# ---- Portafolio Mínima Varianza ----
idx_minvar <- which.min(frontera$Riesgo)
min_var <- frontera[idx_minvar, ]

# ---- Gráfico de Frontera Eficiente ----
p_frontera <- ggplot(frontera, aes(x = Riesgo * 100, y = Retorno * 100)) +
  geom_path(aes(color = Sharpe), size = 1.5) +
  scale_color_gradient(low = "#3498DB", high = "#E74C3C",
                       name = "Sharpe Ratio") +
  geom_point(
    data = data.frame(
      Riesgo = optimo$Riesgo * 100,
      Retorno = optimo$Retorno * 100,
      label = "Máximo Sharpe"
    ),
    aes(x = Riesgo, y = Retorno),
    color = "#E74C3C", size = 5, shape = 18
  ) +
  geom_point(
    data = data.frame(
      Riesgo = min_var$Riesgo * 100,
      Retorno = min_var$Retorno * 100,
      label = "Mínima Varianza"
    ),
    aes(x = Riesgo, y = Retorno),
    color = "#27AE60", size = 4, shape = 17
  ) +
  annotate("text",
           x = optimo$Riesgo * 100 + 0.5,
           y = optimo$Retorno * 100,
           label = paste0("Sharpe Óptimo\n(",
                          round(optimo$Retorno * 100, 1), "% ret | ",
                          round(optimo$Riesgo * 100, 1), "% vol)"),
           color = "#E74C3C", size = 3.5, hjust = 0) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "right"
  ) +
  labs(
    title = "Frontera Eficiente de Markowitz",
    subtitle = "Portafolio KO | JNJ | NFLX — Capital $20M USD",
    x = "Volatilidad Anualizada (%)",
    y = "Retorno Esperado Anualizado (%)",
    caption = "Tasa libre de riesgo: 4.0% | Restricción: pesos ≥ 0 (sin ventas en corto)"
  )

ggplotly(p_frontera)
# Tabla de distribución óptima
monto_usd <- pesos_finales * capital_total
vol_anualizada_named <- vol_anualizada
names(vol_anualizada_named) <- tickers

tabla_optima <- data.frame(
  Activo = tickers,
  Peso = percent(pesos_finales, accuracy = 0.01),
  Monto_USD = dollar(monto_usd),
  Ret_Esperado = percent(mu[tickers], accuracy = 0.01),
  Volatilidad = percent(vol_anualizada_named[tickers], accuracy = 0.01),
  Contribucion = percent(
    (pesos_finales * vol_anualizada_named[tickers]) /
      sum(pesos_finales * vol_anualizada_named[tickers]),
    accuracy = 0.01
  ),
  row.names = NULL
)

tabla_optima %>%
  kbl(
    caption = "Tabla 3.1: Distribución Óptima de Capital — Portafolio Máximo Sharpe",
    align = "c",
    col.names = c("Activo", "Peso (wᵢ)", "Monto USD",
                  "Retorno Esperado", "Volatilidad",
                  "Contribución al Riesgo")
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center"
  ) %>%
  row_spec(0, bold = TRUE, background = "#2C3E50", color = "white") %>%
  add_header_above(
    c(" " = 1, "Estrategia de Asignación" = 2,
      "Métricas Individuales" = 2, "Análisis de Riesgo" = 1)
  ) %>%
  footnote(
    general = paste0(
      "Retorno Portafolio: ", round(optimo$Retorno * 100, 2), "% | ",
      "Volatilidad: ", round(optimo$Riesgo * 100, 2), "% | ",
      "Sharpe Ratio: ", round(optimo$Sharpe, 4), " | ",
      "Capital Total: $20,000,000 USD"
    ),
    general_title = "Resumen Portafolio Óptimo: ",
    footnote_as_chunk = TRUE
  )
Tabla 3.1: Distribución Óptima de Capital — Portafolio Máximo Sharpe
Estrategia de Asignación
Métricas Individuales
Análisis de Riesgo
Activo Peso (wᵢ) Monto USD Retorno Esperado Volatilidad Contribución al Riesgo
KO 21.30% $4,260,422 8.78% 18.22% 14.37%
JNJ 42.46% $8,491,815 9.79% 18.42% 28.96%
NFLX 36.24% $7,247,763 22.99% 42.22% 56.67%
Resumen Portafolio Óptimo: Retorno Portafolio: 14.36% | Volatilidad: 19.59% | Sharpe Ratio: 0.5289 | Capital Total: $20,000,000 USD
# Gráfico de pastel interactivo
pie_data <- data.frame(
  Activo = tickers,
  Peso = pesos_finales * 100,
  Monto = monto_usd
)

plot_ly(pie_data,
        labels = ~Activo,
        values = ~Peso,
        type = "pie",
        textinfo = "label+percent",
        hovertemplate = paste(
          "<b>%{label}</b><br>",
          "Peso: %{percent}<br>",
          "Monto: $%{value:.2f}M<br>",
          "<extra></extra>"
        ),
        marker = list(
          colors = c("#E74C3C", "#E67E22", "#3498DB"),
          line = list(color = "white", width = 2)
        )) %>%
  layout(
    title = list(
      text = "Distribución Óptima del Capital ($20M USD)",
      font = list(size = 16, color = "#2C3E50")
    ),
    showlegend = TRUE
  )
## PUNTO 4 - VaR (Mejorado)

#r var_portafolio}
# ============================================================
# PUNTO 4: VALOR EN RIESGO (VaR)
# ============================================================

vol_anual_p <- optimo$Riesgo
vol_mensual_p <- vol_anual_p / sqrt(12)
ret_mensual_p <- optimo$Retorno / 12

# VaR Paramétrico
niveles <- c(0.95, 0.99)
z_scores <- qnorm(niveles)
var_pct <- z_scores * vol_mensual_p
var_usd <- var_pct * capital_total

# VaR Histórico (simulación con retornos del portafolio)
ret_port_hist <- as.numeric(retornos %*% pesos_finales)

# Agrupación mensual del VaR histórico
fechas_ret <- index(retornos)
meses <- format(fechas_ret, "%Y-%m")
ret_mensual_hist <- tapply(ret_port_hist, meses, sum)

var_hist_95 <- quantile(ret_mensual_hist, 0.05)
var_hist_99 <- quantile(ret_mensual_hist, 0.01)

# Tabla VaR comparativa
tabla_var <- data.frame(
  Metodo = c("Paramétrico", "Paramétrico", "Histórico", "Histórico"),
  Nivel = c("95%", "99%", "95%", "99%"),
  Z_Score = c(round(z_scores, 4), NA, NA),
  VaR_Pct = c(
    percent(abs(var_pct[1]), accuracy = 0.01),
    percent(abs(var_pct[2]), accuracy = 0.01),
    percent(abs(var_hist_95), accuracy = 0.01),
    percent(abs(var_hist_99), accuracy = 0.01)
  ),
  VaR_USD = c(
    dollar(abs(var_usd[1])),
    dollar(abs(var_usd[2])),
    dollar(abs(var_hist_95) * capital_total),
    dollar(abs(var_hist_99) * capital_total)
  ),
  Interpretacion = c(
    "1 de cada 20 meses",
    "1 de cada 100 meses",
    "Basado en historia real",
    "Escenario de estrés extremo"
  )
)

tabla_var %>%
  kbl(
    caption = "Tabla 4.1: Valor en Riesgo (VaR) Mensual — Portafolio $20M USD",
    align = "c",
    col.names = c("Método", "Confianza", "Z-Score",
                  "VaR (%)", "VaR (USD)", "Frecuencia del Evento")
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center"
  ) %>%
  row_spec(0, bold = TRUE, background = "#2C3E50", color = "white") %>%
  row_spec(c(2, 4), bold = TRUE, background = "#FADBD8") %>%
  footnote(
    general = paste0(
      "Volatilidad mensual del portafolio: ",
      percent(vol_mensual_p, accuracy = 0.01),
      " | Capital base: $20,000,000 USD"
    ),
    general_title = "Parámetros: "
  )
Tabla 4.1: Valor en Riesgo (VaR) Mensual — Portafolio $20M USD
Método Confianza Z-Score VaR (%) VaR (USD) Frecuencia del Evento
Paramétrico 95% 1.6449 9.30% $1,860,323 1 de cada 20 meses
Paramétrico 99% 2.3263 13.16% $2,631,090 1 de cada 100 meses
Histórico 95% NA 6.48% $1,296,820 Basado en historia real
Histórico 99% NA 11.09% $2,218,011 Escenario de estrés extremo
Parámetros:
Volatilidad mensual del portafolio: 5.65% | Capital base: $20,000,000 USD
# Histograma de retornos mensuales históricos con VaR
hist_df <- data.frame(Retorno = ret_mensual_hist * 100)

p_var <- ggplot(hist_df, aes(x = Retorno)) +
  geom_histogram(aes(y = after_stat(density)),
                 bins = 30,
                 fill = "#3498DB", color = "white", alpha = 0.7) +
  geom_density(color = "#2C3E50", size = 1.2) +
  geom_vline(
    xintercept = var_hist_95 * 100,
    color = "#E67E22", linetype = "dashed", size = 1.2,
    show.legend = TRUE
  ) +
  geom_vline(
    xintercept = var_hist_99 * 100,
    color = "#E74C3C", linetype = "dashed", size = 1.2,
    show.legend = TRUE
  ) +
  annotate("text",
           x = var_hist_95 * 100 - 0.5,
           y = 0.15,
           label = paste0("VaR 95%\n", round(var_hist_95 * 100, 2), "%"),
           color = "#E67E22", hjust = 1, size = 3.5) +
  annotate("text",
           x = var_hist_99 * 100 - 0.5,
           y = 0.12,
           label = paste0("VaR 99%\n", round(var_hist_99 * 100, 2), "%"),
           color = "#E74C3C", hjust = 1, size = 3.5) +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5)) +
  labs(
    title = "Distribución de Retornos Mensuales del Portafolio",
    subtitle = "VaR histórico al 95% y 99%",
    x = "Retorno Mensual (%)", y = "Densidad",
    caption = "Retornos calculados sobre datos 2016-2026"
  )

ggplotly(p_var)