1 Selección de Acciones y Análisis Fundamental

1.1 Criterios de selección

Las tres acciones seleccionadas pertenecen al S&P 500 y fueron filtradas mediante la plataforma FINVIZ (sección Fundamentals) aplicando los siguientes umbrales cuantitativos:

Criterio Umbral Justificación
EPS Growth (Next 5Y) ≥ 12 % Crecimiento sostenido de utilidades
Debt/Equity (D/E) ≤ 0.80 Bajo apalancamiento financiero
Return on Assets (ROA) ≥ 7 % Eficiencia en uso de activos
Profit Margin ≥ 10 % Solidez operacional real
Forward P/E 12 – 30 Valoración razonable vs. crecimiento

1.2 Portafolio seleccionado

fundamental <- data.frame(
  Empresa  = c("Adobe Inc.", "Vertex Pharmaceuticals", "Monster Beverage"),
  Ticker   = c("ADBE", "VRTX", "MNST"),
  Sector   = c("Software / Inteligencia Artificial","Salud / Biotecnología","Consumo Defensivo"),
  EPS_5Y   = c("12.5%","18.3%","10.8%"),
  DE       = c("0.41","0.00","0.07"),
  ROA      = c("15.2%","14.8%","16.1%"),
  Margen   = c("21.4%","26.7%","22.3%"),
  FwdPE    = c("22.1","19.4","24.6")
)
kable(fundamental,
      col.names = c("Empresa","Ticker","Sector","EPS Next 5Y","D/E","ROA","Margen Neto","Forward P/E"),
      caption   = "Tabla 1. Fundamentales de las acciones seleccionadas (FINVIZ, abril 2026)") |>
  kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
  column_spec(1, bold=TRUE)
Tabla 1. Fundamentales de las acciones seleccionadas (FINVIZ, abril 2026)
Empresa Ticker Sector EPS Next 5Y D/E ROA Margen Neto Forward P/E
Adobe Inc.  ADBE Software / Inteligencia Artificial 12.5% 0.41 15.2% 21.4% 22.1
Vertex Pharmaceuticals VRTX Salud / Biotecnología 18.3% 0.00 14.8% 26.7% 19.4
Monster Beverage MNST Consumo Defensivo 10.8% 0.07 16.1% 22.3% 24.6

1.3 Análisis cualitativo por acción

Descripción general y sector: Adobe Inc. es una compañía tecnológica estadounidense fundada en 1982, con sede en San José, California. Opera en el sector de Software de Aplicaciones del S&P 500 y es el líder mundial en software creativo y de documentos digitales. Sus plataformas —Creative Cloud, Document Cloud y Experience Cloud— atienden a más de 30 millones de suscriptores activos bajo un modelo de suscripción recurrente (SaaS) (Adobe Inc., 2025).

Principales fuentes de ingresos: En el año fiscal 2025 (cerrado en noviembre), Adobe reportó ingresos totales de USD 23,769 millones (+10.5 % interanual). El segmento Digital Media —que agrupa Creative Cloud y Document Cloud— aportó USD 17,650 millones (74 % del total), mientras que Digital Experience contribuyó con USD 5,860 millones. El Annual Recurring Revenue (ARR) alcanzó USD 25,200 millones, con más de un tercio proveniente ya de productos con capacidades de inteligencia artificial (Adobe Inc., 2025).

Evolución reciente del precio de mercado: La acción experimentó una caída de aproximadamente el 42 % desde sus máximos históricos cercanos a USD 540 en 2024, cerrando en torno a USD 247 al 30 de abril de 2026. Esta corrección respondió al denominado “AI existentialism”: el temor del mercado a que herramientas de IA generativa gratuitas erosionen el valor de las suscripciones de Creative Cloud. Sin embargo, los indicadores técnicos señalan sobreventa (RSI ≈ 29), y el 21 de abril de 2026 el directorio aprobó un programa de recompra de acciones por USD 25,000 millones con vigencia hasta 2030, actuando como soporte estructural (StockAnalysis, 2026; Benzinga, 2026).

Situación financiera: La utilidad neta GAAP de FY2025 fue de USD 7,130 millones (+28.2 %), con EPS GAAP de USD 16.73 (+34.6 %). El flujo de caja operativo superó los USD 10,000 millones anuales, con un margen neto del 30 %. La compañía opera sin endeudamiento excesivo y con D/E de 0.41 (FullRatio, 2026).

Expectativas de precio: El consenso de ~55 analistas al 30 de abril de 2026 proyecta un precio objetivo mediano de USD 317–347 en 12 meses (+28–40 % de upside). La guidance de Adobe para FY2026 contempla ingresos de USD 25,900–26,100 millones y EPS no-GAAP de USD 23.30–23.50 (TickerNerd, 2026a).

Justificación de inclusión: Adobe fue incluida en el portafolio como una apuesta de recuperación dentro del sector tecnológico. A pesar de la corrección significativa observada en su precio durante 2025–2026, la compañía continúa mostrando fundamentos financieros sólidos, caracterizados por altos márgenes operacionales, fuerte generación de flujo de caja y una posición competitiva dominante en software creativo y documental. Adicionalmente, el mercado ha reaccionado de forma excesivamente negativa frente a los riesgos asociados a la inteligencia artificial generativa, descontando en el precio un escenario de deterioro que los fundamentos operacionales no confirman. Desde la perspectiva del portafolio, su inclusión permite obtener exposición al sector tecnológico sin recurrir a acciones excesivamente utilizadas en ejercicios académicos y, al mismo tiempo, aporta potencial de valorización. De acuerdo con los resultados del modelo de optimización, se asigna un peso del 15 %, correspondiente al límite mínimo establecido, lo que permite capturar dicho potencial manteniendo controlado el riesgo agregado del portafolio (Markowitz, 1952).


Descripción general y sector: Vertex Pharmaceuticals, fundada en 1989 con sede en Boston, Massachusetts, opera en el sector Farmacéutica/Biofarmacéutica del S&P 500. Es el líder global en el tratamiento de la fibrosis quística (FQ), cubriendo >90 % de los pacientes elegibles con su trilogía Trikafta/Kaftrio (Vertex Pharmaceuticals, 2026a).

Principales fuentes de ingresos: Los ingresos de FY2025 alcanzaron USD 12,000 millones (+9 % interanual), con la franquicia de FQ aportando ~USD 11,200 millones. CASGEVY —primera terapia CRISPR aprobada en el mundo para enfermedad de células falciformes— y JOURNAVX —primer analgésico no-opioide en su clase aprobado por la FDA en 2025— aportaron conjuntamente más del 25 % del crecimiento en Q1 2026 (Vertex Pharmaceuticals, 2026b).

Evolución reciente del precio de mercado: La acción ha mostrado mayor estabilidad que sus pares tecnológicos, cotizando en el rango USD 362–511 en los últimos 52 semanas y ubicándose en torno a USD 441 al 30 de abril de 2026. La resiliencia refleja la predictibilidad de los ingresos de FQ y la credibilidad del pipeline en ejecución (Investing.com, 2026).

Situación financiera: Utilidad neta FY2025 de USD 3,950 millones, margen operativo del 34.7 %, caja e inversiones de USD 12,300 millones y D/E = 0. La sólida posición de caja permite financiar I+D y adquisiciones estratégicas (Alpine Immune Sciences por USD 4,900 millones) sin diluir al accionista (Vertex Pharmaceuticals, 2026a).

Expectativas de precio: Consenso de 29–47 analistas con precio objetivo mediano de USD 548–558 en 12 meses (+25–27 % de upside). Morgan Stanley mantiene objetivo de USD 612 (Overweight). El catalizador principal en el horizonte de 4 años es la aprobación potencial de povetacicept para nefropatía por IgA (IgAN) (Benzinga, 2026b).

Justificación de inclusión: Vertex cumple el rol de activo estabilizador dentro del portafolio debido a la predictibilidad de sus ingresos y a su menor sensibilidad frente a los ciclos del mercado. Su liderazgo en tratamientos para fibrosis quística, junto con una posición financiera sólida y ausencia de endeudamiento relevante, le otorgan un perfil defensivo frente a escenarios adversos. Adicionalmente, la compañía mantiene oportunidades de crecimiento asociadas a nuevas terapias y expansión de su pipeline, lo que evita sacrificar completamente el potencial de rentabilidad. De acuerdo con el modelo de optimización, Vertex recibe la mayor participación del portafolio (60 %), reflejando una combinación favorable entre retorno esperado y riesgo relativo dentro de los activos seleccionados (Markowitz, 1952).


Descripción general y sector: Monster Beverage Corporation, fundada en 1985 con sede en Corona, California, opera en el sector Consumo Defensivo del S&P 500. Es el segundo fabricante global de bebidas energéticas y distribuye en más de 150 países a través de la red de embotelladoras de Coca-Cola, bajo acuerdo estratégico vigente desde 2015 (Yahoo Finance, 2026c).

Principales fuentes de ingresos: Los ingresos de FY2025 ascendieron a USD 8,294 millones (+10.7 %), con el segmento Monster Energy Drinks aportando ~92 % del total. En Q1 2026 (reportado el 7 de mayo de 2026), las ventas netas crecieron 26.9 % interanual a USD 2,350 millones, superando el consenso de USD 2,160 millones. Las ventas internacionales crecieron ~45 % y ya representan el 45 % del total (Monster Beverage Corporation, 2026).

Evolución reciente del precio de mercado: Desde su mínimo de 52 semanas de USD 50.93, la acción escaló un 64.5 %, alcanzando un nuevo máximo histórico de USD 88.77 el 8 de mayo de 2026 (post Q1 earnings). Al 30 de abril de 2026 —fecha de referencia de la inversión— cotizaba en torno a USD 77, lo que refleja una trayectoria alcista bien establecida antes del catalizador de resultados (TradingView, 2026).

Situación financiera: Margen bruto del 55.8 % en FY2025 (expansión de 180 pbs), margen operativo del 30.7 % y D/E = 0.07. La compañía opera bajo un modelo de baja intensidad en activos —subcontrata manufactura y usa la red Coca-Cola para distribución—, lo que genera alta conversión de flujo de caja libre sin requerir inversión significativa en infraestructura propia (TIKR, 2026a).

Expectativas de precio: Post Q1 2026, varios bancos actualizaron sus objetivos: Rothschild & Co Redburn (USD 90, upgrade a Buy), Deutsche Bank (USD 88–90, Buy), Wells Fargo (USD 85, Overweight) y BofA (USD 96–102, Buy) (StockAnalysis, 2026c).

Dividendos: Monster Beverage no paga dividendos en efectivo. La política de la compañía es reinvertir toda la generación de caja en crecimiento orgánico e inorgánico y recompras de acciones. Esta información es verificable directamente en el perfil de la acción en Yahoo Finance (2026c), en la política oficial reportada ante la SEC y en plataformas especializadas en historial de dividendos como DividendMax, que reporta ausencia de pagos históricos en efectivo para esta compañía.

Justificación de inclusión: Monster Beverage fue incorporada al portafolio como una alternativa de consumo defensivo con capacidad de crecimiento sostenido. A diferencia de Adobe y Vertex, la compañía aporta exposición a un sector menos sensible a cambios tecnológicos o regulatorios, favoreciendo la diversificación del riesgo total del portafolio. Su modelo de negocio presenta márgenes elevados, bajo endeudamiento y una expansión internacional relevante respaldada por la red de distribución de Coca-Cola, factores que sustentan la estabilidad financiera de la empresa. Aunque su crecimiento esperado de utilidades (10.8 %) se ubica ligeramente por debajo del umbral mínimo definido del 12 %, fue retenida por su capacidad de diversificación sectorial, estabilidad operativa y menor exposición sistemática frente a las demás acciones seleccionadas. Asimismo, su beta relativamente baja contribuye a moderar la exposición sistemática del portafolio. El modelo de optimización asigna una participación del 25 %, reflejando un balance entre potencial de rentabilidad y diversificación sectorial (Fabozzi et al., 2007).


2 Datos Históricos y Estadísticas Descriptivas

library(quantmod)
inicio <- "2018-01-01"
fin    <- as.Date("2026-04-30")

descargar <- function(ticker, from, to) {
  tryCatch(getSymbols(ticker, src="yahoo", from=from, to=to, auto.assign=FALSE),
           error=function(e){ message("Error: ", ticker); NULL })
}

sp500  <- descargar("^GSPC", inicio, fin)
adbe   <- descargar("ADBE",  inicio, fin)
vrtx   <- descargar("VRTX",  inicio, fin)
mnst   <- descargar("MNST",  inicio, fin)
tnx    <- descargar("^TNX",  inicio, fin)

futuro <- tryCatch(
  getSymbols("ES=F", src="yahoo", from=inicio, to=fin, auto.assign=FALSE),
  error=function(e){ message("ES=F no disponible, usando ^GSPC como proxy"); sp500 })

datos_xts <- merge(Ad(sp500), Ad(futuro), Ad(adbe), Ad(vrtx), Ad(mnst),
                   Ad(tnx), join="inner")
colnames(datos_xts) <- c("SP500","SP500F","ADBE","VRTX","MNST","TNX")
datos_xts <- na.omit(datos_xts)

datos <- data.frame(Fecha=index(datos_xts), coredata(datos_xts))
rownames(datos) <- NULL

info_df <- data.frame(
  Concepto = c("Fecha inicial","Fecha final","Observaciones diarias"),
  Valor    = c(format(min(datos$Fecha),"%d/%m/%Y"),
               format(max(datos$Fecha),"%d/%m/%Y"),
               as.character(nrow(datos)))
)
kable(info_df, col.names=c("Concepto","Valor"),
      caption="Información del período histórico descargado") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  column_spec(1, bold=TRUE)
Información del período histórico descargado
Concepto Valor
Fecha inicial 02/01/2018
Fecha final 29/04/2026
Observaciones diarias 2092
ret <- data.frame(
  Fecha  = datos$Fecha[-1],
  SP500  = diff(log(datos$SP500)),
  SP500F = diff(log(datos$SP500F)),
  ADBE   = diff(log(datos$ADBE)),
  VRTX   = diff(log(datos$VRTX)),
  MNST   = diff(log(datos$MNST))
)
ret <- na.omit(ret)

# Retornos mensuales (último cierre de mes)
datos$YM <- format(datos$Fecha, "%Y-%m")
mensual  <- datos |> group_by(YM) |> slice_tail(n=1) |> ungroup() |> arrange(Fecha)
ret_m    <- data.frame(
  Fecha  = mensual$Fecha[-1],
  SP500  = diff(log(mensual$SP500)),
  SP500F = diff(log(mensual$SP500F)),
  ADBE   = diff(log(mensual$ADBE)),
  VRTX   = diff(log(mensual$VRTX)),
  MNST   = diff(log(mensual$MNST))
) |> na.omit()

met_df <- data.frame(
  Concepto = c("Retornos diarios calculados","Retornos mensuales calculados",
               "Frecuencia para estadísticas","Procedimiento de anualización"),
  Valor    = c(as.character(nrow(ret)), as.character(nrow(ret_m)),
               "Diaria (252 días hábiles/año)",
               "μ_anual = exp(μ_d × 252) − 1   |   σ_anual = σ_d × √252")
)
kable(met_df, col.names=c("Concepto","Valor"),
      caption="Configuración de retornos y anualización") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  column_spec(1, bold=TRUE)
Configuración de retornos y anualización
Concepto Valor
Retornos diarios calculados 2091
Retornos mensuales calculados 99
Frecuencia para estadísticas Diaria (252 días hábiles/año)
Procedimiento de anualización μ_anual = exp(μ_d × 252) − 1 &#124; σ_anual = σ_d × √252

Aunque se calcularon retornos mensuales para fines comparativos y de consistencia temporal con la liquidación trimestral del ejercicio, las estimaciones de riesgo y optimización del portafolio se realizaron con retornos diarios, dado que proporcionan un número significativamente mayor de observaciones y estimaciones más estables de media, volatilidad y covarianza.

2.1 Estadísticas descriptivas

anualizar <- function(rv, freq=252) {
  list(mu    = exp(mean(rv,na.rm=TRUE)*freq)-1,
       sigma = sd(rv,na.rm=TRUE)*sqrt(freq))
}
activos <- c("ADBE","VRTX","MNST")

stats_d <- lapply(activos, function(a) {
  r <- ret[[a]]; e <- anualizar(r)
  data.frame(Activo=a, Ret_Diario=mean(r), Ret_Anual=e$mu,
             Vol_Diaria=sd(r), Vol_Mensual=sd(r)*sqrt(21),
             Vol_Anual=e$sigma, Min=min(r), Max=max(r))
}) |> bind_rows()

kable(stats_d, digits=4,
      col.names=c("Activo","Ret. Diario","Ret. Anual","Vol. Diaria",
                  "Vol. Mensual","Vol. Anual","Ret. Mínimo","Ret. Máximo"),
      caption="Tabla 2. Estadísticas descriptivas de retornos (diarios, 2018–2026)") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE)
Tabla 2. Estadísticas descriptivas de retornos (diarios, 2018–2026)
Activo Ret. Diario Ret. Anual Vol. Diaria Vol. Mensual Vol. Anual Ret. Mínimo Ret. Máximo
ADBE 2e-04 0.0387 0.0229 0.1050 0.3637 -0.1838 0.1631
VRTX 5e-04 0.1305 0.0202 0.0925 0.3204 -0.2319 0.1411
MNST 4e-04 0.1142 0.0169 0.0774 0.2681 -0.1559 0.0846

Nota metodológica: Se utilizan retornos logarítmicos continuos con frecuencia diaria, siguiendo la convención estándar en finanzas cuantitativas (Bodie et al., 2008). La anualización aplica la regla de la raíz del tiempo para la volatilidad:

\(\hat{\sigma}_{anual} = \hat{\sigma}_{diaria} \times \sqrt{252}\)

donde 252 representa los días hábiles bursátiles del año en los mercados estadounidenses.

El retorno anual esperado se calcula como:

\(\hat{\mu}_{anual} = e^{\bar{r}_{diario} \times 252} - 1\)

que corresponde a la conversión de retorno continuo a efectivo anual.

La frecuencia diaria se prefiere sobre la mensual porque proporciona mayor número de observaciones (>2.000 datos vs. ~100 mensuales), mejorando la precisión estadística de los estimadores de media, varianza y covarianza utilizados en la optimización.

2.2 Matriz de varianzas-covarianzas y correlaciones

cov_mat <- cov(ret[,activos]) * 252
cor_mat <- cor(ret[,activos])

kable(cov_mat*1e4, digits=3,
      caption="Tabla 3. Matriz de Varianzas-Covarianzas anualizada (×10⁴)") |>
  kable_styling(bootstrap_options=c("striped","hover"))
Tabla 3. Matriz de Varianzas-Covarianzas anualizada (×10⁴)
ADBE VRTX MNST
ADBE 1322.461 405.116 385.838
VRTX 405.116 1026.785 283.345
MNST 385.838 283.345 718.929
kable(cor_mat, digits=4,
      caption="Tabla 4. Matriz de Correlaciones") |>
  kable_styling(bootstrap_options=c("striped","hover"))
Tabla 4. Matriz de Correlaciones
ADBE VRTX MNST
ADBE 1.0000 0.3477 0.3957
VRTX 0.3477 1.0000 0.3298
MNST 0.3957 0.3298 1.0000
corrplot(cor_mat,
         method      = "color",
         addCoef.col = "black",
         number.cex  = 1.1,
         number.digits = 2,
         tl.col      = "#2d3748",
         tl.srt      = 45,
         tl.cex      = 0.95,
         cl.cex      = 0.85,
         col         = colorRampPalette(c("#f7c59f","#ffffff","#2c5282"))(200),
         col.lim     = c(-1, 1),
         title       = "Figura 1. Mapa de calor — Correlaciones entre acciones",
         mar         = c(0, 0, 2, 0))

Análisis de correlaciones: Las correlaciones entre las tres acciones son positivas pero moderadas, lo que confirma la existencia de beneficios de diversificación al combinarlas dentro de un mismo portafolio (Hull, 2009). De acuerdo con la teoría de Markowitz, cuando las correlaciones son inferiores a uno, es posible reducir el riesgo agregado sin eliminar completamente el retorno esperado. La correlación relativamente mayor entre Adobe y Monster (~0.40) puede asociarse a cierta sensibilidad compartida frente al ciclo económico general y al comportamiento del mercado accionario estadounidense, aunque pertenecen a sectores diferentes —tecnología y consumo defensivo, respectivamente—. Por su parte, Vertex presenta las correlaciones más bajas (~0.33–0.35), reforzando su papel como activo estabilizador dentro del portafolio, debido a que el comportamiento de sus ingresos farmacéuticos depende menos del ciclo económico que los sectores tecnológico y de consumo.

precio_norm <- datos |>
  select(Fecha, ADBE, VRTX, MNST) |>
  na.omit() |>
  mutate(ADBE=ADBE/ADBE[1], VRTX=VRTX/VRTX[1], MNST=MNST/MNST[1]) |>
  pivot_longer(-Fecha, names_to="Accion", values_to="Precio")

ggplot(precio_norm, aes(x=Fecha, y=Precio, color=Accion)) +
  geom_line(linewidth=0.8) +
  scale_color_manual(values=pal_acc) +
  scale_y_continuous(labels=label_number(suffix="x")) +
  geom_vline(xintercept=as.Date("2026-04-30"), linetype="dashed", color="black", alpha=0.5) +
  annotate("text", x=as.Date("2026-04-30"), y=max(precio_norm$Precio)*0.9,
           label="Inicio inversión\n30 abr 2026", hjust=1.1, size=3, color="black") +
  labs(title="Figura 2. Retorno acumulado normalizado (base=1 en ene-2018)",
       subtitle="Línea punteada: fecha de inicio de la inversión (30/04/2026)",
       x=NULL, y="Retorno normalizado", color="Acción") +
  tema_lab + theme(legend.position="top")

La evolución normalizada de precios evidencia trayectorias de crecimiento diferenciadas entre los activos seleccionados. Vertex presenta un comportamiento relativamente más estable a lo largo del período, consistente con su perfil defensivo y menor sensibilidad al ciclo económico. Adobe exhibe mayor volatilidad, particularmente durante el ajuste de expectativas relacionado con la inteligencia artificial generativa en 2025–2026. Monster muestra una tendencia alcista sostenida respaldada por la expansión internacional y el crecimiento de ingresos, aportando equilibrio entre estabilidad y potencial de valorización al portafolio.

2.3 Supuestos y parámetros

mu_anual    <- sapply(activos, function(a) anualizar(ret[[a]])$mu)
sigma_anual <- sapply(activos, function(a) anualizar(ret[[a]])$sigma)
Rf_anual    <- 0.0402
Rf_mensual  <- (1+Rf_anual)^(1/12)-1
Rf_trim     <- (1+Rf_anual)^(1/4)-1
capital     <- 20e6

# ── Tabla de parámetros de entrada ───────────────────────────────────────────
params_df <- data.frame(
  Parametro = c("Retorno anual esperado",
                "Volatilidad anual",
                "Tasa libre de riesgo — Rf anual (^TNX 5Y)",
                "Tasa libre de riesgo — Rf mensual equivalente",
                "Tasa libre de riesgo — Rf trimestral equivalente",
                "Capital total invertido"),
  ADBE = c(fmt_pct(mu_anual["ADBE"]), fmt_pct(sigma_anual["ADBE"]),
           "—","—","—","—"),
  VRTX = c(fmt_pct(mu_anual["VRTX"]), fmt_pct(sigma_anual["VRTX"]),
           "—","—","—","—"),
  MNST = c(fmt_pct(mu_anual["MNST"]), fmt_pct(sigma_anual["MNST"]),
           "—","—","—","—"),
  Global = c("—","—",
             fmt_pct(Rf_anual),
             fmt_pct(Rf_mensual),
             fmt_pct(Rf_trim),
             paste0("USD ", fmt_usd(capital)))
)

kable(params_df,
      col.names = c("Parámetro","ADBE","VRTX","MNST","Global / Portafolio"),
      caption   = "Tabla de parámetros de entrada para la optimización (Fuente: Yahoo Finance, 2026; CBOE, 2026)") |>
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = TRUE) |>
  column_spec(1, bold = TRUE)
Tabla de parámetros de entrada para la optimización (Fuente: Yahoo Finance, 2026; CBOE, 2026)
Parámetro ADBE VRTX MNST Global / Portafolio
Retorno anual esperado 3.87% 13.05% 11.42%
Volatilidad anual 36.37% 32.04% 26.81%
Tasa libre de riesgo — Rf anual (^TNX 5Y) 4.02%
Tasa libre de riesgo — Rf mensual equivalente 0.33%
Tasa libre de riesgo — Rf trimestral equivalente 0.99%
Capital total invertido USD 20,000,000.00

2.4 Optimización: Máximo Sharpe Ratio

set.seed(123)
N_sim <- 500000
sim_w <- matrix(runif(N_sim*3), ncol=3)
sim_w <- sim_w / rowSums(sim_w)
sim_w <- sim_w[apply(sim_w,1,function(w) all(w>=0.15) & all(w<=0.60)),]  # peso mínimo 15%, máximo 60%

ret_sim    <- sim_w %*% mu_anual
sigma_sim  <- sqrt(rowSums((sim_w %*% cov_mat)*sim_w))
sharpe_sim <- (ret_sim - Rf_anual)/sigma_sim

idx_best   <- which.max(sharpe_sim)
w_opt      <- sim_w[idx_best,]; names(w_opt) <- activos
idx_minvar <- which.min(sigma_sim)

ret_port   <- sum(w_opt*mu_anual)
sigma_port <- sqrt(as.numeric(t(w_opt)%*%cov_mat%*%w_opt))
sharpe_port<- (ret_port-Rf_anual)/sigma_port
ret_port_m <- (1+ret_port)^(1/12)-1
sigma_port_m <- sigma_port/sqrt(12)

w_check <- data.frame(
  Restriccion = c("Peso mínimo por acción (w_i >= 15 %)",
                  "Peso máximo por acción (w_i <= 60 %)",
                  "Suma de pesos igual a 100 %"),
  Resultado   = c(ifelse(all(w_opt >= 0.15), "Cumple", "No cumple"),
                  ifelse(all(w_opt <= 0.60), "Cumple", "No cumple"),
                  ifelse(abs(sum(w_opt) - 1) < 1e-6, "Cumple", "No cumple"))
)
kable(w_check, col.names = c("Restricción","Resultado"),
      caption = "Verificación de restricciones del portafolio óptimo") |>
  kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) |>
  column_spec(2, color = ifelse(w_check$Resultado == "Cumple", "#276749", "#c53030"),
              bold = TRUE)
Verificación de restricciones del portafolio óptimo
Restricción Resultado
Peso mínimo por acción (w_i >= 15 %) Cumple
Peso máximo por acción (w_i <= 60 %) Cumple
Suma de pesos igual a 100 % Cumple
resumen_opt <- data.frame(
  Accion   = activos,
  Peso     = w_opt,
  Monto    = w_opt*capital,
  Ret      = mu_anual,
  Vol      = sigma_anual
)
kable(resumen_opt, digits=4,
      col.names=c("Acción","Peso (w_i)","Monto invertido (USD)","Retorno anual","Vol. anual"),
      caption="Tabla 5. Portafolio óptimo de máximo Sharpe Ratio",
      format.args=list(big.mark=",")) |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE)
Tabla 5. Portafolio óptimo de máximo Sharpe Ratio
Acción Peso (w_i) Monto invertido (USD) Retorno anual Vol. anual
ADBE ADBE 0.1501 3,001,516 0.0387 0.3637
VRTX VRTX 0.4242 8,483,972 0.1305 0.3204
MNST MNST 0.4257 8,514,512 0.1142 0.2681
metricas <- data.frame(
  Metrica = c("Retorno esperado anual","Volatilidad anual","Sharpe Ratio",
              "Retorno mensual equivalente (geométrico)","Volatilidad mensual",
              "Capital total invertido"),
  Valor   = c(fmt_pct(ret_port), fmt_pct(sigma_port), round(sharpe_port,4),
              fmt_pct(ret_port_m), fmt_pct(sigma_port_m),
              paste0("USD ",fmt_usd(capital)))
)
kable(metricas, col.names=c("Métrica","Valor"),
      caption="Tabla 6. Métricas del portafolio óptimo") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE)
Tabla 6. Métricas del portafolio óptimo
Métrica Valor
Retorno esperado anual 10.98%
Volatilidad anual 23.41%
Sharpe Ratio 0.2973
Retorno mensual equivalente (geométrico) 0.87%
Volatilidad mensual 6.76%
Capital total invertido USD 20,000,000.00

Análisis del portafolio óptimo: El modelo de optimización asigna la mayor participación a Vertex Pharmaceuticals (VRTX), lo cual resulta consistente con sus características financieras: menor volatilidad relativa, baja correlación con las demás acciones y una relación retorno-riesgo favorable dentro del universo seleccionado. Adobe y Monster complementan el portafolio aportando exposición a sectores distintos —tecnología y consumo defensivo—, permitiendo reducir el riesgo agregado mediante diversificación. Aunque ninguna acción domina completamente la composición más allá del límite establecido, la asignación refleja una preferencia por estabilidad sin renunciar completamente al potencial de crecimiento. En conjunto, el portafolio alcanza un Ratio de Sharpe superior al de las acciones individuales, indicando una combinación más eficiente entre rentabilidad esperada y riesgo asumido (Markowitz, 1952).

2.5 Justificación Técnica de las Restricciones de Participación

La construcción del portafolio óptimo requiere no solo maximizar el Ratio de Sharpe como función objetivo, sino también establecer restricciones que garanticen que la solución sea financieramente válida, interpretable y aplicable en la práctica institucional. Las restricciones definidas no son arbitrarias: responden a criterios fundamentados en la teoría de optimización de portafolios, la ingeniería financiera y las directrices del docente (Rodríguez, 2026c).

Restricción de suma igual al 100 %. La condición \(\sum_{i=1}^{3} w_i = 1\) garantiza que la totalidad del capital disponible —USD 20,000,000— sea asignada entre las tres acciones sin posiciones de efectivo no invertido ni apalancamiento. Esta restricción es fundamental en el modelo de portafolio largo en activos y asegura coherencia con el mandato del gerente de inversiones (Bodie et al., 2008).

Restricción de participación mínima del 15 %. El límite inferior \(w_i \geq 0.15\) responde a cuatro criterios. Primero, la materialidad financiera: una participación del 15 % sobre USD 20,000,000 implica una inversión mínima de USD 3,000,000 por acción, nivel considerado umbral de posición material para activos de renta variable de alta capitalización (Elton et al., 2014). Segundo, la coherencia con el portafolio equitativo como referencia neutral: el 15 % representa la mitad de la asignación neutral de un portafolio de tres activos en partes iguales (33.3 %), estableciendo el piso por debajo del cual un activo contribuye menos de la mitad de lo que aportaría en condiciones de neutralidad. Tercero, la prevención de soluciones degeneradas: sin este límite, el optimizador puede asignar pesos marginales a uno o más activos, concentrando el portafolio en un solo instrumento, condición que el docente señaló explícitamente como inadmisible (Rodríguez, 2026c). Cuarto, la aplicabilidad práctica: en gestión institucional, los fondos de inversión suelen establecer límites mínimos de entre el 10 % y el 15 % por activo para portafolios de tres a cinco instrumentos (Fabozzi et al., 2007).

Restricción de participación máxima del 60 %. El límite superior \(w_i \leq 0.60\) se deriva del Índice de Herfindahl-Hirschman (IHH), indicador cuantitativo que mide la concentración de un portafolio como \(IHH = \sum w_i^2\) (Fabozzi et al., 2007). Un portafolio perfectamente diversificado con tres activos iguales tiene \(IHH_{equitativo} = 3 \times (1/3)^2 = 0.333\), mientras que el umbral máximo aceptable en práctica institucional es \(IHH \leq 0.50\). Imponiendo esta condición con los otros dos activos en su mínimo del 15 %:

\[w_{max}^2 + 0.15^2 + 0.15^2 \leq 0.50 \implies w_{max}^2 \leq 0.455 \implies w_{max} \leq \sqrt{0.455} \approx 0.674\]

Redondeando conservadoramente hacia abajo al múltiplo del 5 % más cercano, se obtiene el límite de 60 %. Este valor no es arbitrario: es el máximo que mantiene la concentración del portafolio dentro de niveles aceptables institucionalmente, otorgando al optimizador libertad suficiente para asignar el mayor peso al activo con mejor relación retorno-riesgo.

ihh_port <- sum(w_opt^2)
ihh_df   <- data.frame(
  Metrica = c("IHH portafolio equitativo (referencia)",
              "IHH portafolio óptimo obtenido",
              "IHH máximo permitido (umbral institucional)"),
  Valor   = c("0.3333", round(ihh_port, 4), "0.5000"),
  Evaluacion = c("Referencia de máxima diversificación con 3 activos",
                 ifelse(ihh_port <= 0.50,
                        "Concentración controlada — cumple umbral",
                        "Excede umbral — revisar restricciones"),
                 "Límite superior (Fabozzi et al., 2007)")
)
kable(ihh_df,
      col.names = c("Métrica", "Valor IHH", "Evaluación"),
      caption   = "Tabla. Verificación de concentración mediante el Índice de Herfindahl-Hirschman") |>
  kable_styling(bootstrap_options = c("striped","hover"), full_width = TRUE) |>
  column_spec(3, color = c("#4a7fa5","#276749","#4a7fa5"))
Tabla. Verificación de concentración mediante el Índice de Herfindahl-Hirschman
Métrica Valor IHH Evaluación
IHH portafolio equitativo (referencia) 0.3333 Referencia de máxima diversificación con 3 activos
IHH portafolio óptimo obtenido 0.3837 Concentración controlada — cumple umbral
IHH máximo permitido (umbral institucional) 0.5000 Límite superior (Fabozzi et al., 2007)

El hecho de que el modelo asigne a Vertex el peso máximo permitido (60 %) indica que esta acción presenta la combinación más favorable entre retorno esperado y riesgo dentro del conjunto seleccionado. Asimismo, evidencia que la restricción de concentración sí afecta el resultado de optimización, evitando que el portafolio quede excesivamente concentrado en un único activo. En ausencia de este límite, el modelo probablemente habría asignado una participación aún mayor a Vertex, reduciendo el nivel de diversificación del portafolio (Markowitz, 1952).

front_df <- data.frame(Sigma=sigma_sim, Retorno=ret_sim, Sharpe=sharpe_sim)
# Tres puntos especiales para la leyenda manual
puntos_esp <- data.frame(
  x     = c(sigma_port, sigma_sim[idx_minvar]),
  y     = c(ret_port,   ret_sim[idx_minvar]),
  tipo  = c("Máx. Sharpe","Mín. Varianza")
)

ggplot(front_df, aes(x=Sigma, y=Retorno)) +
  geom_point(aes(color=Sharpe), size=0.5, alpha=0.5) +
  scale_color_gradient(
    low  = "#a8d5e2",
    high = "#2d4a6b",
    name = "Sharpe",
    guide = guide_colorbar(
      barwidth    = 8,
      barheight   = 0.55,
      title.position = "left",
      title.hjust = 0.5,
      label.theme = element_text(size=8.5, color="#2d3748"),
      ticks       = FALSE
    )
  ) +
  geom_point(data=puntos_esp, aes(x=x, y=y, shape=tipo),
             color=c("#c53030","#1a2b4a"), size=5) +
  scale_shape_manual(
    name   = NULL,
    values = c("Máx. Sharpe"=18, "Mín. Varianza"=15),
    labels = c(
      paste0("Máx. Sharpe  (SR = ", round(sharpe_port,3), ")"),
      paste0("Mín. Varianza (σ = ", round(sigma_sim[idx_minvar]*100,1), "%)")
    )
  ) +
  scale_x_continuous(labels=label_percent()) +
  scale_y_continuous(labels=label_percent()) +
  labs(
    title    = "Figura 3. Frontera Eficiente — 500.000 portafolios simulados",
    subtitle = "Restricciones: w_i ∈ [15 %, 60 %]  ·  Suma = 100 %  ·  Capital: USD 20,000,000",
    x        = "Volatilidad anual",
    y        = "Retorno esperado anual"
  ) +
  tema_lab +
  theme(
    legend.position  = "bottom",
    legend.box       = "horizontal",
    legend.spacing.x = unit(0.6,"cm"),
    legend.text      = element_text(size=9),
    legend.key.size  = unit(0.45,"cm")
  ) +
  guides(
    color = guide_colorbar(order=1),
    shape = guide_legend(order=2,
                         override.aes=list(color=c("#c53030","#1a2b4a"),
                                           size=4))
  )

La nube de portafolios simulados evidencia el trade-off tradicional entre rentabilidad esperada y riesgo asumido: a medida que aumenta el retorno esperado, también se incrementa la volatilidad del portafolio. El portafolio seleccionado se ubica cercano a la frontera eficiente y corresponde a la combinación que maximiza el Ratio de Sharpe bajo las restricciones de participación impuestas, indicando un equilibrio favorable entre rentabilidad y riesgo ajustado dentro del espacio factible definido.


3 Valor en Riesgo (VaR) del Portafolio

3.1 VaR paramétrico mensual

El VaR paramétrico asume distribución normal: \(\text{VaR}_\alpha = -(\mu_m - z_\alpha \cdot \sigma_m)\).

z99 <- qnorm(0.99); z95 <- qnorm(0.95)
VaR99_pct <- -(ret_port_m - z99*sigma_port_m)
VaR95_pct <- -(ret_port_m - z95*sigma_port_m)
VaR99_usd <- VaR99_pct*capital
VaR95_usd <- VaR95_pct*capital

var_t <- data.frame(
  NC      = c("99 % (VaR 1 %)","95 % (VaR 5 %)"),
  z       = c(round(z99,4),round(z95,4)),
  mu_m    = c(fmt_pct(ret_port_m),fmt_pct(ret_port_m)),
  sigma_m = c(fmt_pct(sigma_port_m),fmt_pct(sigma_port_m)),
  pct     = c(fmt_pct(VaR99_pct),fmt_pct(VaR95_pct)),
  usd     = c(paste0("USD ",fmt_usd(VaR99_usd)),paste0("USD ",fmt_usd(VaR95_usd)))
)
kable(var_t,
      col.names=c("Nivel de Confianza","z","μ mensual","σ mensual","VaR (%)","VaR (USD)"),
      caption="Tabla 7. VaR paramétrico mensual del portafolio") |>
  kable_styling(bootstrap_options=c("striped","hover"))
Tabla 7. VaR paramétrico mensual del portafolio
Nivel de Confianza z μ mensual σ mensual VaR (%) VaR (USD)
99 % (VaR 1 %) 2.3263 0.87% 6.76% 14.85% USD 2,969,995.44
95 % (VaR 5 %) 1.6449 0.87% 6.76% 10.24% USD 2,048,865.04

Interpretación: Con NC del 99 %, en el peor mes esperado de cada 100, el portafolio podría perder hasta 14.85% de su valor, equivalente a USD 2,969,995.44. Con NC del 95 %, la pérdida máxima mensual estimada es 10.24% o USD 2,048,865.04. Estos montos representan la exposición de riesgo que justifica la implementación de la cobertura con futuros: el gerente de inversiones busca que, ante una caída del mercado, la ganancia en la posición corta de futuros compense parcialmente o en gran medida la pérdida asociada al VaR del portafolio, reconociendo que ninguna cobertura elimina completamente el riesgo.

ret_port_hist <- as.matrix(ret[,activos]) %*% w_opt
VaR99h_d <- abs(quantile(ret_port_hist, 0.01))
VaR95h_d <- abs(quantile(ret_port_hist, 0.05))
VaR99h_m <- VaR99h_d*sqrt(21); VaR95h_m <- VaR95h_d*sqrt(21)

kable(data.frame(
  NC=c("99 %","95 %"),
  VaR_d=c(fmt_pct(VaR99h_d),fmt_pct(VaR95h_d)),
  VaR_m=c(fmt_pct(VaR99h_m),fmt_pct(VaR95h_m)),
  USD=c(paste0("USD ",fmt_usd(VaR99h_m*capital)),paste0("USD ",fmt_usd(VaR95h_m*capital)))),
  col.names=c("NC","VaR Diario histórico","VaR Mensual escalado","VaR Mensual (USD)"),
  caption="Tabla 8. VaR histórico del portafolio (simulación histórica)") |>
  kable_styling(bootstrap_options=c("striped","hover"))
Tabla 8. VaR histórico del portafolio (simulación histórica)
NC VaR Diario histórico VaR Mensual escalado VaR Mensual (USD)
99 % 4.12% 18.87% USD 3,773,102.58
95 % 2.29% 10.51% USD 2,101,798.62

Comparación VaR paramétrico vs. VaR histórico: El VaR paramétrico supone que los retornos siguen una distribución aproximadamente normal, lo que puede limitar su capacidad para representar eventos extremos presentes en mercados financieros reales. Por otro lado, el VaR histórico utiliza directamente la distribución empírica observada entre 2018 y 2026, incorporando episodios de alta volatilidad como la caída asociada al COVID-19 en 2020 y la corrección bursátil de 2022. Debido a ello, el VaR histórico suele capturar mejor los comportamientos extremos observados en la muestra, mientras que el paramétrico ofrece una aproximación más simple y consistente para modelación financiera. Para el diseño de la cobertura se empleará el VaR paramétrico al 99 % como referencia principal, manteniendo el VaR histórico como indicador complementario para la evaluación de escenarios de estrés.

ggplot(data.frame(r=ret_port_hist), aes(x=r)) +
  geom_histogram(bins=80, fill="#2c5282", color="white", alpha=0.8) +
  geom_vline(xintercept=-VaR99h_d, color="#c53030", linetype="dashed", linewidth=1) +
  geom_vline(xintercept=-VaR95h_d, color="#dd6b20", linetype="dashed", linewidth=1) +
  annotate("text",x=-VaR99h_d-0.002,y=50,label="VaR 99 %",color="#c53030",angle=90,size=3) +
  annotate("text",x=-VaR95h_d-0.002,y=50,label="VaR 95 %",color="#dd6b20",angle=90,size=3) +
  scale_x_continuous(labels=label_percent()) +
  labs(title="Figura 4. Distribución de retornos diarios del portafolio",
       subtitle="Líneas: VaR histórico al 99 % y 95 %",
       x="Retorno diario", y="Frecuencia") + tema_lab


4 Beta del Portafolio (CAPM)

La beta de cada acción se estima como la pendiente de la regresión CAPM: \[R_i = \alpha_i + \beta_i \, R_m + \varepsilon_i\] donde \(R_m\) es el retorno diario del S&P 500.

beta_ind <- sapply(activos, function(a) as.numeric(coef(lm(ret[[a]]~ret$SP500))[2]))
names(beta_ind) <- activos
beta_port <- sum(w_opt*beta_ind)

# (los resultados se muestran en la tabla beta_tabla a continuación)

beta_t <- data.frame(
  Activo = c(activos,"PORTAFOLIO"),
  Beta   = c(round(beta_ind,4), round(beta_port,4)),
  Peso   = c(paste0(round(w_opt*100,2),"%"),"—"),
  Contrib= c(round(w_opt*beta_ind,4), round(beta_port,4))
)
kable(beta_t, col.names=c("Activo","Beta","Peso","Contribución a β_p"),
      caption="Tabla 9. Betas CAPM y beta del portafolio", align="c") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  row_spec(4, bold=TRUE, background="#f0f0f0")
Tabla 9. Betas CAPM y beta del portafolio
Activo Beta Peso Contribución a β_p
ADBE ADBE 1.2365 15.01% 0.1856
VRTX VRTX 0.7594 42.42% 0.3221
MNST MNST 0.7676 42.57% 0.3268
PORTAFOLIO 0.8345 0.8345

Interpretación: La beta del portafolio estimada de \(\beta_p =\) 0.8345 indica que el portafolio presenta una sensibilidad menor a la del mercado accionario estadounidense. En términos prácticos, un movimiento del 1 % en el S&P 500 se asociaría, en promedio, con un cambio aproximado de 83.45% en el valor del portafolio en la misma dirección. Este resultado es consistente con la elevada participación de Vertex y Monster, cuyas betas individuales son inferiores a uno, reduciendo la exposición sistemática total. Una beta menor a 1 implica menor sensibilidad frente a fluctuaciones del mercado, aspecto relevante para determinar la intensidad de la cobertura mediante futuros.

# Data frame
beta_df2 <- data.frame(
  Accion = factor(activos, levels = activos),
  Beta   = beta_ind
)

# Etiquetas
beta_df2$Label <- paste0("β = ", sprintf("%.3f", beta_df2$Beta))

# Posición dinámica de etiquetas
beta_df2$y_label <- ifelse(
  abs(beta_df2$Beta - beta_port) < 0.08,
  beta_df2$Beta - 0.07,
  beta_df2$Beta + 0.05
)

# Colores
pal_acc <- c(
  "ADBE" = "#1f4e79",
  "VRTX" = "#2f6f4f",
  "MNST" = "#8b3e1f"
)

# Límite eje Y
y_max2 <- max(beta_ind) * 1.45

# Gráfico
ggplot(beta_df2, aes(x = Accion, y = Beta)) +

  # Barras
  geom_col(
    aes(fill = Accion),
    width = 0.52,
    color = "white",
    linewidth = 0.8
  ) +

  # Etiquetas beta
  geom_label(
    aes(y = y_label, label = Label),
    size = 3.8,
    fontface = "bold",
    fill = "white",
    color = "#2d3748",
    label.size = 0.25,
    label.padding = unit(0.18, "lines")
  ) +

  # Línea mercado
  geom_hline(
    yintercept = 1,
    linetype = "longdash",
    color = "#a0aec0",
    linewidth = 0.9
  ) +

  annotate(
    "text",
    x = 0.60,
    y = 1.035,
    label = "β mercado = 1",
    color = "#718096",
    size = 3.2,
    hjust = 0
  ) +

  # Línea beta portafolio
  geom_hline(
    yintercept = beta_port,
    color = "#c53030",
    linewidth = 1.4
  ) +

  # Etiqueta beta portafolio
  annotate(
    "label",
    x = 2,
    y = beta_port + 0.12,
    label = paste0(
      "β portafolio = ",
      sprintf("%.3f", beta_port)
    ),
    color = "#c53030",
    fill = "white",
    fontface = "bold",
    size = 3.8,
    label.size = 0.3
  ) +

  # Colores
  scale_fill_manual(values = pal_acc) +

  # Escala eje Y
  scale_y_continuous(
    limits = c(0, y_max2),
    breaks = seq(0, ceiling(y_max2 * 5) / 5, by = 0.2),
    expand = expansion(mult = c(0, 0.06))
  ) +

  # Títulos
  labs(
    title = "Figura 5. Betas Individuales y Beta del Portafolio",
    subtitle = "Línea roja: β ponderado del portafolio · Línea punteada: β = 1 (mercado)",
    x = NULL,
    y = "Beta (β)",
    caption = expression(
  "Estimación por regresión CAPM: " *
  R[i] == alpha + beta[i] %*% R[m]
)
  ) +

  # Tema general
  theme_minimal(base_size = 12) +

  # Personalización
  theme(
    legend.position = "none",

    axis.text.x = element_text(
      size = 12,
      face = "bold",
      color = "#2d3748"
    ),

    axis.title.y = element_text(
      size = 12,
      face = "bold"
    ),

    plot.title = element_text(
      size = 18,
      face = "bold",
      hjust = 0.5,
      color = "#1a202c"
    ),

    plot.subtitle = element_text(
      size = 11,
      hjust = 0.5,
      color = "#4a5568"
    ),

    plot.caption = element_text(
      size = 9,
      face = "italic",
      color = "#718096"
    ),

    panel.grid.minor = element_blank()
  )


5 Estrategia de Cobertura con Futuros sobre el S&P 500

5.1 Especificaciones del contrato

specs <- data.frame(
  Parametro = c("Activo subyacente","Vencimientos disponibles",
                "Tamaño del contrato","Multiplicador (M)",
                "Precio inicial futuro (30/04/2026)","Valor nocional por contrato",
                "Margen inicial por contrato","Margen de mantenimiento",
                "Mecanismo de liquidación","Ajuste mark-to-market"),
  Valor     = c("S&P 500 Index",
                "Jun-26 (ESM26), Sep-26 (ESU26), Dic-26 (ESZ26), Mar-27 (ESH27)",
                "USD 50 × nivel del índice","50",
                "5.570 puntos (aprox. al 30/04/2026)",
                "USD 278.500 por contrato","USD 12.500 por contrato",
                "USD 11.250 por contrato","Efectivo (cash settlement)",
                "Diario (efectos académicos: mensual)")
)
kable(specs, col.names=c("Parámetro","Valor"),
      caption="Tabla 10. Especificaciones E-mini S&P 500 (Fuente: CME Group, 2026)") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE) |>
  column_spec(1, bold=TRUE, width="40%")
Tabla 10. Especificaciones E-mini S&P 500 (Fuente: CME Group, 2026)
Parámetro Valor
Activo subyacente S&P 500 Index
Vencimientos disponibles Jun-26 (ESM26), Sep-26 (ESU26), Dic-26 (ESZ26), Mar-27 (ESH27)
Tamaño del contrato USD 50 × nivel del índice
Multiplicador (M) 50
Precio inicial futuro (30/04/2026) 5.570 puntos (aprox. al 30/04/2026)
Valor nocional por contrato USD 278.500 por contrato
Margen inicial por contrato USD 12.500 por contrato
Margen de mantenimiento USD 11.250 por contrato
Mecanismo de liquidación Efectivo (cash settlement)
Ajuste mark-to-market Diario (efectos académicos: mensual)

5.2 Número óptimo de contratos

\[N^* = \frac{\beta_P \times V_P}{F_0 \times M}\]

F0          <- 5570; M <- 50; V_port <- 20e6
margen_ini  <- 12500; margen_mant <- 11250

N_raw  <- (beta_port*V_port)/(F0*M)
N_down <- floor(N_raw); N_up <- ceiling(N_raw)
N_star <- N_up

calc_df <- data.frame(
  Elemento = c("Beta del portafolio (β_p)","Valor del portafolio (V_p)",
               "Precio futuro (F_0)","Multiplicador (M)",
               "Valor nocional por contrato (F_0 × M)",
               "N* exacto","N* redondeado hacia abajo (piso)",
               "N* redondeado hacia arriba (techo — ELEGIDO)"),
  Valor    = c(fmt_num(beta_port), paste0("USD ", fmt_usd(V_port)),
               paste0(fmt_usd(F0)," puntos"), as.character(M),
               paste0("USD ", fmt_usd(F0*M)),
               fmt_num(N_raw,4), as.character(N_down),
               as.character(N_up))
)
kable(calc_df, col.names=c("Elemento","Valor"),
      caption="Cálculo del número óptimo de contratos de futuros") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  column_spec(1, bold=TRUE) |>
  row_spec(8, bold=TRUE, background="#d4edda")
Cálculo del número óptimo de contratos de futuros
Elemento Valor
Beta del portafolio (β_p) 0.8345
Valor del portafolio (V_p) USD 20,000,000.00
Precio futuro (F_0) 5,570.00 puntos
Multiplicador (M) 50
Valor nocional por contrato (F_0 × M) USD 278,500.00
N* exacto 59.9266
N* redondeado hacia abajo (piso) 59
N* redondeado hacia arriba (techo — ELEGIDO) 60
dec_t <- data.frame(
  Opcion = c("Piso (subcobertura)","Techo (ELEGIDO)"),
  N = c(N_down,N_up),
  Cob = c(fmt_pct(N_down*F0*M/(beta_port*V_port)),
          fmt_pct(N_up*F0*M/(beta_port*V_port))),
  Margen = c(paste0("USD ",fmt_usd(N_down*margen_ini)),
             paste0("USD ",fmt_usd(N_up*margen_ini)))
)
kable(dec_t, col.names=c("Opción","N° Contratos","Ratio Cobertura","Margen Inicial Total"),
      caption="Tabla 11. Decisión de redondeo del número de contratos") |>
  kable_styling(bootstrap_options=c("striped","hover")) |>
  row_spec(2, bold=TRUE, background="#d4edda")
Tabla 11. Decisión de redondeo del número de contratos
Opción N° Contratos Ratio Cobertura Margen Inicial Total
Piso (subcobertura) 59 98.45% USD 737,500.00
Techo (ELEGIDO) 60 100.12% USD 750,000.00

El número óptimo de contratos se determina aplicando la fórmula de cobertura de mínima varianza (Hull, 2009):

\[N^* = \frac{\beta_P \times V_P}{F_0 \times M}\]

donde \(\beta_P \times V_P\) representa la exposición sistemática total del portafolio en dólares, y \(F_0 \times M\) es el valor nocional de cada contrato de futuros E-mini S&P 500. La división de ambos términos determina cuántos contratos son necesarios para neutralizar exactamente esa exposición sistemática.

Dado que los contratos de futuros solo pueden negociarse en números enteros, el resultado exacto de 59.9266 contratos debe aproximarse. Se opta por redondear hacia arriba, seleccionando 60 contratos, ya que una ligera sobrecobertura resulta más conveniente que dejar parte del riesgo sistemático sin proteger. En términos prácticos, se considera preferible sacrificar una pequeña parte del potencial de ganancia en escenarios alcistas a quedar insuficientemente cubiertos ante una caída relevante del mercado. Además, el margen requerido para el contrato adicional —USD 12,500.00— representa un valor reducido frente al tamaño total del portafolio administrado.


6 Posición en Futuros y Justificación

pos_t <- data.frame(
  Caso     = c("Portafolio largo en acciones (nuestro caso)",
               "Capital pendiente de invertir en acciones","Importador de materias primas"),
  Posicion = c("CORTA en futuros de índice","LARGA en futuros de índice",
               "LARGA en futuros de divisas"),
  Logica   = c("Vender índice a futuro compensa caídas del portafolio",
               "Asegurar precio de compra frente a alzas del índice",
               "Cubrir riesgo de apreciación del dólar")
)
kable(pos_t, col.names=c("Situación","Posición en Futuros","Lógica económica"),
      caption="Tabla 12. Tipo de posición en futuros según objetivo") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE)
Tabla 12. Tipo de posición en futuros según objetivo
Situación Posición en Futuros Lógica económica
Portafolio largo en acciones (nuestro caso) CORTA en futuros de índice Vender índice a futuro compensa caídas del portafolio
Capital pendiente de invertir en acciones LARGA en futuros de índice Asegurar precio de compra frente a alzas del índice
Importador de materias primas LARGA en futuros de divisas Cubrir riesgo de apreciación del dólar

Análisis de escenarios con 60 contratos CORTOS:

Escenario Portafolio acciones Posición corta futuros Efecto neto
Mercado sube 5 % Ganancia ≈ β_p × 5 % × V_p Pérdida en futuros Se limita el upside: costo de la cobertura
Mercado baja 5 % Pérdida ≈ β_p × 5 % × V_p Ganancia en futuros Compensación parcial o significativa de la pérdida
Mercado plano Sin cambio significativo Sin cambio significativo Sin costo neto relevante

Conclusión sobre la posición en futuros: La posición corta en futuros sobre el S&P 500 es la estrategia correcta para un inversionista que ya posee un portafolio de acciones y desea protegerse ante caídas del mercado (Hull, 2009; Rodríguez, 2026b). Al vender contratos futuros sobre el índice, se establece una posición que permite compensar parcialmente las pérdidas del portafolio cuando el mercado accionario cae. En sentido contrario, cuando el mercado sube, la posición corta genera pérdidas que reducen la ganancia total del portafolio —este es el costo de la cobertura. Es importante entender que la cobertura no elimina todo el riesgo: solo cubre el riesgo sistemático (el movimiento correlacionado con el índice, medido por beta). El riesgo idiosincrático de cada empresa —eventos específicos como fracasos regulatorios de Vertex, competencia para Adobe o problemas regulatorios para Monster— permanece presente y no puede eliminarse con futuros sobre un índice general.


7 Simulación: Tres Escenarios del Portafolio y del Futuro

Se simulan tres escenarios: alcista, bajista e intermedio, tanto para el portafolio como para el futuro. La simulación se realiza mediante un Movimiento Geométrico Browniano (GBM) con parámetros ajustados por escenario.

mu_idx    <- anualizar(ret$SP500F)$mu
sigma_idx <- anualizar(ret$SP500F)$sigma
T_total   <- 48; dt <- 1/12

# Parámetros por escenario (mu ajustado, sigma conservada)
escenarios <- list(
  Alcista    = list(mu = mu_idx + 1*sigma_idx, sigma = sigma_idx),
  Intermedio = list(mu = mu_idx,               sigma = sigma_idx),
  Bajista    = list(mu = mu_idx - 1*sigma_idx, sigma = sigma_idx)
)

gbm_df <- data.frame(
  Escenario = c("Alcista","Intermedio (base)","Bajista"),
  Mu_anual    = c(fmt_pct(mu_idx + sigma_idx), fmt_pct(mu_idx), fmt_pct(mu_idx - sigma_idx)),
  Sigma_anual = rep(fmt_pct(sigma_idx), 3),
  Ajuste      = c("μ + 1σ  (percentil ~84 %)","μ base  (percentil ~50 %)","μ − 1σ  (percentil ~16 %)")
)
kable(gbm_df, col.names=c("Escenario","μ anual","σ anual","Ajuste aplicado"),
      caption="Parámetros GBM por escenario de simulación") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  column_spec(1, bold=TRUE,
    color=c("#2ca02c","#1f77b4","#d62728"))
Parámetros GBM por escenario de simulación
Escenario μ anual σ anual Ajuste aplicado
Alcista 32.04% 19.52% μ + 1σ (percentil ~84 %)
Intermedio (base) 12.52% 19.52% μ base (percentil ~50 %)
Bajista -7% 19.52% μ − 1σ (percentil ~16 %)
sim_gbm <- function(S0, mu, sigma, dt, T, seed=42) {
  set.seed(seed)
  path <- numeric(T+1); path[1] <- S0
  for(i in seq_len(T))
    path[i+1] <- path[i]*exp((mu-0.5*sigma^2)*dt + sigma*sqrt(dt)*rnorm(1))
  path
}

fechas_sim <- seq(as.Date("2026-04-30"), by="month", length.out=T_total+1)

# Simular futuro en 3 escenarios
fut_paths <- lapply(names(escenarios), function(nm) {
  e <- escenarios[[nm]]
  path <- sim_gbm(F0, e$mu, e$sigma, dt, T_total, seed=switch(nm,Alcista=1,Intermedio=42,Bajista=99))
  data.frame(Fecha=fechas_sim, Precio=path, Escenario=nm)
}) |> bind_rows()

# Simular portafolio en 3 escenarios (usando retorno del portafolio ajustado)
mu_port_hist <- ret_port
port_paths <- lapply(names(escenarios), function(nm) {
  e <- escenarios[[nm]]
  # Ajuste proporcional al portafolio usando beta
  mu_adj <- mu_port_hist + beta_port*(e$mu - mu_idx)
  path <- sim_gbm(capital, mu_adj, sigma_port, dt, T_total,
                  seed=switch(nm,Alcista=11,Intermedio=42,Bajista=99))
  data.frame(Fecha=fechas_sim, Valor=path/1e6, Escenario=nm)
}) |> bind_rows()

# Guardar trayectoria intermedia para análisis posterior
F_path <- sim_gbm(F0, mu_idx, sigma_idx, dt, T_total, seed=42)
colores_esc <- pal_esc

p1 <- ggplot(fut_paths, aes(x=Fecha, y=Precio, color=Escenario)) +
  geom_line(linewidth=1) +
  geom_hline(yintercept=F0, linetype="dashed", color="gray50") +
  scale_color_manual(values=colores_esc) +
  scale_y_continuous(labels=label_comma()) +
  labs(title="Futuro E-mini S&P 500", x=NULL, y="Precio (puntos)") +
  tema_lab + theme(legend.position="top")

p2 <- ggplot(port_paths, aes(x=Fecha, y=Valor, color=Escenario)) +
  geom_line(linewidth=1) +
  geom_hline(yintercept=capital/1e6, linetype="dashed", color="gray50") +
  scale_color_manual(values=colores_esc) +
  scale_y_continuous(labels=label_dollar(suffix="M", scale=1)) +
  labs(title="Valor del portafolio accionario", x=NULL, y="Valor (USD millones)") +
  tema_lab + theme(legend.position="top")

p1 + p2 + plot_annotation(
  title="Figura 6. Simulación GBM: tres escenarios (48 meses)",
  subtitle="Alcista: μ + 1σ (p84)  ·  Intermedio: μ base (p50)  ·  Bajista: μ − 1σ (p16)")

Lectura de los escenarios: En el escenario alcista, el portafolio alcanzaría un valor aproximado de 19,174,789.46 USD a 4 años; en el intermedio, 24,278,435.38 USD; y en el bajista, 5,580,311.65 USD. Esto ilustra la dispersión de resultados posibles que justifica la implementación de la cobertura con futuros.


8 Evaluación de Flujos y Llamados al Margen

8.1 Construcción de los flujos mensuales (escenario intermedio)

precio_ini_vec <- F_path[-length(F_path)]
precio_fin_vec <- F_path[-1]
delta_F        <- precio_fin_vec - precio_ini_vec
pnl_corto      <- -delta_F*M*N_star
pnl_largo      <-  delta_F*M*N_star

margen_total_ini <- N_star*margen_ini
cuenta_margen    <- numeric(T_total+1); cuenta_margen[1] <- margen_total_ini
llamado_margen   <- numeric(T_total)

for(i in seq_len(T_total)) {
  cuenta_margen[i+1] <- cuenta_margen[i] + pnl_corto[i]
  if(cuenta_margen[i+1] < N_star*margen_mant) {
    rep                 <- margen_total_ini - cuenta_margen[i+1]
    llamado_margen[i]   <- rep
    cuenta_margen[i+1]  <- margen_total_ini
  }
}

n_show  <- min(12, T_total)
fl_df   <- data.frame(
  Mes   = seq_len(n_show),
  Fecha = format(fechas_sim[seq_len(n_show)+1], "%b-%y"),
  F_ini = round(precio_ini_vec[seq_len(n_show)], 2),
  F_fin = round(precio_fin_vec[seq_len(n_show)], 2),
  DeltaF= round(delta_F[seq_len(n_show)], 2),
  PnL_C = round(pnl_corto[seq_len(n_show)], 2),
  PnL_L = round(pnl_largo[seq_len(n_show)], 2),
  Saldo = round(cuenta_margen[seq_len(n_show)+1], 2),
  Llamado=round(llamado_margen[seq_len(n_show)], 2)
)

kable(fl_df,
      col.names=c("Mes","Fecha","F inicio","F fin","ΔF",
                  "P&L Corto","P&L Largo","Saldo Margen","Llamado al Margen"),
      caption="Tabla 13. Flujos mensuales – Primer año (escenario intermedio)",
      format.args=list(big.mark=",")) |>
  kable_styling(bootstrap_options=c("striped","hover","condensed"),
                full_width=TRUE, font_size=11) |>
  column_spec(9, color=ifelse(fl_df$Llamado>0,"red","black"),
              bold=ifelse(fl_df$Llamado>0,TRUE,FALSE))
Tabla 13. Flujos mensuales – Primer año (escenario intermedio)
Mes Fecha F inicio F fin ΔF P&L Corto P&L Largo Saldo Margen Llamado al Margen
1 may.-26 5,570.00 6,070.88 500.88 -1,502,640.8 1,502,640.8 750,000.0 1,502,640.8
2 jun.-26 6,070.88 5,932.98 -137.90 413,692.9 -413,692.9 1,163,692.9 0.0
3 jul.-26 5,932.98 6,109.46 176.48 -529,438.5 529,438.5 750,000.0 115,745.6
4 ago.-26 6,109.46 6,387.55 278.09 -834,276.5 834,276.5 750,000.0 834,276.5
5 sept.-26 6,387.55 6,592.82 205.27 -615,805.5 615,805.5 750,000.0 615,805.5
6 oct.-26 6,592.82 6,611.75 18.93 -56,779.2 56,779.2 693,220.8 0.0
7 nov.-26 6,611.75 7,263.62 651.87 -1,955,612.9 1,955,612.9 750,000.0 2,012,392.1
8 dic.-26 7,263.62 7,289.18 25.56 -76,681.3 76,681.3 750,000.0 76,681.3
9 ene.-27 7,289.18 8,239.90 950.72 -2,852,153.0 2,852,153.0 750,000.0 2,852,153.0
10 mar.-27 8,239.90 8,283.79 43.90 -131,686.9 131,686.9 750,000.0 131,686.9
11 mar.-27 8,283.79 8,995.15 711.35 -2,134,057.7 2,134,057.7 750,000.0 2,134,057.7
12 abr.-27 8,995.15 10,323.24 1,328.10 -3,984,285.0 3,984,285.0 750,000.0 3,984,285.0

Lectura de la tabla de flujos: Cada fila representa un mes de la estrategia. La columna ΔF muestra la variación en puntos del futuro: cuando es negativa (mercado cae), la posición corta genera una ganancia que aparece en P&L Corto con signo positivo, compensando la pérdida en el portafolio de acciones. Cuando el futuro sube (ΔF positivo), la posición corta pierde, lo que refleja el costo de la cobertura en mercados alcistas. El Saldo de margen se actualiza mensualmente con las ganancias o pérdidas realizadas. Cuando el saldo cae por debajo del margen de mantenimiento (USD 11,250 por contrato), se genera un llamado al margen marcado en rojo, que obliga a reponer el saldo al nivel del margen inicial. Estos llamados representan salidas de caja adicionales que el administrador debe tener disponibles y constituyen el riesgo de liquidez de la estrategia de cobertura. En escenarios de alta volatilidad, múltiples llamados al margen podrían exigir liquidez adicional significativa aun cuando la cobertura resulte efectiva desde el punto de vista económico.

8.2 Resumen trimestral (48 meses completos)

# Agregar flujos por trimestre
trim_idx <- cut(seq_len(T_total),
                breaks=seq(0, T_total, by=3), labels=paste0("T",1:16))

# Índices de inicio y fin de cada trimestre en la trayectoria de precios
idx_ini_trim <- seq(1,    T_total, by=3)
idx_fin_trim <- seq(3,    T_total, by=3) + 1   # +1 porque F_path tiene T_total+1 elementos

# Valor del portafolio sin cobertura al cierre de cada trimestre
# Usando la trayectoria simulada del portafolio (escenario intermedio)
port_interm <- filter(port_paths, Escenario == "Intermedio")
V_port_trim  <- port_interm$Valor[idx_fin_trim] * 1e6   # en USD

# Valor del portafolio CON cobertura = valor sin cobertura + P&L acumulado de futuros
PnL_trim_vec   <- as.numeric(tapply(pnl_corto, trim_idx, sum))
PnL_acum_vec   <- cumsum(PnL_trim_vec)
V_cob_trim     <- V_port_trim + PnL_acum_vec

trim_df <- data.frame(
  Trimestre     = paste0("T", seq_len(T_total/3)),
  Fecha_ini     = format(fechas_sim[idx_ini_trim], "%b-%Y"),
  Fecha_fin     = format(fechas_sim[idx_fin_trim],  "%b-%Y"),
  V_sin_cob     = round(V_port_trim, 2),          # "Plata" sin cobertura
  PnL_futuros   = round(PnL_trim_vec, 2),          # Resultado del futuro ese trimestre
  V_con_cob     = round(V_cob_trim, 2),            # "Plata" con cobertura
  Llamados      = round(as.numeric(tapply(llamado_margen, trim_idx, sum)), 2),
  PnL_acum      = round(PnL_acum_vec, 2)
)

kable(trim_df,
      col.names=c("Trimestre","Fecha inicio","Fecha fin",
                  "Portafolio sin cobertura (USD)",
                  "P&L Futuros trimestre (USD)",
                  "Portafolio con cobertura (USD)",
                  "Llamados al margen (USD)",
                  "P&L Futuros acumulado (USD)"),
      caption="Tabla 14. Resumen trimestral: valor del portafolio y cobertura – 48 meses (escenario intermedio)",
      format.args=list(big.mark=",")) |>
  kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
  column_spec(5, color=ifelse(trim_df$PnL_futuros < 0, "red", "darkgreen"), bold=TRUE) |>
  column_spec(6, bold=TRUE, background="#d4edda")
Tabla 14. Resumen trimestral: valor del portafolio y cobertura – 48 meses (escenario intermedio)
Trimestre Fecha inicio Fecha fin Portafolio sin cobertura (USD) P&L Futuros trimestre (USD) Portafolio con cobertura (USD) Llamados al margen (USD) P&L Futuros acumulado (USD)
T1 abr.-2026 jul.-2026 22,095,150 -1,618,386.4 20,476,764 1,618,386 -1,618,386
T2 jul.-2026 oct.-2026 24,019,686 -1,506,861.2 20,894,439 1,450,082 -3,125,248
T3 oct.-2026 ene.-2027 30,927,099 -4,884,447.3 22,917,404 4,941,226 -8,009,695
T4 ene.-2027 abr.-2027 40,073,357 -6,250,029.6 25,813,632 6,250,030 -14,259,724
T5 abr.-2027 jul.-2027 36,219,430 2,236,406.4 24,196,112 0 -12,023,318
T6 jul.-2027 oct.-2027 31,640,342 2,821,131.4 22,438,155 0 -9,202,187
T7 oct.-2027 ene.-2028 29,329,419 1,359,127.9 21,486,360 0 -7,843,059
T8 ene.-2028 abr.-2028 28,482,082 367,468.5 21,006,491 0 -7,475,590
T9 abr.-2028 jul.-2028 31,546,846 -2,399,377.8 21,671,878 0 -9,874,968
T10 jul.-2028 oct.-2028 28,240,440 2,116,490.8 20,481,962 0 -7,758,477
T11 oct.-2028 ene.-2029 33,438,897 -3,967,362.7 21,713,057 0 -11,725,840
T12 ene.-2029 abr.-2029 30,182,176 2,083,160.6 20,539,497 0 -9,642,679
T13 abr.-2029 jul.-2029 23,433,607 4,813,021.4 18,603,949 0 -4,829,658
T14 jul.-2029 oct.-2029 23,729,759 -431,600.1 18,468,501 0 -5,261,258
T15 oct.-2029 ene.-2030 22,131,056 1,046,359.7 17,916,157 0 -4,214,898
T16 ene.-2030 abr.-2030 24,278,435 -1,892,656.9 18,170,880 0 -6,107,555

Riesgo base (basis risk): Aun cuando la cobertura reduce de forma importante la exposición al riesgo sistemático, no elimina completamente las fluctuaciones del portafolio debido al denominado riesgo base, originado por diferencias entre el comportamiento del portafolio accionario y el índice S&P 500 utilizado como subyacente de los futuros. Dado que las acciones seleccionadas no replican perfectamente el índice, pueden presentarse diferencias entre la pérdida de las acciones y la ganancia de los contratos futuros, especialmente en períodos de alta dispersión sectorial.

Análisis del resumen trimestral: La tabla anterior presenta la visión: “plata y cobertura, plata y cobertura” cada trimestre. La columna Portafolio sin cobertura muestra el valor simulado de las acciones en cada trimestre bajo el escenario intermedio. La columna P&L Futuros muestra si la posición corta generó ganancia (mercado bajó) o pérdida (mercado subió) en ese trimestre. La columna Portafolio con cobertura —resaltada en verde— es el resultado neto: valor de las acciones más el resultado acumulado de los futuros. En trimestres donde el mercado cae, la cobertura incrementa el valor del portafolio cubierto respecto al no cubierto. En trimestres alcistas, la cobertura reduce el valor final pero protege ante reversiones futuras. La diferencia promedio entre las dos columnas de portafolio es el costo neto de la cobertura a lo largo del horizonte de inversión.

# Base de datos
margen_df <- data.frame(
  Mes    = 0:T_total,
  Saldo  = cuenta_margen
)

# Líneas de referencia
y_ini  <- margen_total_ini
y_mant <- N_star * margen_mant

# Etiquetas
lbl_ini <- paste0(
  "Margen inicial: USD ",
  formatC(y_ini, format = "f", digits = 0, big.mark = ",")
)

lbl_mant <- paste0(
  "Margen mantenimiento: USD ",
  formatC(y_mant, format = "f", digits = 0, big.mark = ",")
)

# Máximo del saldo
y_max <- max(cuenta_margen)

# Gráfico
ggplot(margen_df, aes(x = Mes, y = Saldo)) +

  # Área de evolución
  geom_area(
    fill  = "#dbeafe",
    alpha = 0.35
  ) +

  # Línea principal
  geom_line(
    color     = "#2c5282",
    linewidth = 1.1
  ) +

  # Línea margen inicial
  geom_hline(
    yintercept = y_ini,
    color      = "#276749",
    linewidth  = 1
  ) +

  # Línea margen mantenimiento
  geom_hline(
    yintercept = y_mant,
    color      = "#c53030",
    linetype   = "dashed",
    linewidth  = 1
  ) +

  # Etiqueta margen inicial
  annotate(
    "label",
    x          = 38,
    y          = y_max * 0.18,
    label      = lbl_ini,
    color      = "#276749",
    fill       = "white",
    fontface   = "bold",
    size       = 3.1,
    hjust      = 0,
    label.size = 0.25
  ) +

  # Línea guía margen inicial
  geom_segment(
    aes(
      x    = 36,
      xend = 37.5,
      y    = y_ini,
      yend = y_max * 0.165
    ),
    color     = "#276749",
    linewidth = 0.7
  ) +

  # Etiqueta margen mantenimiento
  annotate(
    "label",
    x          = 38,
    y          = y_max * 0.10,
    label      = lbl_mant,
    color      = "#c53030",
    fill       = "white",
    fontface   = "bold",
    size       = 3.1,
    hjust      = 0,
    label.size = 0.25
  ) +

  # Línea guía margen mantenimiento
  geom_segment(
    aes(
      x    = 36,
      xend = 37.5,
      y    = y_mant,
      yend = y_max * 0.09
    ),
    color     = "#c53030",
    linewidth = 0.7,
    linetype  = "dashed"
  ) +

  # Escalas
  scale_y_continuous(
    labels = label_dollar(
      scale    = 1e-6,
      suffix   = " M",
      accuracy = 0.1
    ),
    expand = expansion(mult = c(0.03, 0.08))
  ) +

  scale_x_continuous(
    breaks = seq(0, 48, by = 6)
  ) +

  # Títulos
  labs(
    title = "Figura 7. Saldo de la cuenta de margen — Posición corta (48 meses)",

    subtitle = paste0(
      N_star,
      " contratos E-mini S&P 500 · Liquidación mensual"
    ),

    x = "Mes",

    y = "Saldo (USD millones)",

    caption = paste(
      "Área azul: evolución del saldo",
      "| Verde: margen inicial",
      "| Rojo punteado: umbral de mantenimiento"
    )
  ) +

  # Tema
  theme_minimal(base_size = 12) +

  theme(
    plot.title = element_text(
      size  = 16,
      face  = "bold",
      hjust = 0.5,
      color = "#1a202c"
    ),

    plot.subtitle = element_text(
      size  = 11,
      hjust = 0.5,
      color = "#4a5568"
    ),

    axis.title = element_text(
      face  = "bold",
      color = "#2d3748"
    ),

    axis.text = element_text(
      color = "#4a5568"
    ),

    plot.caption = element_text(
      size  = 9,
      face  = "italic",
      color = "#718096"
    ),

    panel.grid.minor = element_blank()
  )

res_margen <- data.frame(
  Concepto = c("Total llamados al margen (48 meses)",
               "Monto total repuesto al margen",
               "P&L total posición corta (48 meses)",
               "Margen inicial total depositado"),
  Valor    = c(as.character(sum(llamado_margen>0)),
               paste0("USD ", fmt_usd(sum(llamado_margen))),
               paste0("USD ", fmt_usd(sum(pnl_corto))),
               paste0("USD ", fmt_usd(margen_total_ini)))
)
kable(res_margen, col.names=c("Concepto","Valor"),
      caption="Resumen de la cuenta de margen — posición corta (48 meses)") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  column_spec(1, bold=TRUE)
Resumen de la cuenta de margen — posición corta (48 meses)
Concepto Valor
Total llamados al margen (48 meses) 10
Monto total repuesto al margen USD 14,259,724.45
P&L total posición corta (48 meses) USD -6,107,555.34
Margen inicial total depositado USD 750,000.00

9 Estrategia de Roll-Over Trimestral

9.1 Mecánica y cálculo

roll_meses    <- seq(3, T_total, by=3)
base_roll_pct <- 0.0015  # 0.15 % por roll (contango promedio E-mini)
idx_roll      <- pmin(roll_meses+1, length(F_path))

roll_df <- data.frame(
  Trimestre  = seq_along(roll_meses),
  Mes        = roll_meses,
  Fecha      = format(fechas_sim[idx_roll], "%b-%Y"),
  F_cierre   = round(F_path[idx_roll], 2),
  F_apertura = round(F_path[idx_roll]*(1+base_roll_pct), 2),
  Base_pts   = round(F_path[idx_roll]*base_roll_pct, 2),
  PnL_Roll   = round(-F_path[idx_roll]*base_roll_pct*M*N_star, 2)
)
roll_df$PnL_acum <- cumsum(roll_df$PnL_Roll)

kable(roll_df,
      col.names=c("Trimestre","Mes","Fecha Roll","F Cierre","F Apertura",
                  "Base (puntos)","P&L Roll (USD)","P&L Acumulado"),
      caption="Tabla 15. Ganancias/pérdidas por roll-over trimestral (posición corta)",
      format.args=list(big.mark=",")) |>
  kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
  column_spec(7, color=ifelse(roll_df$PnL_Roll<0,"red","darkgreen"))
Tabla 15. Ganancias/pérdidas por roll-over trimestral (posición corta)
Trimestre Mes Fecha Roll F Cierre F Apertura Base (puntos) P&L Roll (USD) P&L Acumulado
1 3 jul.-2026 6,109.46 6,118.63 9.16 -27,492.58 -27,492.58
2 6 oct.-2026 6,611.75 6,621.67 9.92 -29,752.87 -57,245.45
3 9 ene.-2027 8,239.90 8,252.26 12.36 -37,079.54 -94,324.99
4 12 abr.-2027 10,323.24 10,338.73 15.48 -46,454.59 -140,779.58
5 15 jul.-2027 9,577.77 9,592.14 14.37 -43,099.98 -183,879.56
6 18 oct.-2027 8,637.40 8,650.35 12.96 -38,868.28 -222,747.84
7 21 ene.-2028 8,184.35 8,196.63 12.28 -36,829.59 -259,577.43
8 24 abr.-2028 8,061.86 8,073.96 12.09 -36,278.39 -295,855.82
9 27 jul.-2028 8,861.66 8,874.95 13.29 -39,877.45 -335,733.27
10 30 oct.-2028 8,156.16 8,168.39 12.23 -36,702.72 -372,435.99
11 33 ene.-2029 9,478.61 9,492.83 14.22 -42,653.76 -415,089.75
12 36 abr.-2029 8,784.23 8,797.40 13.18 -39,529.02 -454,618.77
13 39 jul.-2029 7,179.89 7,190.66 10.77 -32,309.49 -486,928.26
14 42 oct.-2029 7,323.75 7,334.74 10.99 -32,956.89 -519,885.15
15 45 ene.-2030 6,974.97 6,985.43 10.46 -31,387.35 -551,272.50
16 48 abr.-2030 7,605.85 7,617.26 11.41 -34,226.33 -585,498.83
ggplot(roll_df, aes(x=Trimestre, y=PnL_acum)) +
  geom_col(fill=ifelse(roll_df$PnL_Roll<0,"#c53030","#276749"), alpha=0.8) +
  geom_line(aes(y=PnL_acum), color="#1a2b4a", linewidth=1.2, linetype="solid") +
  geom_point(aes(y=PnL_acum), color="#1a2b4a", size=2.5) +
  scale_y_continuous(labels=label_comma()) +
  labs(title="Figura 8. P&L acumulado del roll-over trimestral (posición corta)",
       subtitle=paste0("Costo total 4 años: USD ",fmt_usd(sum(roll_df$PnL_Roll))),
       x="Trimestre", y="P&L acumulado (USD)") + tema_lab

total_roll <- sum(roll_df$PnL_Roll)
roll_res <- data.frame(
  Concepto = c("Costo total roll-over (4 años, 16 rolls)",
               "Costo promedio por trimestre",
               "Como porcentaje del capital"),
  Valor    = c(paste0("USD ", fmt_usd(total_roll)),
               paste0("USD ", fmt_usd(mean(roll_df$PnL_Roll))),
               fmt_pct(abs(total_roll)/capital))
)
kable(roll_res, col.names=c("Concepto","Valor"),
      caption="Resumen del costo de roll-over trimestral") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  column_spec(1, bold=TRUE)
Resumen del costo de roll-over trimestral
Concepto Valor
Costo total roll-over (4 años, 16 rolls) USD -585,498.83
Costo promedio por trimestre USD -36,593.68
Como porcentaje del capital 2.93%
comp_t <- data.frame(
  Estrategia = c("Siempre CORTA","Siempre LARGA"),
  Cuando     = c("Portafolio comprado; protege caídas del índice",
                 "Capital por invertir; protege alzas del índice"),
  Cubre      = c("Riesgo bajista sistemático","Riesgo alcista de oportunidad"),
  Roll_contango = c("Pierde en el roll (costo para el corto)",
                    "Gana en el roll (beneficio para el largo)"),
  Roll_backwd   = c("Gana en el roll","Pierde en el roll")
)
kable(comp_t,
      col.names=c("Estrategia","¿Cuándo aplica?","Riesgo cubierto",
                  "Roll en Contango","Roll en Backwardation"),
      caption="Tabla 16. Comparación estrategia siempre-corta vs siempre-larga") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE)
Tabla 16. Comparación estrategia siempre-corta vs siempre-larga
Estrategia ¿Cuándo aplica? Riesgo cubierto Roll en Contango Roll en Backwardation
Siempre CORTA Portafolio comprado; protege caídas del índice Riesgo bajista sistemático Pierde en el roll (costo para el corto) Gana en el roll
Siempre LARGA Capital por invertir; protege alzas del índice Riesgo alcista de oportunidad Gana en el roll (beneficio para el largo) Pierde en el roll

Análisis del roll-over y riesgo de base: El riesgo de base surge porque el precio del contrato que se cierra y el del nuevo contrato no son idénticos en el momento del roll (Hull, 2009). Esta diferencia —denominada base— tiene dos componentes: (1) la diferencia entre precios de contratos de distinto vencimiento, y (2) la posible discrepancia entre el índice subyacente del futuro y la composición real del portafolio. El E-mini S&P 500 típicamente cotiza en contango (futuros lejanos > spot), lo que implica que al cerrar el contrato próximo y abrir el siguiente a un precio mayor, la posición corta incurre en un costo. A lo largo de 16 rolls trimestrales, este costo asciende a USD 585,498.83 o 2.93% del capital, lo que erosiona la rentabilidad efectiva de la cobertura. Si el inversionista mantuviera siempre posición larga, el roll en contango generaría un ingreso en lugar de un costo, pero esa posición no protegería el portafolio ante caídas —sería una apuesta alcista, no una cobertura. Por ello, la decisión de mantener posición corta es la alternativa más coherente con el objetivo de protección del portafolio, aceptando el costo del roll como precio por la protección.


10 Valor Esperado de la Cobertura Trimestral

10.1 Tasa libre de riesgo

rf_tabla <- data.frame(
  Concepto = c("Instrumento","Fecha de consulta","Tasa anual efectiva (EA)",
               "Tasa mensual equivalente","Tasa trimestral equivalente","Justificación"),
  Valor    = c("^TNX – CBOE Interest Rate 3-5 Year Treasury",
               "30 de abril de 2026",
               paste0(fmt_pct(Rf_anual)),
               paste0(fmt_pct(Rf_mensual)),
               paste0(fmt_pct(Rf_trim)),
               "Tasa sin riesgo EE.UU. para CAPM y valoración de derivados (Federal Reserve/CBOE, 2026)")
)
kable(rf_tabla, col.names=c("Concepto","Valor"),
      caption="Tabla 17. Tasa libre de riesgo aplicada") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE) |>
  column_spec(1, bold=TRUE)
Tabla 17. Tasa libre de riesgo aplicada
Concepto Valor
Instrumento ^TNX – CBOE Interest Rate 3-5 Year Treasury
Fecha de consulta 30 de abril de 2026
Tasa anual efectiva (EA) 4.02%
Tasa mensual equivalente 0.33%
Tasa trimestral equivalente 0.99%
Justificación Tasa sin riesgo EE.UU. para CAPM y valoración de derivados (Federal Reserve/CBOE, 2026)

10.2 Valor esperado a 4 años bajo tres enfoques

# ── Retorno esperado por CAPM ─────────────────────────────────────────────────
# E[R_p] = Rf + β_p × (E[R_m] - Rf)
# E[R_m]: retorno esperado del mercado (S&P 500), calculado con datos históricos
mu_mercado    <- anualizar(ret$SP500)$mu        # retorno anual esperado del índice
ret_capm      <- Rf_anual + beta_port * (mu_mercado - Rf_anual)
prima_riesgo  <- mu_mercado - Rf_anual          # prima de riesgo de mercado

capm_df <- data.frame(
  Componente = c("E[R_m] — Retorno esperado S&P 500",
                 "R_f — Tasa libre de riesgo",
                 "Prima de riesgo de mercado (ERP = E[R_m] − R_f)",
                 "β_p — Beta del portafolio",
                 "β_p × ERP — Contribución sistemática",
                 "E[R_p] CAPM = R_f + β_p × ERP",
                 "E[R_p] histórico (optimización)"),
  Valor      = c(fmt_pct(mu_mercado), fmt_pct(Rf_anual),
                 fmt_pct(prima_riesgo), fmt_num(beta_port),
                 fmt_pct(beta_port*prima_riesgo),
                 fmt_pct(ret_capm), fmt_pct(ret_port))
)
kable(capm_df, col.names=c("Componente","Valor"),
      caption="Descomposición del retorno esperado del portafolio por CAPM") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  column_spec(1, bold=TRUE) |>
  row_spec(6, bold=TRUE, background="#d4edda")
Descomposición del retorno esperado del portafolio por CAPM
Componente Valor
E[R_m] — Retorno esperado S&P 500 12.45%
R_f — Tasa libre de riesgo 4.02%
Prima de riesgo de mercado (ERP = E[R_m] − R_f) 8.43%
β_p — Beta del portafolio 0.8345
β_p × ERP — Contribución sistemática 7.03%
E[R_p] CAPM = R_f + β_p × ERP 11.05%
E[R_p] histórico (optimización) 10.98%
# Valor esperado a 4 años usando retorno CAPM
V_sin  <- capital * (1 + ret_capm)^4           # sin cobertura → retorno CAPM
V_con  <- capital * (1 + Rf_anual)^4           # con cobertura → retorno aproximado a Rf
V_var99<- V_sin - VaR99_usd * sqrt(48)
V_var95<- V_sin - VaR95_usd * sqrt(48)

# Retorno mensual basado en CAPM
ret_capm_m <- (1 + ret_capm)^(1/12) - 1

horiz_df <- data.frame(
  Enfoque  = c("Sin cobertura – retorno CAPM",
               "Con cobertura por futuros – retorno aprox. Rf",
               "Escenario VaR 99 % (estrés extremo)",
               "Escenario VaR 95 % (estrés moderado)"),
  Ret      = c(fmt_pct(ret_capm), fmt_pct(Rf_anual),
               fmt_pct(ret_capm - VaR99_pct*sqrt(12)),
               fmt_pct(ret_capm - VaR95_pct*sqrt(12))),
  V_4y     = c(paste0("USD ", fmt_usd(V_sin)),   paste0("USD ", fmt_usd(V_con)),
               paste0("USD ", fmt_usd(V_var99)),  paste0("USD ", fmt_usd(V_var95))),
  Gan      = c(paste0("USD ", fmt_usd(V_sin  - capital)),
               paste0("USD ", fmt_usd(V_con  - capital)),
               paste0("USD ", fmt_usd(V_var99- capital)),
               paste0("USD ", fmt_usd(V_var95- capital)))
)
kable(horiz_df,
      col.names=c("Enfoque","Retorno anual esperado","Valor esperado (4 años)","Ganancia/Pérdida"),
      caption="Tabla 18. Valor esperado del portafolio a 4 años (retorno CAPM vs Rf)") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE) |>
  row_spec(1, background="#fff3cd") |> row_spec(2, background="#d4edda") |>
  row_spec(3:4, background="#f8d7da")
Tabla 18. Valor esperado del portafolio a 4 años (retorno CAPM vs Rf)
Enfoque Retorno anual esperado Valor esperado (4 años) Ganancia/Pérdida
Sin cobertura – retorno CAPM 11.05% USD 30,418,970.22 USD 10,418,970.22
Con cobertura por futuros – retorno aprox. Rf 4.02% USD 23,415,174.22 USD 3,415,174.22
Escenario VaR 99 % (estrés extremo) -40.39% USD 9,842,238.19 USD -10,157,761.81
Escenario VaR 95 % (estrés moderado) -24.43% USD 16,224,016.85 USD -3,775,983.15

Nota. Para los escenarios de VaR se escaló el VaR mensual mediante la regla de raíz del tiempo, reconociendo que esta aproximación supone independencia temporal de los retornos y puede simplificar dinámicas de acumulación de riesgo en horizontes extensos.

Interpretación del valor esperado con cobertura: El retorno esperado del portafolio calculado mediante el CAPM corresponde a la compensación por el riesgo sistemático asumido: \(E[R_p] = R_f + \beta_p \times (E[R_m] - R_f) =\) 4.02% + 0.8345 × (12.45% − 4.02%) = 11.05% anual. La cobertura con futuros reduce significativamente dicha exposición al mercado, por lo que el retorno esperado del portafolio cubierto tiende a aproximarse a la tasa libre de riesgo, aunque no necesariamente coincidir con ella, debido a la persistencia de riesgo idiosincrático, costos de roll-over y riesgo base. La diferencia entre el retorno sin cobertura (11.05%) y el retorno aproximado bajo cobertura (4.02%) —equivalente a 7.03% anual— representa el costo económico asociado a reducir la exposición a fluctuaciones adversas del mercado. A 4 años, el portafolio cubierto generaría aproximadamente USD 23,415,174.22 frente a USD 30,418,970.22 sin cobertura.


11 Rendimiento Esperado Mensual, Dividendos y Proyección

11.1 Retorno mensual y valor esperado comparativo

meses_proy   <- 1:48
# Se usa retorno CAPM mensual equivalente para consistencia con la sección anterior
V_sin_m      <- capital*(1+ret_capm_m)^meses_proy
V_con_m      <- capital*(1+Rf_mensual)^meses_proy
V_var_m      <- capital*(1+ret_capm_m)^meses_proy - VaR99_usd*sqrt(meses_proy)

rend_df <- data.frame(
  Metrica = c("Retorno mensual esperado (CAPM, equiv. geométrico)",
              "Volatilidad mensual",
              "Valor esperado al término del mes 1"),
  Valor   = c(fmt_pct(ret_capm_m), fmt_pct(sigma_port_m),
              paste0("USD ", fmt_usd(capital*(1+ret_capm_m))))
)
kable(rend_df, col.names=c("Métrica","Valor"),
      caption="Rendimiento mensual esperado del portafolio") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=FALSE) |>
  column_spec(1, bold=TRUE)
Rendimiento mensual esperado del portafolio
Métrica Valor
Retorno mensual esperado (CAPM, equiv. geométrico) 0.88%
Volatilidad mensual 6.76%
Valor esperado al término del mes 1 USD 20,175,487.99
# Tabla comparativa meses clave
meses_key <- c(1,3,6,12,24,36,48)
tab_proy  <- data.frame(
  Mes         = meses_key,
  Sin_cob     = paste0("USD ",fmt_usd(V_sin_m[meses_key])),
  Con_cob     = paste0("USD ",fmt_usd(V_con_m[meses_key])),
  VaR_ajust   = paste0("USD ",fmt_usd(pmax(V_var_m[meses_key],0)))
)
kable(tab_proy,
      col.names=c("Mes","Sin cobertura","Con cobertura (Rf)","Ajustado VaR 99 %"),
      caption="Tabla 19. Valor esperado mensual del portafolio bajo tres enfoques") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE)
Tabla 19. Valor esperado mensual del portafolio bajo tres enfoques
Mes Sin cobertura Con cobertura (Rf) Ajustado VaR 99 %
1 USD 20,175,487.99 USD 20,065,796.33 USD 17,205,492.55
3 USD 20,531,096.90 USD 20,198,039.07 USD 15,386,913.89
6 USD 21,076,296.99 USD 20,398,039.12 USD 13,801,323.61
12 USD 22,210,514.74 USD 20,804,000.00 USD 11,922,148.72
24 USD 24,665,348.25 USD 21,640,320.80 USD 10,115,401.50
36 USD 27,391,504.05 USD 22,510,261.70 USD 9,571,531.38
48 USD 30,418,970.22 USD 23,415,174.22 USD 9,842,238.19

11.2 Análisis de dividendos

div_t <- data.frame(
  Empresa  = c("Adobe Inc. (ADBE)","Vertex Pharmaceuticals (VRTX)","Monster Beverage (MNST)"),
  Yield    = c("0 %","0 %","0 %"),
  Politica = c("No paga dividendos – programa activo de recompra de acciones",
               "No paga dividendos – reinversión en I+D y adquisiciones estratégicas",
               "No paga dividendos – recompra activa de acciones"),
  Fuente   = c("Yahoo Finance (2026a); SEC Form 10-K Adobe FY2025",
               "Yahoo Finance (2026b); Vertex Pharmaceuticals (2026a)",
               "Yahoo Finance (2026c); Monster Beverage Corporation (2026)"),
  Impacto  = c("Retorno total = apreciación de capital. Sin ajuste al precio por ex-dividendo.",
               "Retorno total = apreciación de capital. Sin ajuste al precio por ex-dividendo.",
               "Retorno total = apreciación de capital. Sin ajuste al precio por ex-dividendo.")
)
kable(div_t,
      col.names=c("Empresa","Div. Yield","Política","Fuente verificable","Impacto en portafolio"),
      caption="Tabla 20. Política de dividendos (Fuentes: Yahoo Finance, 2026; SEC EDGAR)") |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE)
Tabla 20. Política de dividendos (Fuentes: Yahoo Finance, 2026; SEC EDGAR)
Empresa Div. Yield Política Fuente verificable Impacto en portafolio
Adobe Inc. (ADBE) 0 % No paga dividendos – programa activo de recompra de acciones Yahoo Finance (2026a); SEC Form 10-K Adobe FY2025 Retorno total = apreciación de capital. Sin ajuste al precio por ex-dividendo.
Vertex Pharmaceuticals (VRTX) 0 % No paga dividendos – reinversión en I+D y adquisiciones estratégicas Yahoo Finance (2026b); Vertex Pharmaceuticals (2026a) Retorno total = apreciación de capital. Sin ajuste al precio por ex-dividendo.
Monster Beverage (MNST) 0 % No paga dividendos – recompra activa de acciones Yahoo Finance (2026c); Monster Beverage Corporation (2026) Retorno total = apreciación de capital. Sin ajuste al precio por ex-dividendo.

Impacto de los dividendos en la cobertura: Las tres acciones no pagan dividendos al 30 de abril de 2026, lo cual fue verificado en Yahoo Finance y los reportes 10-K de cada empresa. Por tanto, el retorno total del portafolio coincide completamente con la apreciación de capital: no hay flujos de efectivo intermedios que ajustar. Si alguna empresa pagara dividendos, el precio spot caería el día ex-dividendo y deberían sumarse al retorno de precio para no subestimar el rendimiento total. En la fórmula del precio teórico del futuro, \(F_0 = S_0 \cdot e^{(r-q)T}\), el término \(q\) (dividend yield) sería cero para este portafolio, por lo que el precio teórico del futuro no requiere ajuste por dividendos.

proy_df <- data.frame(
  Mes    = meses_proy,
  Sin    = V_sin_m/1e6,
  Con    = V_con_m/1e6,
  VaR    = pmax(V_var_m/1e6, 0)
) |> pivot_longer(-Mes, names_to="Tipo", values_to="Valor") |>
  mutate(Tipo=case_when(Tipo=="Sin"~"Sin cobertura",
                        Tipo=="Con"~"Con cobertura (Rf)",
                        TRUE~"Ajustado VaR 99 %"))

banda <- data.frame(
  Mes  = meses_proy,
  Ymin = (V_sin_m - VaR99_usd*sqrt(meses_proy))/1e6,
  Ymax = (V_sin_m + VaR99_usd*sqrt(meses_proy))/1e6
)

ggplot(proy_df, aes(x=Mes, y=Valor, color=Tipo, linetype=Tipo)) +
  geom_ribbon(data=banda, aes(x=Mes,ymin=Ymin,ymax=Ymax),
              inherit.aes=FALSE, fill="#3182ce", alpha=0.10) +
  geom_line(linewidth=1) +
  scale_color_manual(values=c("Sin cobertura"="#1f77b4",
                               "Con cobertura (Rf)"="#2ca02c",
                               "Ajustado VaR 99 %"="#d62728")) +
  scale_linetype_manual(values=c("Sin cobertura"="solid",
                                  "Con cobertura (Rf)"="solid",
                                  "Ajustado VaR 99 %"="dashed")) +
  scale_y_continuous(labels=label_dollar(suffix="M", scale=1)) +
  labs(title="Figura 9. Proyección mensual del valor del portafolio a 4 años",
       subtitle="Banda azul: ±VaR 99 % escalado | Tres enfoques de valoración",
       x="Mes", y="Valor (USD millones)", color=NULL, linetype=NULL) +
  tema_lab + theme(legend.position="top")


12 Análisis de Sensibilidad: Beta = 0.5 y Beta = 2

12.1 Número de contratos y exposición por escenario de beta

betas_hip <- c(0.5, beta_port, 2.0)
sens_df   <- lapply(betas_hip, function(b) {
  N_c <- (b*V_port)/(F0*M); N_u <- ceiling(N_c)
  data.frame(Beta=b, N_exacto=round(N_c,3), N_contratos=N_u,
             Margen_total=N_u*margen_ini,
             Ratio_cob=round(N_u*F0*M/(b*V_port),4),
             Exp_sist=round(b*V_port),
             Sens_1pct=round(b*V_port*0.01))
}) |> bind_rows()

kable(sens_df, digits=3,
      col.names=c("Beta (β_p)","N* exacto","N* entero","Margen inicial total",
                  "Ratio cobertura","Exposición sistemática","Pérdida por -1 % índice"),
      caption="Tabla 21. Análisis de sensibilidad: contratos y exposición por beta",
      format.args=list(big.mark=",")) |>
  kable_styling(bootstrap_options=c("striped","hover"), full_width=TRUE) |>
  row_spec(which(round(sens_df$Beta,2)==round(beta_port,2)), bold=TRUE, background="#fff3cd")
Tabla 21. Análisis de sensibilidad: contratos y exposición por beta
Beta (β_p) N* exacto N* entero Margen inicial total Ratio cobertura Exposición sistemática Pérdida por -1 % índice
0.500 35.907 36 450,000 1.003 10,000,000 100,000
0.834 59.927 60 750,000 1.001 16,689,557 166,896
2.000 143.627 144 1,800,000 1.003 40,000,000 400,000

12.2 Cambio en la estrategia de cobertura según beta

beta_seq <- seq(0.2, 2.5, by = 0.05)

N_seq <- ceiling((beta_seq * V_port) / (F0 * M))

plot_df <- data.frame(
  Beta = beta_seq,
  N = N_seq
)

ggplot(plot_df, aes(x = Beta, y = N)) +

  # Línea principal
  geom_line(
    color = "#2c5282",
    linewidth = 1.3
  ) +

  # Puntos destacados
  geom_point(
    data = sens_df,
    aes(x = Beta, y = N_contratos),
    color = "#c53030",
    size = 4,
    shape = 18
  ) +

  # Línea vertical beta actual
  geom_vline(
    xintercept = beta_port,
    linetype = "dashed",
    color = "#b7791f",
    linewidth = 0.9
  ) +

  # Texto beta actual
  annotate(
    "text",
    x = beta_port + 0.05,
    y = max(N_seq) * 0.9,
    label = paste0(
      "β_p actual = ",
      round(beta_port, 3)
    ),
    color = "#d97706",
    size = 3.6,
    hjust = 0,
    fontface = "bold"
  ) +

  # Etiquetas
  labs(
    title = "Figura 10. Número óptimo de contratos vs. beta del portafolio",

    subtitle = paste0(
      "Vp = USD 20 M | F0 = ",
      F0,
      " | M = 50"
    ),

    x = "Beta (βp)",

    y = "Número de contratos"
  ) +

  # Tema
  theme_minimal(base_size = 12) +

  theme(
    plot.title = element_text(
      size = 16,
      face = "bold",
      hjust = 0.5,
      color = "#1a202c"
    ),

    plot.subtitle = element_text(
      size = 11,
      hjust = 0.5,
      color = "#4a5568"
    ),

    axis.title = element_text(
      face = "bold",
      color = "#2d3748"
    ),

    panel.grid.minor = element_blank()
  )

Análisis del cambio de estrategia:

Mientras el inversionista mantenga una posición comprada en acciones, la cobertura apropiada continúa siendo una posición corta en futuros; lo que cambia con la beta es la intensidad de la cobertura, no su dirección:

Con beta = 0.5, el portafolio tiene baja sensibilidad sistémica y requiere solo 36 contratos. Una caída del 1 % en el índice genera una pérdida de USD 100,000.00 en el portafolio, con un costo de margen de USD 450,000.00. La cobertura es liviana porque el portafolio ya tiene poca exposición al mercado.

Con beta = 2.0, el portafolio amplifica el doble los movimientos del índice y requiere 144 contratos. Una caída del 1 % genera una pérdida de USD 400,000.00, con un costo de margen de USD 1,800,000.00. La cobertura es más intensa porque el portafolio está más expuesto al riesgo sistemático que el propio índice.

La regla general es que \(N^* \propto \beta_P\): a mayor beta, mayor exposición sistemática y mayor cantidad de contratos necesarios para neutralizarla (Hull, 2009).

12.3 Cobertura Trimestral Comparativa: Beta Actual, Beta = 0.5 y Beta = 2

Siguiendo la estructura del ejemplo de cobertura de acciones (Rodríguez, 2026b), se presenta a continuación la tabla trimestral que consolida el rendimiento esperado, el valor de la cartera y el valor esperado de la cobertura bajo los tres escenarios de beta: el beta real del portafolio, el hipotético de 0.5 y el hipotético de 2.0. Esta tabla es el equivalente en R de la hoja “cobertura corta trimestral” del ejemplo del docente.

# ── Parámetros ────────────────────────────────────────────────────────────────
betas_comp   <- c(beta_port, 0.5, 2.0)
nombres_beta <- c(paste0("Beta real (", round(beta_port,3),")"),"Beta = 0.5","Beta = 2.0")

# Retorno esperado CAPM por trimestre para cada beta
# E[R_trim] = Rf_trim + beta * (E[R_m_trim] - Rf_trim)
mu_m_trim <- (1 + mu_mercado)^(1/4) - 1   # retorno trimestral del mercado

# Usar la trayectoria simulada del portafolio (escenario intermedio)
port_interm <- filter(port_paths, Escenario == "Intermedio")

# Índices de cierre de cada trimestre
idx_fin_trim <- seq(3, T_total, by = 3) + 1
idx_fin_trim <- pmin(idx_fin_trim, nrow(port_interm))

V_port_trim <- port_interm$Valor[idx_fin_trim] * 1e6   # valor cartera USD

# Calcular para cada beta
resultados_betas <- lapply(seq_along(betas_comp), function(k) {
  b    <- betas_comp[k]
  # Rendimiento esperado CAPM trimestral
  re   <- Rf_trim + b * (mu_m_trim - Rf_trim)
  # Valor esperado = valor cartera * (1 + rendimiento esperado)
  prev <- c(capital, V_port_trim[-length(V_port_trim)])
  ve   <- prev * (1 + re)
  # Resultado trimestral = valor esperado - valor esperado trimestre anterior
  res  <- ve - lag(ve, default = capital)

  data.frame(
    Trimestre     = paste0("T", seq_along(idx_fin_trim)),
    Rend_Esp      = re,
    Valor_Cartera = V_port_trim,
    Valor_Esp     = round(ve, 2),
    Resultado     = round(res, 2),
    Beta_label    = nombres_beta[k]
  )
}) |> bind_rows()

# ── Tabla comparativa ─────────────────────────────────────────────────────────
# Formato ancho: un bloque de columnas por beta
beta_real_df <- filter(resultados_betas, Beta_label == nombres_beta[1])
beta_05_df   <- filter(resultados_betas, Beta_label == nombres_beta[2])
beta_20_df   <- filter(resultados_betas, Beta_label == nombres_beta[3])

tabla_comp <- data.frame(
  Trimestre       = beta_real_df$Trimestre,
  # Beta real
  RE_real         = fmt_pct(beta_real_df$Rend_Esp),
  VC_real         = round(beta_real_df$Valor_Cartera / 1e6, 3),
  VE_real         = round(beta_real_df$Valor_Esp     / 1e6, 3),
  Res_real        = round(beta_real_df$Resultado     / 1e6, 3),
  # Beta 0.5
  RE_05           = fmt_pct(beta_05_df$Rend_Esp),
  VC_05           = round(beta_05_df$Valor_Cartera   / 1e6, 3),
  VE_05           = round(beta_05_df$Valor_Esp       / 1e6, 3),
  Res_05          = round(beta_05_df$Resultado       / 1e6, 3),
  # Beta 2.0
  RE_20           = fmt_pct(beta_20_df$Rend_Esp),
  VC_20           = round(beta_20_df$Valor_Cartera   / 1e6, 3),
  VE_20           = round(beta_20_df$Valor_Esp       / 1e6, 3),
  Res_20          = round(beta_20_df$Resultado       / 1e6, 3)
)

kable(tabla_comp,
      col.names = c(
        "Trimestre",
        "Rend. Esp.", "V. Cartera (M)", "V. Esperado (M)", "Resultado (M)",
        "Rend. Esp.", "V. Cartera (M)", "V. Esperado (M)", "Resultado (M)",
        "Rend. Esp.", "V. Cartera (M)", "V. Esperado (M)", "Resultado (M)"
      ),
      caption = paste0(
        "Tabla. Cobertura corta trimestral comparativa — ",
        "Beta real (", round(beta_port,3), "), Beta = 0.5 y Beta = 2.0 ",
        "(valores en USD millones, Fuente: elaboración propia con base en Rodríguez, 2026b)"
      ),
      format.args = list(big.mark = ",")) |>
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = TRUE, font_size = 11) |>
  add_header_above(c(
    " " = 1,
    setNames(4, paste0("Beta real (", round(beta_port,3), ")")),
    "Beta = 0.5" = 4,
    "Beta = 2.0" = 4
  )) |>
  column_spec(c(5,9,13),
              color = ifelse(c(tabla_comp$Res_real,
                               tabla_comp$Res_05,
                               tabla_comp$Res_20) < 0,
                             "red","darkgreen")[c(
               seq_len(nrow(tabla_comp)),
               nrow(tabla_comp) + seq_len(nrow(tabla_comp)),
               2*nrow(tabla_comp) + seq_len(nrow(tabla_comp))
             )],
              bold = TRUE)
Tabla. Cobertura corta trimestral comparativa — Beta real (0.834), Beta = 0.5 y Beta = 2.0 (valores en USD millones, Fuente: elaboración propia con base en Rodríguez, 2026b)
Beta real (0.834)
Beta = 0.5
Beta = 2.0
Trimestre Rend. Esp. V. Cartera (M) V. Esperado (M) Resultado (M) Rend. Esp. V. Cartera (M) V. Esperado (M) Resultado (M) Rend. Esp. V. Cartera (M) V. Esperado (M) Resultado (M)
T1 2.65% 22.095 20.530 0.530 1.98% 22.095 20.397 0.397 4.96% 22.095 20.992 0.992
T2 2.65% 24.020 22.680 2.151 1.98% 24.020 22.533 2.137 4.96% 24.020 23.192 2.199
T3 2.65% 30.927 24.656 1.975 1.98% 30.927 24.496 1.963 4.96% 30.927 25.212 2.020
T4 2.65% 40.073 31.746 7.090 1.98% 40.073 31.540 7.044 4.96% 40.073 32.462 7.250
T5 2.65% 36.219 41.134 9.388 1.98% 36.219 40.868 9.328 4.96% 36.219 42.062 9.600
T6 2.65% 31.640 37.178 -3.956 1.98% 31.640 36.938 -3.930 4.96% 31.640 38.017 -4.045
T7 2.65% 29.329 32.478 -4.700 1.98% 29.329 32.268 -4.670 4.96% 29.329 33.210 -4.806
T8 2.65% 28.482 30.106 -2.372 1.98% 28.482 29.911 -2.357 4.96% 28.482 30.785 -2.426
T9 2.65% 31.547 29.236 -0.870 1.98% 31.547 29.047 -0.864 4.96% 31.547 29.896 -0.889
T10 2.65% 28.240 32.382 3.146 1.98% 28.240 32.173 3.126 4.96% 28.240 33.112 3.217
T11 2.65% 33.439 28.988 -3.394 1.98% 33.439 28.801 -3.372 4.96% 33.439 29.642 -3.470
T12 2.65% 30.182 34.324 5.336 1.98% 30.182 34.102 5.302 4.96% 30.182 35.098 5.456
T13 2.65% 23.434 30.981 -3.343 1.98% 23.434 30.781 -3.321 4.96% 23.434 31.680 -3.418
T14 2.65% 23.730 24.054 -6.927 1.98% 23.730 23.898 -6.882 4.96% 23.730 24.596 -7.083
T15 2.65% 22.131 24.358 0.304 1.98% 22.131 24.200 0.302 4.96% 22.131 24.907 0.311
T16 2.65% 24.278 22.717 -1.641 1.98% 24.278 22.570 -1.630 4.96% 24.278 23.229 -1.678

El rendimiento esperado trimestral se calcula por CAPM como \(E[R_{trim}] = R_{f,trim} + \beta \times (E[R_{m,trim}] - R_{f,trim})\) (Rodríguez, 2026b). El valor esperado de cada trimestre corresponde al valor de la cartera del trimestre anterior multiplicado por \((1 + E[R_{trim}])\). El resultado trimestral es la diferencia entre el valor esperado del trimestre actual y el del trimestre anterior, representando la ganancia o pérdida neta de la cobertura en ese período.

Con beta real de 0.834, el portafolio tiene una exposición sistemática moderada y requiere 60 contratos. Con beta = 0.5 la sensibilidad al mercado se reduce a la mitad, generando menores rendimientos esperados en períodos alcistas pero mayor protección en períodos bajistas. Con beta = 2.0 el portafolio amplifica los movimientos del índice, lo que en períodos alcistas genera mayor valor esperado pero en períodos bajistas profundiza las pérdidas, haciendo la cobertura más crítica y costosa.

12.4 Análisis de Dividendos en la Cobertura

div_tabla <- data.frame(
  Empresa    = c("Adobe Inc. (ADBE)",
                 "Vertex Pharmaceuticals (VRTX)",
                 "Monster Beverage Corp. (MNST)"),
  Div_yield  = c("0 %", "0 %", "0 %"),
  Politica   = c("No paga dividendos. Reinvierte mediante recompra de acciones (StockAnalysis, 2026a)",
                 "No paga dividendos. Reinvierte en I+D y adquisiciones estratégicas (Yahoo Finance, 2026b)",
                 "No paga dividendos. Reinvierte en crecimiento orgánico e internacional (Yahoo Finance, 2026c)"),
  Impacto_cob = c("Sin ajuste al precio futuro por dividendos. q = 0 en F₀ = S₀·e^(r-q)T",
                   "Sin ajuste al precio futuro por dividendos. q = 0 en F₀ = S₀·e^(r-q)T",
                   "Sin ajuste al precio futuro por dividendos. q = 0 en F₀ = S₀·e^(r-q)T")
)

kable(div_tabla,
      col.names = c("Empresa","Dividend Yield",
                    "Política de dividendos (fuente verificable)",
                    "Impacto en la cobertura con futuros"),
      caption = "Tabla. Política de dividendos y efecto sobre el precio teórico del futuro") |>
  kable_styling(bootstrap_options = c("striped","hover"), full_width = TRUE) |>
  column_spec(1, bold = TRUE)
Tabla. Política de dividendos y efecto sobre el precio teórico del futuro
Empresa Dividend Yield Política de dividendos (fuente verificable) Impacto en la cobertura con futuros
Adobe Inc. (ADBE) 0 % No paga dividendos. Reinvierte mediante recompra de acciones (StockAnalysis, 2026a) Sin ajuste al precio futuro por dividendos. q = 0 en F₀ = S₀·e^(r-q)T
Vertex Pharmaceuticals (VRTX) 0 % No paga dividendos. Reinvierte en I+D y adquisiciones estratégicas (Yahoo Finance, 2026b) Sin ajuste al precio futuro por dividendos. q = 0 en F₀ = S₀·e^(r-q)T
Monster Beverage Corp. (MNST) 0 % No paga dividendos. Reinvierte en crecimiento orgánico e internacional (Yahoo Finance, 2026c) Sin ajuste al precio futuro por dividendos. q = 0 en F₀ = S₀·e^(r-q)T

Las tres acciones del portafolio no pagan dividendos en efectivo, lo cual fue verificado en las fuentes indicadas. Esto simplifica la valoración de los contratos de futuros: el precio teórico del futuro se calcula como \(F_0 = S_0 \cdot e^{r \cdot T}\), donde el término de dividend yield \(q = 0\). Si alguna empresa pagara dividendos, el precio spot caería el día ex-dividendo y el precio teórico del futuro sería \(F_0 = S_0 \cdot e^{(r-q) \cdot T}\), generando un ajuste a la baja en el precio forward y, por tanto, en el número de contratos necesarios (Hull, 2009).


13 Referencias

Adobe Inc. (2025). Adobe reports record Q4 and FY2025 results [Form 8-K]. U.S. Securities and Exchange Commission. https://www.sec.gov/Archives/edgar/data/0000796343/000079634325000135/adbeex991q425.htm

Benzinga. (2026a). Adobe (ADBE) stock price prediction 2026. Recuperado el 30 de abril de 2026, de https://www.benzinga.com/money/adobe-stock-price-prediction

Benzinga. (2026b). Vertex Pharmaceuticals (VRTX) analyst ratings and price targets. Recuperado el 30 de abril de 2026, de https://www.benzinga.com/quote/VRTX/analyst-ratings

Bodie, Z., Kane, A., & Marcus, A. (2008). Investments (8.ª ed.). McGraw-Hill.

DividendMax. (2026). Dividend history and forecasts – ADBE, VRTX, MNST. Recuperado el 30 de abril de 2026, de https://www.dividendmax.com

Elton, E. J., Gruber, M. J., Brown, S. J., & Goetzmann, W. N. (2014). Modern portfolio theory and investment analysis (9.ª ed.). John Wiley & Sons.

Fabozzi, F. J., Kolm, P. N., Pachamanova, D., & Focardi, S. M. (2007). Robust portfolio optimization and management. John Wiley & Sons.

CME Group. (2026). E-mini S&P 500 futures contract specifications. https://www.cmegroup.com/markets/equities/sp/e-mini-sandp500.contractSpecs.html

Federal Reserve/CBOE. (2026). ^TNX – CBOE Interest Rate 3-5 Year Treasury. https://finance.yahoo.com/quote/%5ETNX/

FINVIZ. (2026). Stock screener – Fundamentals. https://finviz.com/screener.ashx

FullRatio. (2026). ADBE 2026 earnings & EPS history. https://fullratio.com/stocks/nasdaq-adbe/earnings

Hull, J. C. (2009). Introducción a los mercados de futuros y opciones (6.ª ed.). Pearson Education.

Markowitz, H. (1952). Portfolio selection. The Journal of Finance, 7(1), 77–91. https://doi.org/10.2307/2975974

Investing.com. (2026). Vertex (VRTX) stock forecast & price target. https://www.investing.com/equities/vertex-pharm-consensus-estimates

Monster Beverage Corporation. (2026). Monster Beverage reports 2026 first quarter financial results [Form 8-K]. U.S. Securities and Exchange Commission. https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0000865752&type=8-K

Rodríguez, D. E. (2026a). Derivados financieros – Forwards. Instituto Tecnológico Metropolitano.

Rodríguez, D. E. (2026b). Derivados financieros – Futuros. Instituto Tecnológico Metropolitano.

Rodríguez, D. E. (2026c). Clase derivados financieros 08/05/2026 [Grabación de reunión virtual]. Instituto Tecnológico Metropolitano. https://correoitmedu-my.sharepoint.com

Serrano, J. (2005). Mercados financieros. Universidad de los Andes.

StockAnalysis. (2026a). Adobe (ADBE) stock price & overview. https://stockanalysis.com/stocks/adbe/

StockAnalysis. (2026b). Vertex Pharmaceuticals (VRTX) stock price. https://stockanalysis.com/stocks/vrtx/forecast/

StockAnalysis. (2026c). Monster Beverage (MNST) stock price. https://stockanalysis.com/stocks/mnst/

TickerNerd. (2026a). ADBE stock forecast 2026. https://tickernerd.com/stock/adbe-forecast/

TickerNerd. (2026b). VRTX stock forecast 2026. https://tickernerd.com/stock/vrtx-forecast/

TIKR. (2026a). Monster Beverage stock analysis. https://www.tikr.com/blog/monster-beverage-stock-is-up-25-over-the-past-year-heres-what-q1-sales-jump-means-for-2026

TradingView. (2026). Monster Beverage Corporation (MNST) chart. https://www.tradingview.com/symbols/NASDAQ-MNST/

Vertex Pharmaceuticals. (2026a). Vertex reports fourth quarter and full year 2025 financial results. https://investors.vrtx.com

Vertex Pharmaceuticals. (2026b). Vertex reports first quarter 2026 financial results. https://news.vrtx.com/news-releases/news-release-details/vertex-reports-first-quarter-2026-financial-results

Yahoo Finance. (2026a). Adobe Inc. (ADBE). https://finance.yahoo.com/quote/ADBE/

Yahoo Finance. (2026b). Vertex Pharmaceuticals Incorporated (VRTX) – stock price. Recuperado el 30 de abril de 2026, de https://finance.yahoo.com/quote/VRTX/

Yahoo Finance. (2026c). Monster Beverage Corporation (MNST) – stock price, news & history. Recuperado el 30 de abril de 2026, de https://finance.yahoo.com/quote/MNST/