1 Introducción

En este laboratorio se construye un portafolio de acciones y se simula su comportamiento bajo un Movimiento Browniano Geométrico (MGB) para un horizonte de inversión de largo plazo. A partir de tres activos accionarios (MSFT, NKE y NEE) se estima un portafolio de media-varianza, que servirá posteriormente como subyacente para la valuación de opciones europeas y americanas y el diseño de estrategias de cobertura.

La inversión total considerada es de 10 millones de dólares, y se utiliza información histórica de precios desde el 01/10/2023 en adelante. En la primera parte se construye el portafolio y se simulan las trayectorias de precios del portafolio bajo un modelo MGB. En la segunda parte se analiza el desempeño del portafolio mediante volatilidad, índice de Sharpe y medidas de riesgo como el VaR. Finalmente, en la tercera parte se valúan opciones europeas y americanas sobre cada activo y se diseña una estrategia de cobertura del 85 % de la inversión, apalancada a la tasa del bono del Tesoro a 10 años.

2 1. Construcción del portafolio y simulación MGB

2.1 1.1 Carga de librerías y datos

# Definir las tres acciones del portafolio
tickers <- c("MSFT", "NKE", "NEE")

# Fecha de inicio de la base de datos
fecha_inicio <- "2023-10-01"

# Descarga de precios ajustados diarios
precios <- tq_get(tickers,
                  from = fecha_inicio,
                  get  = "stock.prices") %>%
  select(symbol, date, adjusted) %>%
  pivot_wider(names_from = symbol, values_from = adjusted)

head(precios)
## # A tibble: 6 × 4
##   date        MSFT   NKE   NEE
##   <date>     <dbl> <dbl> <dbl>
## 1 2023-10-02  317.  91.1  49.1
## 2 2023-10-03  309.  91.6  49.7
## 3 2023-10-04  314.  92.4  47.6
## 4 2023-10-05  315.  92.3  46.5
## 5 2023-10-06  322.  93.6  47.3
## 6 2023-10-09  325.  93.3  46.4

En la tabla anterior se observan los precios ajustados diarios de las acciones MSFT, NKE y NEE desde la fecha seleccionada.

2.2 1.2 Cálculo de retornos y parámetros (mu, Sigma)

# Ordenar por fecha y calcular retornos logarítmicos diarios
ret_diarios <- precios %>%
  arrange(date) %>%
  mutate(across(-date,
                ~ log(.x / dplyr::lag(.x)),
                .names = "ret_{col}")) %>%
  select(date, starts_with("ret_")) %>%
  drop_na()

head(ret_diarios)
## # A tibble: 6 × 4
##   date       ret_MSFT  ret_NKE ret_NEE
##   <date>        <dbl>    <dbl>   <dbl>
## 1 2023-10-03 -0.0265   0.00559  0.0120
## 2 2023-10-04  0.0176   0.00838 -0.0418
## 3 2023-10-05  0.00125 -0.00104 -0.0234
## 4 2023-10-06  0.0244   0.0137   0.0158
## 5 2023-10-09  0.00779 -0.00237 -0.0185
## 6 2023-10-10 -0.00435  0.00761  0.0448
# Matriz de retornos (sin la columna date)
R <- ret_diarios %>%
  select(-date) %>%
  as.matrix()

# Vector de medias de retornos diarios (mu) y matriz de covarianza (Sigma)
mu    <- colMeans(R)
Sigma <- cov(R)

mu
##      ret_MSFT       ret_NKE       ret_NEE 
##  0.0009217002 -0.0007568996  0.0009706352
Sigma
##              ret_MSFT      ret_NKE      ret_NEE
## ret_MSFT 1.935298e-04 6.585606e-05 6.467237e-06
## ret_NKE  6.585606e-05 5.495113e-04 7.697379e-05
## ret_NEE  6.467237e-06 7.697379e-05 3.128711e-04

2.2.1 Análisis de retornos y covarianzas

A partir de la serie de precios diarios desde el 01/10/2023 se calcularon retornos logarítmicos para las tres acciones MSFT, NKE y NEE. Los promedios de los retornos diarios (vector mu) permiten identificar cuáles activos han presentado, en el período de estudio, una mayor tendencia de crecimiento esperado.

De forma complementaria, la matriz de covarianza (Sigma) muestra cómo se mueven conjuntamente los activos. Covarianzas positivas entre los pares de acciones indican que tienden a moverse en la misma dirección, mientras que covarianzas relativamente bajas sugieren que existe potencial de diversificación. En este caso, la estructura de Sigma es coherente con un portafolio de renta variable diversificada: los activos están correlacionados, pero no de forma perfecta, lo que abre espacio para reducir riesgo mediante la combinación adecuada de pesos.

2.3 1.3 Portafolio media-varianza (Markowitz)

n <- length(mu)   # número de activos

# Matrices para solve.QP (minimizar 1/2 x' D x - d' x)
Dmat <- 2 * Sigma
dvec <- rep(0, n)

# Restricciones en forma: t(Amat) %*% w >= bvec
# 1) sum(w) = 1  (primera restricción, tratada como igualdad)
# 2) w_i >= 0   (no short-selling)

Amat <- cbind(
  rep(1, n),   # sum(w) >= 1
  diag(n)      # w_i >= 0
)
bvec <- c(1, rep(0, n))

sol <- solve.QP(Dmat, dvec, Amat, bvec, meq = 1)  # meq=1 → primera restricción es igualdad

w_opt <- sol$solution
names(w_opt) <- tickers

w_opt
##       MSFT        NKE        NEE 
## 0.56178666 0.09882279 0.33939054
sum(w_opt)  # Debe ser ~1
## [1] 1
inversion_total <- 10e6  # 10 millones de dólares

monto_por_accion <- w_opt * inversion_total
monto_por_accion
##      MSFT       NKE       NEE 
## 5617866.6  988227.9 3393905.4
# Precio al último día disponible
precios_ult <- precios %>%
  arrange(date) %>%
  tail(1) %>%
  select(-date) %>%
  as.numeric()

names(precios_ult) <- tickers

precios_ult
##   MSFT    NKE    NEE 
## 514.33  61.23  81.69
# Cantidad de acciones compradas de cada activo
cantidades <- monto_por_accion / precios_ult
cantidades
##     MSFT      NKE      NEE 
## 10922.69 16139.60 41546.15

2.3.1 Análisis del portafolio de mínima varianza

Con los parámetros mu y Sigma se construyó un portafolio de varianza mínima global, sujeto a dos condiciones: (i) la suma de los pesos es igual a 1 y (ii) no se permiten posiciones cortas. Los pesos óptimos obtenidos reflejan qué proporción de la inversión total se asigna a cada acción para minimizar el riesgo total del portafolio.

El hecho de que algunos activos reciban un peso mayor indica que, dadas las covarianzas observadas, estos instrumentos contribuyen de manera más eficiente a reducir la volatilidad agregada. En otras palabras, no solo importa el riesgo y el retorno individual de cada acción, sino también cómo interactúa con el resto del portafolio. La solución de Markowitz aprovecha precisamente esos efectos de diversificación: si dos activos no se mueven exactamente igual, una combinación adecuada puede lograr un nivel de riesgo menor que el de cualquiera de ellos por separado.

2.4 1.4 Simulación MGB del portafolio a dos años

A continuación se simulan trayectorias de precios para cada activo y para el portafolio utilizando un Movimiento Browniano Geométrico (MGB). Se considera un horizonte de 2 años con pasos diarios de mercado (aprox. 252 días al año).

set.seed(123)  # Para reproducibilidad

# Parámetros de simulación
anios         <- 2
dias_por_anio <- 252
N             <- anios * dias_por_anio
dt            <- 1 / dias_por_anio

# Precio inicial de cada acción (último precio observado)
S0 <- precios_ult
S0
##   MSFT    NKE    NEE 
## 514.33  61.23  81.69
mu
##      ret_MSFT       ret_NKE       ret_NEE 
##  0.0009217002 -0.0007568996  0.0009706352
Sigma
##              ret_MSFT      ret_NKE      ret_NEE
## ret_MSFT 1.935298e-04 6.585606e-05 6.467237e-06
## ret_NKE  6.585606e-05 5.495113e-04 7.697379e-05
## ret_NEE  6.467237e-06 7.697379e-05 3.128711e-04
# Función para simular trayectorias MGB correlacionadas
simular_mgb <- function(S0, mu, Sigma, dt, N, n_sim = 1000) {
  n_activos <- length(S0)
  L <- chol(Sigma)          # descomposición de Cholesky

  # Array con dimensiones: tiempo x simulación x activo
  S <- array(NA, dim = c(N + 1, n_sim, n_activos))

  # Condición inicial: todos los escenarios parten de S0
  S[1, , ] <- matrix(rep(S0, each = n_sim),
                     nrow = n_sim,
                     byrow = FALSE)

  for (t in 2:(N + 1)) {
    # Z ~ N(0, I)
    Z <- matrix(rnorm(n_sim * n_activos),
                nrow = n_sim,
                ncol = n_activos)

    # Choques correlacionados
    eps <- Z %*% L

    # Drift y difusión
    drift <- (mu - 0.5 * diag(Sigma)) * dt       # vector (n_activos)
    diffu <- sqrt(dt) * eps                      # matriz n_sim x n_activos

    # Actualización de precios
    S[t, , ] <- S[t - 1, , ] * exp(
      matrix(rep(drift, each = n_sim),
             nrow = n_sim,
             byrow = FALSE) +
        diffu
    )
  }

  return(S)
}

# Número de simulaciones
n_sim <- 1000

S_sim <- simular_mgb(S0 = S0,
                     mu = mu,
                     Sigma = Sigma,
                     dt = dt,
                     N = N,
                     n_sim = n_sim)

dim(S_sim)   # tiempo x simulación x activos
## [1]  505 1000    3
w      <- w_opt
n_act  <- length(w)
tiempo <- 0:N

# Matriz con el valor del portafolio: filas = tiempo, columnas = simulaciones
V <- matrix(NA, nrow = N + 1, ncol = n_sim)

for (t in 1:(N + 1)) {
  # precios en el tiempo t: matriz n_sim x n_activos
  S_t <- S_sim[t, , ]
  S_t <- matrix(S_t, nrow = n_sim, ncol = n_act)

  # valor del portafolio en cada simulación
  V[t, ] <- S_t %*% w
}

# Estadísticos descriptivos por tiempo
V_media <- rowMeans(V)
V_q05   <- apply(V, 1, quantile, 0.05)
V_q95   <- apply(V, 1, quantile, 0.95)

head(V_media)
## [1] 322.7195 322.7248 322.7241 322.7175 322.7076 322.6937

2.4.1 Análisis de la simulación MGB del portafolio

La simulación mediante Movimiento Browniano Geométrico (MGB) permite proyectar trayectorias posibles del valor del portafolio durante un horizonte de dos años. El modelo asume retornos lognormales, volatilidad constante y shocks aleatorios con distribución normal, correlacionados según la matriz Sigma estimada.

La curva media de la simulación representa el valor esperado del portafolio en cada punto del tiempo, mientras que las bandas formadas por los cuantiles 5 % y 95 % muestran un intervalo de confianza aproximado del 90 %. Una banda más ancha indica una mayor incertidumbre sobre el valor futuro de la inversión, es decir, mayor riesgo. La tendencia general de la media (creciente, estable o volátil) refleja la interacción entre el retorno esperado y la volatilidad de los activos.

En conjunto, estos resultados permiten visualizar no solo un escenario puntual, sino un conjunto de escenarios probables para la evolución de la inversión de 10 millones de dólares, lo cual es fundamental para la toma de decisiones de cobertura con derivados.

3 2. Análisis de riesgo y desempeño del portafolio

En esta sección se evalúa el comportamiento del portafolio construido mediante el modelo de media-varianza. A partir de los retornos históricos desde el 01/10/2023 se calculan:

3.1 2.1 Definición de la tasa libre de riesgo (bono a 10 años)

# Tasa libre de riesgo (bono del Tesoro de EE. UU. a 10 años)
rf_anual  <- 0.04          # 4 % anual
rf_diaria <- rf_anual / 252

rf_anual
## [1] 0.04
rf_diaria
## [1] 0.0001587302

Se adopta una tasa libre de riesgo del 4 % anual, correspondiente al rendimiento de referencia de los bonos del Tesoro de Estados Unidos a 10 años. Esta tasa se utilizará para el cálculo del índice de Sharpe y la valuación de derivados en la estrategia de cobertura.

3.2 2.2 Retornos y volatilidad del portafolio

# Retornos históricos del portafolio (combinación lineal de los activos)
R_port_hist <- R %*% w_opt   # R es la matriz de retornos de los activos
colnames(R_port_hist) <- "Portafolio"

# Volatilidad diaria histórica (por activo y para el portafolio)
sigma_diaria_activos <- apply(R, 2, sd)
sigma_diaria_port    <- sd(R_port_hist)

sigma_diaria_activos
##   ret_MSFT    ret_NKE    ret_NEE 
## 0.01391150 0.02344166 0.01768816
sigma_diaria_port
## [1] 0.0108363

3.2.1 Interpretación de la volatilidad del portafolio

La volatilidad diaria de cada activo mide la dispersión de sus retornos alrededor de la media, es decir, qué tan “nervioso” es el comportamiento del precio en el corto plazo. En general, acciones con volatilidad más alta implican un mayor riesgo de fluctuaciones fuertes, tanto al alza como a la baja.

Al comparar la volatilidad de cada acción con la volatilidad del portafolio, se observa que la combinación de MSFT, NKE y NEE logra un nivel de riesgo agregado que puede ser menor al de algunos activos por separado. Esto es consistente con el principio de diversificación: al combinar activos que no se mueven de forma perfectamente sincronizada, el riesgo total puede reducirse, aun cuando cada activo individualmente tenga una volatilidad considerable.

3.3 2.3 Índice de Sharpe anualizado

El índice de Sharpe permite medir la relación entre el rendimiento excedente del portafolio frente a la tasa libre de riesgo y el riesgo asumido:

Sharpe = (mu_portafolio - rf) / sigma_portafolio.

dias_por_anio <- 252

# Medias diarias históricas (activos y portafolio)
mu_diaria_activos <- colMeans(R)
mu_diaria_port    <- mean(R_port_hist)

# Anualización de medias y volatilidades
mu_anual_activos    <- (1 + mu_diaria_activos)^dias_por_anio - 1
mu_anual_port       <- (1 + mu_diaria_port)^dias_por_anio - 1

sigma_anual_activos <- sigma_diaria_activos * sqrt(dias_por_anio)
sigma_anual_port    <- sigma_diaria_port * sqrt(dias_por_anio)

# Índice de Sharpe para cada activo y para el portafolio
Sharpe_activos <- (mu_anual_activos - rf_anual) / sigma_anual_activos
Sharpe_port    <- (mu_anual_port    - rf_anual) / sigma_anual_port

Sharpe_activos
##   ret_MSFT    ret_NKE    ret_NEE 
##  1.0021969 -0.5742998  0.8438984
Sharpe_port
## [1] 1.016129

3.3.1 Análisis del índice de Sharpe

El índice de Sharpe compara el rendimiento excedente sobre la tasa libre de riesgo con la volatilidad asumida. Un Sharpe más alto indica que el inversor está siendo mejor compensado por cada unidad de riesgo asumido.

En este caso, se utilizó una tasa libre de riesgo del 4 % anual, correspondiente al bono del Tesoro estadounidense a 10 años. Al calcular el Sharpe para cada acción y para el portafolio, se observa si la combinación de activos ofrece una relación retorno/riesgo más eficiente que las inversiones individuales.

Si el índice de Sharpe del portafolio supera al de la mayoría de los activos, se concluye que la estrategia de diversificación no solo reduce la volatilidad, sino que también mejora la calidad del retorno ajustado por riesgo. En cambio, si el portafolio presenta un Sharpe inferior, ello sugeriría que la selección de pesos o de activos podría ser revisada para alcanzar una asignación más eficiente.

3.4 2.4 Precios esperados por trimestre a partir de la simulación MGB

A partir de la simulación MGB realizada en la parte 1, se estiman los precios esperados de cada activo y del portafolio al cierre de cada trimestre durante los dos años simulados.

# Un trimestre ≈ 252 / 4 ≈ 63 días
dias_trimestre <- round(dias_por_anio / 4)

# Tabla de trimestres desde t=0 hasta el final de los 2 años (8 trimestres)
trimestres <- tibble(
  trimestre = 0:(anios * 4),
  dia       = pmin(trimestre * dias_trimestre, N)
) %>%
  mutate(indice = dia + 1)  # +1 porque en S_sim y V el índice de tiempo arranca en 1

trimestres
## # A tibble: 9 × 3
##   trimestre   dia indice
##       <int> <dbl>  <dbl>
## 1         0     0      1
## 2         1    63     64
## 3         2   126    127
## 4         3   189    190
## 5         4   252    253
## 6         5   315    316
## 7         6   378    379
## 8         7   441    442
## 9         8   504    505
n_act <- length(tickers)

# Precios esperados por activo (media de las simulaciones)
precios_esp_activos <- map_dfc(1:n_act, function(j) {
  # extraer precios simulados en los índices de los trimestres
  S_trimestral <- S_sim[trimestres$indice, , j]
  S_trimestral <- matrix(S_trimestral,
                         nrow = nrow(trimestres),
                         ncol = n_sim)
  apply(S_trimestral, 1, mean)
})

colnames(precios_esp_activos) <- paste0("E_", tickers)

# Precio esperado del portafolio (media de V en los trimestres)
V_trimestral <- V[trimestres$indice, ]
V_trimestral <- matrix(V_trimestral,
                       nrow = nrow(trimestres),
                       ncol = n_sim)

precio_port_esp <- apply(V_trimestral, 1, mean)

tabla_trimestres <- bind_cols(
  trimestres %>% select(trimestre, dia),
  precios_esp_activos,
  tibble(E_Portafolio = precio_port_esp)
)

tabla_trimestres
## # A tibble: 9 × 6
##   trimestre   dia E_MSFT E_NKE E_NEE E_Portafolio
##       <int> <dbl>  <dbl> <dbl> <dbl>        <dbl>
## 1         0     0   514.  61.2  81.7         323.
## 2         1    63   515.  61.2  81.7         323.
## 3         2   126   515.  61.2  81.8         323.
## 4         3   189   515.  61.2  81.8         323.
## 5         4   252   515.  61.2  81.8         323.
## 6         5   315   515.  61.1  81.8         323.
## 7         6   378   515.  61.1  81.8         323.
## 8         7   441   515.  61.1  81.8         323.
## 9         8   504   515.  61.0  81.8         323.

3.4.1 Comportamiento esperado del portafolio por trimestre

El análisis de precios esperados por trimestre, derivado de la simulación MGB, permite trasladar la información diaria a un horizonte más relevante para la toma de decisiones financieras y la estructura de pagos trimestrales de las opciones que se utilizarán en la cobertura.

La serie de valores esperados del portafolio por trimestre muestra la trayectoria promedio anticipada de la inversión. Si la serie es claramente ascendente, puede interpretarse como una valorización esperada del portafolio, coherente con los retornos positivos estimados. Por el contrario, una trayectoria plana o con ligera tendencia a la baja reflejaría un entorno de menor crecimiento esperado o incluso de corrección en el mercado.

Este análisis resulta clave porque conecta la dinámica simulada del subyacente con el diseño temporal de los instrumentos de cobertura, los cuales suelen liquidarse de forma trimestral.

3.5 2.5 VaR al 1 % y 5 % (histórico y simulado)

Para evaluar el riesgo de pérdidas extremas, se calcula el Valor en Riesgo (VaR) del portafolio:

  • VaR histórico diario al 1 % y 5 % usando los retornos observados.
  • VaR simulado a un trimestre usando las trayectorias generadas por el MGB.
# Serie de retornos diarios del portafolio en formato xts
R_port_xts <- xts::xts(R_port_hist,
                       order.by = ret_diarios$date)
colnames(R_port_xts) <- "Portafolio"

# VaR histórico al 1 % (nivel de confianza 99 %) y 5 % (95 %)
VaR_1_hist <- VaR(R_port_xts,
                  p      = 0.99,
                  method = "historical")   # cola izquierda 1 %
VaR_5_hist <- VaR(R_port_xts,
                  p      = 0.95,
                  method = "historical")   # cola izquierda 5 %

VaR_1_hist
##      Portafolio
## VaR -0.03155147
VaR_5_hist
##      Portafolio
## VaR -0.01753038

El VaR histórico al 1 % indica la pérdida máxima diaria que no se espera superar más que en el 1 % de los peores días observados en la muestra. De forma análoga, el VaR al 5 % representa la pérdida máxima diaria con un nivel de confianza del 95 %.

# Primer trimestre: del tiempo inicial (trimestre 0) al final del trimestre 1
ind_inicio <- trimestres$indice[1]
ind_fin    <- trimestres$indice[2]

# Retorno del portafolio en el primer trimestre para cada simulación
ret_q1_sim <- V[ind_fin, ] / V[ind_inicio, ] - 1   # vector de longitud n_sim

# VaR al 1 % y 5 % a un trimestre (cola izquierda)
VaR_1_sim <- -quantile(ret_q1_sim, 0.01)
VaR_5_sim <- -quantile(ret_q1_sim, 0.05)

VaR_1_sim
##         1% 
## 0.01518787
VaR_5_sim
##         5% 
## 0.01004976

3.5.1 Análisis del VaR histórico y simulado

El Valor en Riesgo (VaR) proporciona una medida cuantitativa de las pérdidas extremas que podrían ocurrir con baja probabilidad. El VaR histórico diario al 1 % y al 5 % refleja las pérdidas máximas observadas en la muestra bajo niveles de confianza del 99 % y 95 %, respectivamente. En otras palabras, solo en el 1 % o 5 % de los peores días se esperarían pérdidas superiores a esos valores.

Por otro lado, el VaR simulado a un trimestre se obtiene a partir de las trayectorias generadas mediante el modelo MGB para el portafolio. Este enfoque incorpora no solo la información histórica, sino también los supuestos del modelo sobre el comportamiento futuro de los precios. El VaR trimestral al 1 % y al 5 % indica la pérdida máxima esperada en ese horizonte, con los respectivos niveles de confianza.

La comparación entre el VaR histórico diario y el VaR trimestral simulado permite tener una visión más completa del riesgo: el primero está anclado en la experiencia pasada, mientras que el segundo incorpora escenarios futuros generados estocásticamente. Si ambos valores son consistentes (es decir, ninguno resulta desproporcionadamente más alto o más bajo), se refuerza la credibilidad del modelo. En caso contrario, podría ser necesario revisar los supuestos de volatilidad, correlaciones o el horizonte temporal considerado.

4 3. Valuación de opciones y estrategia de cobertura

En esta sección se valúan opciones europeas y americanas de tipo call y put para cada uno de los tres activos (MSFT, NKE, NEE), y se diseña una estrategia de cobertura que protege el 85 % de la inversión total, apalancada a la tasa libre de riesgo (4 %).

Se tendrá en cuenta la tasa de dividendo de cada empresa, siguiendo las instrucciones del enunciado, modelada como una tasa de dividendo continua (q).

4.1 3.1 Parámetros de opciones y tasas de dividendo

Supondremos un horizonte de 2 años para las opciones (coherente con el horizonte de simulación) y strikes at-the-money (cercanos al precio spot actual). Las tasas de dividendo son aproximadas y pueden ajustarse según la información de mercado.

# Horizonte de la opción (en años)
T_opt <- 2

# Strikes at-the-money: iguales al precio spot actual
K_vec <- S0
K_vec
##   MSFT    NKE    NEE 
## 514.33  61.23  81.69
# Volatilidades anuales de cada activo (desde el bloque de Sharpe)
sigma_anual_activos
##  ret_MSFT   ret_NKE   ret_NEE 
## 0.2208382 0.3721248 0.2807909
sigma_vec <- sigma_anual_activos  # renombrar para claridad

# Tasas de dividendo anuales aproximadas (continuas)
q_vec <- c(MSFT = 0.008,   # ~0.8 % anual
           NKE  = 0.009,   # ~0.9 % anual
           NEE  = 0.025)   # ~2.5 % anual

q_vec
##  MSFT   NKE   NEE 
## 0.008 0.009 0.025

4.1.1 Comentario financiero

El uso de tasas de dividendo continuas (q) permite ajustar el modelo de Black–Scholes–Merton al hecho de que algunas acciones reparten dividendos periódicamente. Un mayor dividendo tiende a reducir el precio teórico de las opciones call (ya que parte del valor futuro se distribuye en efectivo) y a incrementar el valor relativo de las opciones put.

4.2 3.2 Valuación de opciones europeas (Black–Scholes–Merton con dividendos)

A continuación se implementa el modelo de Black–Scholes–Merton con dividendos continuos para valuar opciones europeas call y put.

# Función de Black-Scholes-Merton con dividendos continuos
bs_european_div <- function(type = c("call", "put"),
                            S0, K, r, q, sigma, T) {
  type <- match.arg(type)
  d1 <- (log(S0 / K) + (r - q + 0.5 * sigma^2) * T) / (sigma * sqrt(T))
  d2 <- d1 - sigma * sqrt(T)
  if (type == "call") {
    price <- S0 * exp(-q * T) * pnorm(d1) - K * exp(-r * T) * pnorm(d2)
  } else {
    price <- K * exp(-r * T) * pnorm(-d2) - S0 * exp(-q * T) * pnorm(-d1)
  }
  return(price)
}
# Calcular precios europeos call y put para cada activo
res_eur <- tibble(
  Activo = tickers,
  S0     = as.numeric(S0),
  K      = as.numeric(K_vec),
  sigma  = as.numeric(sigma_vec),
  q      = as.numeric(q_vec[tickers])
) %>%
  rowwise() %>%
  mutate(
    Call_Eur = bs_european_div("call", S0, K, rf_anual, q, sigma, T_opt),
    Put_Eur  = bs_european_div("put",  S0, K, rf_anual, q, sigma, T_opt)
  ) %>%
  ungroup()

res_eur
## # A tibble: 3 × 7
##   Activo    S0     K sigma     q Call_Eur Put_Eur
##   <chr>  <dbl> <dbl> <dbl> <dbl>    <dbl>   <dbl>
## 1 MSFT   514.  514.  0.221 0.008     77.8    46.4
## 2 NKE     61.2  61.2 0.372 0.009     14.0    10.4
## 3 NEE     81.7  81.7 0.281 0.025     13.2    10.9

4.2.1 Análisis de las opciones europeas

Las opciones call europeas valoradas con este modelo representan el derecho, mas no la obligación, de comprar la acción a un precio de ejercicio K al vencimiento de 2 años. Las opciones put otorgan el derecho de vender la acción al mismo strike.

En general, para un mismo activo:

  • Un mayor nivel de volatilidad (sigma) incrementa el valor tanto de calls como de puts, porque aumenta la probabilidad de movimientos extremos favorables.
  • Un mayor dividendo (q) reduce el valor de la call y aumenta relativamente la put, dado que los flujos por dividendo favorecen a quien mantiene la acción subyacente más que al tenedor de la opción call.
  • La tasa libre de riesgo (rf) afecta principalmente el valor presente del strike K, vía el descuento exponencial exp(-rf T).

Estos valores europeos servirán como referencia para comparar con las opciones americanas, que permiten ejercicio anticipado.

4.3 3.3 Valuación de opciones americanas (árbol binomial trimestral)

Para las opciones americanas se utiliza un modelo binomial recombinante con 8 pasos (un paso por trimestre durante 2 años). El ejercicio puede ocurrir en cualquier nodo del árbol, lo que las hace más valiosas (o al menos no menos valiosas) que las opciones europeas equivalentes.

# Función de valuación binomial para opciones americanas con dividendos
binom_american <- function(type = c("call", "put"),
                           S0, K, r, q, sigma, T, steps) {
  type <- match.arg(type)
  dt <- T / steps
  u  <- exp(sigma * sqrt(dt))
  d  <- 1 / u
  # Probabilidad neutral al riesgo ajustada por dividendos
  p  <- (exp((r - q) * dt) - d) / (u - d)

  # Precios del subyacente al vencimiento
  ST <- S0 * d^(0:steps) * u^(steps:0)

  # Payoff al vencimiento
  if (type == "call") {
    V <- pmax(ST - K, 0)
  } else {
    V <- pmax(K - ST, 0)
  }

  # Descuento hacia atrás
  disc <- exp(-r * dt)
  for (j in steps:1) {
    V <- disc * (p * V[2:(j + 1)] + (1 - p) * V[1:j])
    # Valores intrínsecos en el nodo (posible ejercicio anticipado)
    S_j <- S0 * d^(0:(j - 1)) * u^((j - 1):0)
    if (type == "call") {
      V_intr <- pmax(S_j - K, 0)
    } else {
      V_intr <- pmax(K - S_j, 0)
    }
    V <- pmax(V, V_intr)
  }
  return(V[1])
}
steps_binom <- 8  # 8 trimestres en 2 años

res_amer <- res_eur %>%
  rowwise() %>%
  mutate(
    Call_Amer = binom_american("call", S0, K, rf_anual, q, sigma, T_opt, steps_binom),
    Put_Amer  = binom_american("put",  S0, K, rf_anual, q, sigma, T_opt, steps_binom)
  ) %>%
  ungroup()

res_amer
## # A tibble: 3 × 9
##   Activo    S0     K sigma     q Call_Eur Put_Eur Call_Amer Put_Amer
##   <chr>  <dbl> <dbl> <dbl> <dbl>    <dbl>   <dbl>     <dbl>    <dbl>
## 1 MSFT   514.  514.  0.221 0.008     77.8    46.4      66.5    53.7 
## 2 NKE     61.2  61.2 0.372 0.009     14.0    10.4      20.4     8.50
## 3 NEE     81.7  81.7 0.281 0.025     13.2    10.9      18.0     9.07

4.3.1 Comparación europea vs americana

res_opc <- res_amer %>%
  select(Activo, S0, K, sigma, q, Call_Eur, Put_Eur, Call_Amer, Put_Amer)

res_opc
## # A tibble: 3 × 9
##   Activo    S0     K sigma     q Call_Eur Put_Eur Call_Amer Put_Amer
##   <chr>  <dbl> <dbl> <dbl> <dbl>    <dbl>   <dbl>     <dbl>    <dbl>
## 1 MSFT   514.  514.  0.221 0.008     77.8    46.4      66.5    53.7 
## 2 NKE     61.2  61.2 0.372 0.009     14.0    10.4      20.4     8.50
## 3 NEE     81.7  81.7 0.281 0.025     13.2    10.9      18.0     9.07

En teoría, para un mismo activo y parámetros:

  • La opción americana nunca vale menos que su equivalente europea, porque el ejercicio anticipado es un derecho adicional.
  • Esta diferencia suele ser más relevante en las puts americanas, especialmente cuando la acción paga dividendos o cuando el activo presenta caídas relevantes antes del vencimiento.
  • Para las calls sobre activos sin dividendos, el valor americano y europeo suele coincidir; con dividendos positivos, el valor americano puede ser ligeramente superior.

En el contexto de cobertura, las opciones americanas put son especialmente útiles, ya que permiten ejercer anticipadamente si el precio de la acción cae por debajo del strike antes del vencimiento, protegiendo de forma más flexible la inversión.

4.4 3.4 Cobertura del 85 % de la inversión con puts americanas

Se desea cubrir el 85 % de la inversión total de 10 millones de dólares utilizando opciones. Una estrategia clásica de cobertura de caída de precios es la compra de puts de protección (protective puts): el inversionista mantiene la posición larga en la acción y compra opciones put que fijan un precio mínimo de venta.

Primero, se calcula cuántas acciones de cada activo se desea cubrir (85 % de la cantidad total de acciones).

porc_cobertura <- 0.85

acciones_cubiertas <- cantidades * porc_cobertura
acciones_cubiertas
##      MSFT       NKE       NEE 
##  9284.285 13718.663 35314.231

Supondremos que la cobertura se realiza con puts americanas (Put_Amer), ya que ofrecen mayor flexibilidad que las europeas.

# Juntamos la información relevante en una tabla de cobertura
tabla_cobertura <- tibble(
  Activo            = tickers,
  Peso_Portafolio   = as.numeric(w_opt),
  S0                = as.numeric(S0),
  Cant_Acciones     = as.numeric(cantidades),
  Acciones_Cubiertas= as.numeric(acciones_cubiertas),
  Put_Amer          = res_opc$Put_Amer
) %>%
  mutate(
    Costo_Puts = Acciones_Cubiertas * Put_Amer,
    Notional_Cubierto = Acciones_Cubiertas * S0
  )

tabla_cobertura
## # A tibble: 3 × 8
##   Activo Peso_Portafolio    S0 Cant_Acciones Acciones_Cubiertas Put_Amer
##   <chr>            <dbl> <dbl>         <dbl>              <dbl>    <dbl>
## 1 MSFT            0.562  514.         10923.              9284.    53.7 
## 2 NKE             0.0988  61.2        16140.             13719.     8.50
## 3 NEE             0.339   81.7        41546.             35314.     9.07
## # ℹ 2 more variables: Costo_Puts <dbl>, Notional_Cubierto <dbl>

El costo total de la estrategia de cobertura con puts es:

costo_total_cobertura <- sum(tabla_cobertura$Costo_Puts)
costo_total_cobertura
## [1] 935188.4

Este costo se financia mediante apalancamiento a la tasa libre de riesgo (4 % anual). Si se considera un horizonte de 2 años, el valor futuro aproximado del costo de cobertura sería:

costo_futuro_cobertura <- costo_total_cobertura * (1 + rf_anual)^T_opt
costo_futuro_cobertura
## [1] 1011500

4.4.1 Análisis de la estrategia de cobertura

La estrategia de cobertura planteada consiste en:

  • Mantener la posición larga en las tres acciones, de acuerdo con los pesos del portafolio de mínima varianza.
  • Comprar opciones put americanas sobre cada activo, cubriendo el 85 % de la cantidad de acciones mantenidas.
  • Financiar el costo inicial de las puts mediante un préstamo al 4 % anual (tasa del bono del Tesoro a 10 años).

Desde el punto de vista financiero:

  1. Protección a la baja:
    Si el precio de alguna acción cae por debajo del strike K (aproximadamente el precio actual), la opción put entra in the money y la pérdida en el valor de la acción se ve compensada por la ganancia en la opción. Esto limita la pérdida máxima sobre el 85 % de la posición cubierta.

  2. Participación al alza:
    Si el precio de la acción sube por encima del strike, las puts expiran out of the money y se pierde la prima pagada, pero el inversionista se beneficia de la apreciación del subyacente. Así, la estrategia mantiene exposición a ganancias, a costa de un costo de seguro.

  3. Costo de la cobertura y apalancamiento:
    El costo total de las primas de las puts representa el “seguro” por la protección. Al financiar dicho costo con deuda al 4 % anual, se incrementa el apalancamiento del portafolio. Este apalancamiento genera un compromiso de pago futuro (costo_futuro_cobertura), que debe ser comparado con el beneficio de la reducción de riesgo: si el mercado efectivamente presenta caídas fuertes, la cobertura puede ahorrar pérdidas mucho mayores que el costo financiado de las opciones.

  4. Reparto del dinero apalancado entre activos:
    El reparto de la cobertura se hace proporcional a las cantidades de acciones y a los pesos del portafolio, es decir, cada activo recibe una parte del “presupuesto de cobertura” acorde a su importancia en la inversión total. De esta manera, la protección es coherente con la estructura del portafolio: los activos más representativos en términos de valor reciben una proporción mayor de opciones de cobertura.

En resumen, la estrategia de puts americanas apalancadas al 4 % anual permite transformar el perfil de riesgo del portafolio: se limita la pérdida potencial en escenarios adversos a cambio de pagar (y financiar) una prima de seguro. Esta lógica es consistente con la gestión moderna de riesgo: sacrificar una fracción del retorno esperado para reducir la probabilidad de pérdidas extremas sobre el capital invertido.

4.5 3.5 Construcción del árbol binomial para MSFT

Aunque el modelo binomial se utilizó previamente para valuar las opciones americanas, es importante visualizar explícitamente la estructura del árbol binomial, ya que esta representa de forma gráfica la evolución posible del precio del subyacente y el proceso de valuación hacia atrás.

A continuación se construye el árbol binomial recombinante de 8 pasos trimestrales para la acción MSFT, usando los mismos parámetros de volatilidad, tasa libre de riesgo y dividendo empleados en la valuación de opciones.

library(dplyr)
library(tidyr)

# Asegurar nombres correctos de las volatilidades
names(sigma_anual_activos) <- tickers

# Parámetros para MSFT
steps_binom <- 8
T_opt       <- 2
sigma_msft  <- as.numeric(sigma_anual_activos["MSFT"])
S0_msft     <- as.numeric(S0["MSFT"])

dt_bin <- T_opt / steps_binom
u_msft <- exp(sigma_msft * sqrt(dt_bin))
d_msft <- 1 / u_msft

# Árbol completo de nodos (sin bucles)
tree_df <- expand_grid(
  step = 0:steps_binom,
  i    = 0:steps_binom
) %>%
  filter(i <= step) %>%                              # sólo nodos válidos
  mutate(
    S = S0_msft * u_msft^(step - i) * d_msft^i,      # precio en cada nodo
    y = step - 2 * i                                 # posición vertical
  )

head(tree_df)
## # A tibble: 6 × 4
##    step     i     S     y
##   <int> <int> <dbl> <dbl>
## 1     0     0  514.     0
## 2     1     0  574.     1
## 3     1     1  461.    -1
## 4     2     0  641.     2
## 5     2     1  514.     0
## 6     2     2  412.    -2

4.5.1 Interpretación financiera del árbol binomial

Cada nodo del árbol representa un precio posible de MSFT en un trimestre específico, partiendo del precio actual \(S_0\). En cada paso, el precio puede subir multiplicándose por \(u\) o bajar multiplicándose por \(d\). Las probabilidades neutras al riesgo \(p\) y \(1-p\) se utilizan para valuar las opciones bajo la medida neutral al riesgo, consistente con la tasa libre de riesgo y los dividendos.

Sobre esta misma estructura de precios se calculan los valores de la opción americana (call o put) usando un procedimiento de inducción hacia atrás:

  1. En el vencimiento (paso 8) se evalúa el valor intrínseco de la opción en cada nodo (por ejemplo, \((K - S_T, 0)\) para una put).
  2. En cada nodo anterior se calcula el valor esperado descontado bajo la medida neutral al riesgo.
  3. Para opciones americanas, en cada nodo se toma el máximo entre el valor de continuación y el valor por ejercicio anticipado, lo que justifica que el valor americano no sea menor al europeo.

Desde el punto de vista de cobertura, el árbol binomial permite visualizar cómo, a medida que el precio de MSFT evoluciona en el tiempo, la opción put de protección gana o pierde valor, compensando parcialmente las caídas del subyacente. Esto hace evidente la lógica de la cobertura dinámica: en escenarios de fuertes caídas (rama descendente del árbol), la put entra en el dinero y protege el valor de la inversión; en escenarios alcistas, la put expira sin valor, pero el inversionista se beneficia de la apreciación de la acción.

5 Conclusiones generales

A lo largo del laboratorio se desarrollaron tres etapas principales:

  1. Construcción del portafolio y simulación MGB:
    Se seleccionaron tres acciones (MSFT, NKE y NEE) y se construyó un portafolio de mínima varianza para una inversión de 10 millones de dólares. Con base en retornos históricos desde el 01/10/2023 se estimaron los parámetros de media y covarianza, y se simuló la evolución del portafolio bajo un Movimiento Browniano Geométrico durante dos años.

  2. Análisis de riesgo y desempeño:
    Se evaluó la volatilidad diaria y anual, el índice de Sharpe, los precios esperados por trimestre y el Valor en Riesgo (VaR) tanto histórico como simulado. Estos resultados permitieron caracterizar el perfil de riesgo-retorno del portafolio, identificando el impacto de la diversificación y cuantificando las pérdidas extremas esperadas en distintos horizontes.

  3. Valuación de opciones y cobertura del 85 %:
    Se valúan opciones europeas y americanas call y put para cada activo, incorporando la tasa libre de riesgo del 4 % y tasas de dividendo continuas. Con las opciones put americanas se diseña una estrategia de cobertura que protege el 85 % de la inversión, financiando el costo de las primas mediante apalancamiento a la tasa del bono del Tesoro. El análisis muestra cómo esta estrategia acota la pérdida máxima del portafolio ante choques negativos, manteniendo al mismo tiempo la posibilidad de participar en las ganancias si el mercado se recupera.

Desde el punto de vista financiero, el laboratorio integra los componentes clave de la gestión de portafolios y derivados: selección eficiente de activos, modelación estocástica de precios, medición de riesgo y diseño de coberturas utilizando opciones. Esto proporciona una visión completa de cómo un ingeniero financiero puede combinar herramientas cuantitativas y criterios de mercado para tomar decisiones de inversión más robustas frente a la incertidumbre.