Introducción

La práctica consiste en la estructuración de un portfolio de inversión entre 3 activos, en donde se realiza medidas de rentabilidad y riesgo para simular, mediante el Movimiento Browniano Geométrico, los precios diarios hasta los próximos dos años. Mediante el análisis del riesgo se plantea hacer uso de derivados con opciones tanto europeas como americanas para cubrir caídas de precios con una metodología basada en precios de cierre a trimestre.

Instalación y/o activación de librerías necesarias

library(tidyquant)
library(plotly) 
library(timetk)
library(tidyr)
library(forcats)
library(tidyverse)
library(ggplot2)
library(reshape2)

Definir activos para la estructuración del portafolio

Se eligieron las acciones Cheniere Energy, Inc. (LNG), Meta Platforms, Inc. (META) y NMI Holdings, Inc. (NMIH) para la construcción del portafolio teniendo en cuenta un análisis descriptivo y fundamental para la compra de activos, lo cuál bajo la teoría de la estructuración de un portafolio, lo ideal es comprar activos que se encuentren subvalorados en el mercado.

La siguiente información utilizada para hacer este análisis para la selección de los activos, fue de forma complementaria entre los sitios web Finviz (s.f.) y Yahoo Finance (s.f.).

Cheniere Energy, Inc. (LNG)

A pesar de que en el enunciado anterior se mencionaba la importancia de incluir activos subvalorados para la estrcuturación del portafolio, se obtuvo que:

  • P/E= 16.3, Esto podría indicar que el activo se encuentra ligeramente subvalorado ya que el promedio del mercado es aproximadamente de 20, si lo comparamos con el S&P500.

  • Forward P/E= 19.3, Esto podría indicarnos un factor de crecimiento moderado pero asociado a un mayor riesgo financiero.

  • PEG= 2, nos confirma que la acción no es un activo atractivo para comprar en función de su crecimiento esperado.

Estos indicadores nos dice que de por sí no es una acción totalmente atractiva si se quiere comprar una acción completamente subvalorada, ya que su precio actual refleja el crecimiento que ha tenido. Sin embargo, teniendo en cuenta que compañía se encuentra en el sector energético, dadas las expectativas de mercado de crecimiento moderado y que esto es confirmado por el análisis fundamental, podemos concluir que esta acción se encuentra en un punto medio en donde hay expectativas de crecimiento, pero moderadas y se incluyen para brindarle un factor de estabilidad al portafolio.

Meta Platforms, Inc. (META)

Para el caso de esta acción, se quiso incluir una empresa mega cap, con el fin de de tener mayor estabilidad y onbtener menores impactos antes movimientos fuertes del mercado.

Uno de los puntos más actractivos para escogerla fue que su Gross Marging= 81,68%, lo cual es beneficioso en términos de generar utilidades en casos adversos y es atractivo para la reinversión. Además:

  • ROI= 27,07%, esto indica un modelo de negocio rentable en terminos de inversión lo cuál termina siendo atractivo para los inversionistas ya que se está generando altos retornos sobre el capital invertido.

  • P/FCF= 23.5, es un valor elevado teniendo en cuenta que META se encuentra en el sector tecnológico y este presenta un mayor crecimiento, por lo cuál es un valor esperado, por lo tanto no denota sobrevaloración y puede considerarse moderado.

Es un activo pensado para el largo plazo, con una gran estabilidad y con un crecimiendo moderado, ya que esta compañía en este punto ya superó la curva de un crecimiento exponencial. Teniendo en cuenta que es una inversión a 2 años, con bajo apalancamiento y un buen nivel de ROI es una opción atractiva en términos de estabilidad.

NMI Holdings, Inc. (NMIH)

Finalmente, se decide incluir una acción que se encuentre totalmente subvalorada, ya que la estabilidad y el crecimiento esperado se encuentra cubierto por las otras dos acciones que conformaran el portafolio. En el caso de NMIH, tenemos que:

El P/E= 7.82, es muy bajo a comparación del mercado lo cual es una oportunidad de compra. Por otro lado, el P/FCF= 7.03 lo cual denota que el mercado está valorando la acción por debajo de su capacidad de generar flujos de caja libre, es decir otra señal de subvaloración.

El crecimiento de sus rendimientos en los últimos 5 años han sido del 12,43% y el ROE= 17.38% lo cual da buenas señales sobre el manejo de la compañía y capacidad de obtener retornos sobre el capital propio. Posee un bajo apalancamiento del 0.19 haciendo que se mitigue de cierta forma el riesgo financiero ante escenarios de incrementos inflacionarios.

En definita, el portafolio se construye de dos empresas que hoy en día tienen una solidez definida y generarían un crecimiento más lento, ya que especificamente son acciones que no se encuentran subvaloradas, estando en un punto medio en donde hay expectativas de que su precio siga aumentando debido al sector en el que se encuentran. A su vez, se incluye un activo cuyo análisis fundamental explica que la acción se encuentra subvalorada y se recomienda su compra, el único aspecto negativo, es que NMIH es una compañía del sector financiero y este sector a pesar de ser estable, no tiene unas grandes expectativas de crecimiento ya que su comportamiento es cíclico por definición.

¿Para quién va dirigido este portafolio?

Para aquellos inversionistas que desean un crecimiento estable y pensado en el largo plazo debido a las características de las acciones incluidas para este portafolio. El inversionista debe considerar la proyección en el sector energético, tecnológico y financiero, para determinar si estos sectores cumplen sus expectativas en términos de rentabilidad y riesgo.

Construcción del portafolio

Se tomará información histórica de los precios de LNG, META y NMIH desde 01/06/2022 hasta el 31/03/2025.

tick <- c('LNG', 'NMIH', 'META')

price_data <- tq_get(tick,from = '2022-06-01',to = '2025-03-31',get = 'stock.prices')

Grafica de serie historica de precios

#Graficar serie historica de precios
df_price <- price_data %>%
  select(symbol, date, adjusted) %>%
  pivot_wider(names_from = symbol, values_from = adjusted) %>%
  arrange(date)

# Ajustar los márgenes para dar espacio a la leyenda
par(mar = c(5, 4, 4, 8), xpd = TRUE)  

# Graficar con matplot
matplot(df_price[, -1], type = "l", lty = 1, col = 1:(ncol(df_price) - 1),ylab = "Precios en USD")

# Agregar la leyenda fuera del gráfico
legend("topright", inset = c(-0.3, 0), legend = colnames(df_price)[-1], 
       col = 1:(ncol(df_price) - 1), lty = 1, bty = "n")

Calcular rentabilidad y riesgo de cada acción

Calcular rendimientos diarios

La idea de calcular los rendimientos y su riesgo tiene dos propósitos:

1. Conocer estas métricas individualmente para identificar como se comportan a diario y lo que debe de tener en cuenta el inversionista día a día

2. Anualizar el promedio de los rendimientos y el riesgo para calcular el Ratio Sharpe, lo cual nos permitirá construir el portafolio de media varianza (maximización del Ratio Sharpe)

#Calcular rendimientos diarios
rendimientos_RCC <- price_data %>%
  group_by(symbol) %>%
  tq_transmute(select = adjusted, mutate_fun = periodReturn, period = 'daily', 
               col_rename = 'RCC', type = 'log')

#Visualizar datos
head(rendimientos_RCC)
## # A tibble: 6 × 3
## # Groups:   symbol [1]
##   symbol date            RCC
##   <chr>  <date>        <dbl>
## 1 LNG    2022-06-01  0      
## 2 LNG    2022-06-02  0.0239 
## 3 LNG    2022-06-03 -0.00988
## 4 LNG    2022-06-06 -0.0138 
## 5 LNG    2022-06-07  0.0436 
## 6 LNG    2022-06-08 -0.0282

Es conveniente organizar los rendimientos agrupandolos por acciones mediante columnas

#Ordenar acciones de filas a columnas
RCC_ordenado <- rendimientos_RCC %>%
  pivot_wider(names_from = symbol, values_from = RCC)

Rendimientos, riesgo diarios y anualizar

#Calcular promedio y desviación diaria de los rendimientos

mean_daily <- colMeans(RCC_ordenado[, -1], na.rm = TRUE)
print(mean_daily)
##          LNG         NMIH         META 
## 0.0007159258 0.0009306345 0.0015828676
sd_daily <- apply(RCC_ordenado[, -1], 2, sd, na.rm = TRUE)
print(sd_daily)
##        LNG       NMIH       META 
## 0.01831020 0.01701104 0.02763702
#Calcular matriz de covarianzas y anualizar
RCC_ordenado<-RCC_ordenado[,-1]
cov_mat <- cov(RCC_ordenado) * 252
print(round(cov_mat,4))
##         LNG   NMIH   META
## LNG  0.0845 0.0213 0.0058
## NMIH 0.0213 0.0729 0.0266
## META 0.0058 0.0266 0.1925

Optimización del portafolio

Para este proceso de optimización, nos interesa llegar al cálculo y la construcción de un portafolio basado en Ratio Sharpe, por lo que, se debe de tener en cuenta lo siguiente:

Cálculo del Ratio Sharpe

Para el cálculo del Ratio Sharpe se debe de tener en cuenta la tasa libre riesgo basada en los bonos del tesoro Tbond U.S. Department of the Treasury. (2025). Daily Treasury Real Yield Curve Rates – March 2025. La tasa a fecha del 31/03/2025 se encontraba a 1,38% en términos anuales con capitalización semestral, por lo cual se debía hacer una conversión para manejarlo en términos EA.

Recuperado de: https://home.treasury.gov/resource-center/data-chart-center/interest-rates/TextView?type=daily_treasury_real_yield_curve&field_tdr_date_value_month=202503

#Convertir tasa libre de riesgo a EA
tbond_5yr=0.0138
rf<-(1+(tbond_5yr/2))^2-1

El proceso a seguir es construir un portafolio con pesos aleatorios, visualizar los cambios al optimizar un portafolio de minima varianza, para finalmente obtener optimizar el portafolio maximizando el Ratio Sharpe (Portafolio de media-varianza).

Es necesario crear el objeto que almacenará los valores del portafolio que contendrá los pesos, rendimientos y riesgos anualizados y el Ratio Sharpe.

#Crear matriz y vectores vacios
num_port <- 5000

pesos1 <- matrix(nrow = num_port, ncol = length(tick))

port_returns <- vector('numeric', length = num_port)

port_risk <- vector('numeric', length = num_port)

sharpe_ratio <- vector('numeric', length = num_port)

#Generar bucle
for (i in seq_along(port_returns)) {
  
  pesos <- runif(length(tick))
  pesos <- pesos/sum(pesos)
  
  #Almacenar peso en la matriz
  pesos1[i,] <- pesos
  
  #Retorno del portafolio
  
  port_ret <- sum(pesos * mean_daily)
  port_ret <- ((port_ret + 1)^252) - 1
  
  #Almacenar retorno del portafolio
  port_returns[i] <- port_ret
  
  
  #Crear y almacenar riesgo del portafolio
  port_sd <- sqrt(t(pesos) %*% (cov_mat  %*% pesos))
  port_risk[i] <- port_sd
  
  #Crear y almacenar riesgo del portafolio
  
  sr <- (port_ret-rf)/port_sd
  sharpe_ratio[i] <- sr
  
}

#Almacenar valores en una tabla
portfolio_values <- tibble(Return = port_returns,
                           Risk = port_risk,
                           SharpeRatio = sharpe_ratio)


#Convertir una matriz en un tibble y cambiar los nombres de las columnas
pesos1 <- tk_tbl(pesos1)

colnames(pesos1) <- colnames(RCC_ordenado)

#Combinar todos los valores juntos
portfolio_values <- tk_tbl(cbind(pesos1, portfolio_values))

head(portfolio_values)
## # A tibble: 6 × 6
##     LNG   NMIH  META Return  Risk SharpeRatio
##   <dbl>  <dbl> <dbl>  <dbl> <dbl>       <dbl>
## 1 0.407 0.462  0.131  0.264 0.211        1.18
## 2 0.389 0.438  0.173  0.274 0.211        1.23
## 3 0.344 0.393  0.263  0.296 0.216        1.30
## 4 0.510 0.344  0.146  0.260 0.214        1.15
## 5 0.234 0.101  0.665  0.392 0.311        1.22
## 6 0.574 0.0301 0.396  0.308 0.249        1.18

Portafolio con pesos aleatorios

La maximización de este ratio nos da como resultado la mejor combinación retorno-riesgo y se encuentra en la frontera eficiente. Este ratio lo que hace es maximizar el rendimiento esperado para cierto nivel de riesgo.

#Calcular pesos aleaorios de inversion
pesos <- runif(n = length(tick))
print(pesos)
## [1] 0.13825701 0.66515914 0.02134979
#La suma de los pesos debe de ser igual a 1 
pesos<-pesos/sum(pesos)
print(pesos)
## [1] 0.16763181 0.80648231 0.02588588
#Calcular rendimientos anualizados del portafolio
rend_portafolio <- (sum(pesos * mean_daily) + 1)^252 - 1

#Calcular riesgo del portafolio
riesgo_portafolio<-sqrt(t(pesos) %*% (cov_mat %*% pesos))

#Calculo del ratio sharpe
tbond_5yr=0.0138
rf<-(1+(tbond_5yr/2))^2-1
ratio_sharpe<-(rend_portafolio-rf)/riesgo_portafolio
print(ratio_sharpe)
##          [,1]
## [1,] 1.024478

Portafolio de mínima varianza con sus respectivos pesos

Este portafolio se optimiza con la finalidad de obtener el menor riesgo posible y a este nivel de riesgo obtener la mayor rentabilidad esperada.

#Poratfolio de mínima varianza (Minimizar el portafolio)
min_var <- portfolio_values[which.min(portfolio_values$Risk),]
print(min_var)
## # A tibble: 1 × 6
##     LNG  NMIH  META Return  Risk SharpeRatio
##   <dbl> <dbl> <dbl>  <dbl> <dbl>       <dbl>
## 1 0.406 0.433 0.162  0.270 0.211        1.21
print(sd_daily*sqrt(252))
##       LNG      NMIH      META 
## 0.2906654 0.2700419 0.4387241
p_minima_varianza <- min_var %>%
  gather(LNG:META, key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Assets', y = 'Weights', title = "Portafolio de mínima varianza") +
  scale_y_continuous(labels = scales::percent) 

ggplotly(p_minima_varianza)

Lo interesante con este tipo de optimización es que se logra un nivel de riesgo más bajo a que si se invirtiera todo el capital en el activo de menor riesgo.

Sin embargo, si se optimizara el portafolio para obtener el mayor rendimiento esperado, se obtendría que se debe invertir el 100% del capital en el activo de mayor rendimiento, por definición.

Pesos obtenidos al estructurar el portafolio de media-varianza (Maximización del Ratio Sharpe)

La elección estratégica de las 3 acciones que conforman el portafolio permitió al maximizar el Ratio Sharpe, obtener ponderaciones equilibradas entre los activos, lo cuál es beneficioso para el término de la diversificación y lo cual tiene como efecto una menor exposición al riesgo.

La maximización del Ratio Sharpe nos permite llegar a ese punto en donde obtenemos la mayor rentabilidad tras asumir una unidad de riesgo, ya que a pesar de que se pueden constuir portafolios con mayor rentabilidad, llegan a un punto en donde se asume de manera proporcional un mayor riesgo que por un poco más de rentabilidad, lo cuál deja de ser lo adecuado según la teoría Bailey, D. H., & López de Prado, M. M. (2012).

#Portafolio de media varianza (Maximizar ratio sharpe)
max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]
p_media_varianza <- max_sr %>%
  gather(LNG:META, key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Acciones', y = 'Pesos', title = "Portafolio de media varianza") +
  scale_y_continuous(labels = scales::percent) 
print(max_sr)
## # A tibble: 1 × 6
##     LNG  NMIH  META Return  Risk SharpeRatio
##   <dbl> <dbl> <dbl>  <dbl> <dbl>       <dbl>
## 1 0.237 0.399 0.365  0.325 0.234        1.33
ggplotly(p_media_varianza)

Al maximizar el Ratio Sharpe, significa que por cada unidad de riesgo, recibimos 1.3 en exceso de retorno. Esta medida es considerada balanceada y eficiente ya que el exceso de retorno obtenido es mayor al nivel de riesgo que se asume.

Frontera eficiente

La frontera eficiente es el límite de la curva que nos permite visualizar la cantidad infinita de combinaciones óptimas para estructurar el portafolio.

#Graficar frontera eficiente
frontera_eficiente <- portfolio_values %>%
  ggplot(aes(x = Risk, y = Return, color = SharpeRatio)) +
  geom_point() +
  theme_classic() +
  scale_y_continuous(labels = scales::percent) +
  scale_x_continuous(labels = scales::percent) +
  labs(x = 'Riesgo anualizado',
       y = 'Rentabilidad anualizada',
       title = "Frontera eficiente con optimización del portafolio") +
  geom_point(aes(x = Risk,
                 y = Return), data = min_var, color = 'red') +
  geom_point(aes(x = Risk,
                 y = Return), data = max_sr, color = 'red') +
  annotate('text', x = 0.23, y = 0.45, label = "Portafolio de media varianza") +
  annotate('text', x = 0.25, y = 0.15, label = "Portafolio de mínima varianza") +
  annotate(geom = 'segment', x = 0.18, xend = 0.20,  y = 0.20, 
           yend = 0.24, color = 'red', arrow = arrow(type = "open")) +
  annotate(geom = 'segment', x = 0.22, xend = 0.2275,  y = 0.405, 
           yend = 0.365, color = 'red', arrow = arrow(type = "open"))

ggplotly(frontera_eficiente)

Hasta este punto se ha estructurado un portafolio de media-varianza, que cuenta con una distribución equilibrada en sus ponderaciones de invesión. Pero si comparamos la tasa libre de riesgo a comparación del riesgo que se asume en cada activo, por ejemplo en un activo como META que presenta mayor volatilidad, se presenta un riesgo de factores del mercado que hacen que el portafolio tenga un nivel de riesgo elevado (23.3% anual). Este valor según como se analice puede estar por debajo de volatilidades de otros activos, como también puede verse muy elevado y más si alguien no quiere asumir ese nivel de riesgo para obtener la rentabilidad ofrecida.

Simulación con el Movimiento Browniano Geométrico de cada acción

Teniendo en cuenta que se pueden calcular rentabilidades y riesgos anualizados para cada activo, es interesante conocer a partir de una simulación por medio del Movimiento Browniano Geomtétrico, para hacer un análisis de sensibilidad extremo de la evolución del precio diario del activo.

La inversión en este caso está contemplada para 2 años y se tomará el tiempo pensando en días bursátiles y para el ejercicio de simulación de precios de cada activo se hará con 5000 simulación de escenarios diferentes.

year<-252
T=504
N<-5000
dt<-1/year
#MBG para LNG
mean_LNG<-mean(RCC_ordenado$LNG)
rendimiento_LNG <- exp(mean_LNG * year) - 1
sigma_LNG=sqrt(var(RCC_ordenado$LNG)*year)
S0_LNG<-tail(df_price$LNG, 1)

MBG_LNG <- matrix(NA, nrow = T, ncol = N)
MBG_LNG[1, ] <- S0_LNG

for (i in 1:N) {
  for (t in 2:T) {
    MBG_LNG[t, i] <- MBG_LNG[t - 1, i] * exp((rendimiento_LNG - 0.5 * sigma_LNG^2) * dt +
                                               sigma_LNG * sqrt(dt) * qnorm(runif(1)))
  }
}

matplot(MBG_LNG,type="l")

#MBG para META
mean_META<-mean(RCC_ordenado$META)
rendimiento_META <- exp(mean_META * year) - 1
sigma_META=sqrt(var(RCC_ordenado$META)*year)
S0_META<-tail(df_price$META, 1)

MBG_META <- matrix(NA, nrow = T, ncol = N)
MBG_META[1, ] <- S0_META

for (i in 1:N) {
  for (t in 2:T) {
    MBG_META[t, i] <- MBG_META[t - 1, i] * exp((rendimiento_META - 0.5 * sigma_META^2) * dt +
                                                 sigma_META * sqrt(dt) * qnorm(runif(1)))
  }
}

matplot(MBG_META,type="l")

#MBG para NMIH
mean_NMIH<-mean(RCC_ordenado$NMIH)
rendimiento_NMIH <- exp(mean_NMIH * year) - 1
sigma_NMIH=sqrt(var(RCC_ordenado$NMIH)*year)
S0_NMIH<-tail(df_price$NMIH, 1)

MBG_NMIH <- matrix(NA, nrow = T, ncol = N)
MBG_NMIH[1, ] <- S0_NMIH

for (i in 1:N) {
  for (t in 2:T) {
    MBG_NMIH[t, i] <- MBG_NMIH[t - 1, i] * exp((rendimiento_NMIH - 0.5 * sigma_NMIH^2) * dt +
                                                 sigma_NMIH * sqrt(dt) * qnorm(runif(1)))
  }
}

matplot(MBG_NMIH,type="l")

Analisis de sensibilidad (Caso extremo)

La idea de hacer esta simulación en cada una de las acciones del portafolio, es tomar un escenario en donde el precio de la acción esté cayendo y con esto simular como se comporta el portafolio en cada cierre de precios en trimestre, por lo cual se asumirá intervalos de 63 días.

# Paso 1: Encontrar la trayectoria con menor valor final
col_LNG <- which.min(MBG_LNG[nrow(MBG_LNG), ])
col_META <- which.min(MBG_META[nrow(MBG_META), ])
col_NMIH <- which.min(MBG_NMIH[nrow(MBG_NMIH), ])

# Paso 2: Extraer la trayectoria completa
trayectoria_LNG <- MBG_LNG[, col_LNG]
trayectoria_META <- MBG_META[, col_META]
trayectoria_NMIH <- MBG_NMIH[, col_NMIH]

#Analisis trimestral
T_trimestres <- seq(1, T, by = 63)

# Extraer precios de cierre trimestrales
precios_trimestrales_LNG <- trayectoria_LNG[T_trimestres]
precios_trimestrales_META <- trayectoria_META[T_trimestres]
precios_trimestrales_NMIH <- trayectoria_NMIH[T_trimestres]

# Crear un data frame con los precios trimestrales
precios_trimestrales <- data.frame(
  Trimestre = 1:length(precios_trimestrales_LNG),
  LNG = precios_trimestrales_LNG,
  META = precios_trimestrales_META,
  NMIH = precios_trimestrales_NMIH
)

pesos_mediavarianza <- as.numeric(as.vector(max_sr[, c("LNG", "META", "NMIH")]))
precios_matriz <- as.matrix(precios_trimestrales[, c("LNG", "META", "NMIH")])

La simulación se construyó para 2 años, en donde equivalen 8 trimestres. La idea ahora es saber como se comporta el portafolio ante este tipo de escenarios y sin ningún tipo de cobertura.

# Multiplicar los precios trimestrales por los pesos óptimos
valor_portafolio_trimestral_unitario <- precios_matriz %*% pesos_mediavarianza
inversion<-1000000
precios_iniciales<-c(S0_LNG,S0_META,S0_NMIH)
cantidad_acciones<-(inversion*pesos_mediavarianza)/precios_iniciales
valor_portafolio_trimestral <- precios_matriz %*% cantidad_acciones


# Crear data frame
 df_valor_portafolio <- data.frame(
   Trimestre = 1:nrow(valor_portafolio_trimestral),
   Valor = as.vector(valor_portafolio_trimestral)
 )
 
 # Gráfico final sin formato científico ni separadores de miles
 ggplot(df_valor_portafolio, aes(x = Trimestre, y = Valor)) +
   geom_line(color = "#1f77b4", size = 1.3) +
   labs(
     title = "Evolución del Portafolio en Escenario Adverso",
     x = "Trimestre",
     y = "Valor del Portafolio"
   ) +
   scale_x_continuous(labels = function(x) format(x, scientific = FALSE, big.mark = "")) +
   scale_y_continuous(labels = function(y) format(y, scientific = FALSE, big.mark = "")) +
   theme_minimal(base_size = 14) +
   theme(
     plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
     axis.title = element_text(face = "bold"),
     axis.text = element_text(color = "gray30")
   )

En este caso extremo y que en términos de probabilidades, es poco probable que ocurra, se evidencia que ante un esecenario en donde no hay una cobertura que me proteja de las caídas de los precios, la inversión inicial que es de 1000000 USD se ve reducida por un mal desempeño del portafolio. Esto basado en terminos de la simulación que también tiene sus propios supuestos y volatilidades tan altas como la de META, generan no solo caídas sino subidas de precios elevadas en ciertas trayectorias.

Sin embargo, definiendo el término de volatilidad alta en acciones tanto individualmente como del portafolio en conjunto, demuestran que se asumen riesgos muy altos que pueden materializarse en este tipo de situaciones.

VaRes de la simulación al 1% y 5%

VaR de LNG

VaR_1_LNG <- quantile(MBG_LNG[T, ], 0.01)
VaR_5_LNG <- quantile(MBG_LNG[T, ], 0.05)
valores_VaR_LNG <- data.frame(Nivel = c("VaR 1%", "VaR 5%"), Valor = c(VaR_1_LNG, VaR_5_LNG)
)

print(valores_VaR_LNG)
##     Nivel    Valor
## 1% VaR 1% 113.8902
## 5% VaR 5% 154.4962

VaR de META

VaR_1_META <- quantile(MBG_META[T, ], 0.01)  # Cuantil al 1%
VaR_5_META <- quantile(MBG_META[T, ], 0.05)  # Cuantil al 5%
valores_VaR_META <- data.frame(Nivel = c("VaR 1%", "VaR 5%"), Valor = c(VaR_1_META, VaR_5_META)
)

print(valores_VaR_META)
##     Nivel    Valor
## 1% VaR 1% 296.4637
## 5% VaR 5% 456.0942

VaR de NMIH al 1% y 5%

VaR_1_NMIH <- quantile(MBG_NMIH[T, ], 0.01)
VaR_5_NMIH <- quantile(MBG_NMIH[T, ], 0.05)
valores_VaR_NMIH <- data.frame(Nivel = c("VaR 1%", "VaR 5%"), Valor = c(VaR_1_NMIH, VaR_5_NMIH)
)

print(valores_VaR_NMIH)
##     Nivel    Valor
## 1% VaR 1% 23.37893
## 5% VaR 5% 29.99465
  • El VaR de LNG representa en térmninos de precios, una caída entre 50% y 70% del precio actual de la acción, evidenciando un riesgo considerable en escenarios extremos.

  • El VaR de META representan una caída del precio entre el 50% y 80% con respecto al precio actual, indicando un riesgo más alto bajo condiciones adversas.

  • El VaR de NMIH es equivalente entre el 65%-84% del precio actual, lo que refleja una exposición mucho más significativa ante eventos extremos a comparación de las otras dos acciones.

Grafica del VaR al 1% y 5% de los activos del portafolio

# Crear data frame combinado para los tres activos
df_todos <- data.frame(
  Precio = c(MBG_META[T, ], MBG_LNG[T, ], MBG_NMIH[T, ]),
  Activo = rep(c("META", "LNG", "NMIH"), each = ncol(MBG_META))
)

# Crear data frame combinado con líneas de referencia
lineas_VAR <- data.frame(
  x = c(VaR_1_META, VaR_5_META, S0_META,
        VaR_1_LNG, VaR_5_LNG, S0_LNG,
        VaR_1_NMIH, VaR_5_NMIH, S0_NMIH),
  tipo = rep(c("VaR 1%", "VaR 5%", "Precio Inicial"), 3),
  Activo = rep(c("META", "LNG", "NMIH"), each = 3)
)

# Gráfico con facetas por activo
ggplot(df_todos, aes(x = Precio)) +
  geom_density(fill = "#cce5ff", alpha = 0.6, color = "blue", size = 1.2) +
  geom_vline(data = lineas_VAR, aes(xintercept = x, color = tipo), linetype = "dashed", size = 1.1) +
  scale_color_manual(values = c("VaR 1%" = "blue", "VaR 5%" = "green4", "Precio Inicial" = "red")) +
  labs(
    title = "Distribución Empírica del Precio Simulado por Activo",
    x = "Precio Simulado",
    y = "Densidad",
    color = "Líneas de Referencia"
  ) +
  facet_wrap(~ Activo, scales = "free") +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
    axis.title = element_text(face = "bold"),
    axis.text = element_text(color = "gray30"),
    legend.title = element_text(face = "bold"),
    legend.position = "top"
  ) +
  scale_y_continuous(labels = scales::comma_format())

Después de haber evidenciado los diferentes riesgos al simular los precios y mostrar un escenario extremo, a su vez, al demostrar las perdidas que se pueden generar a partir del portafolio dada la inversión y tambien como a nivel individual se pueden presentar casos extremos de baja probabilidad con grandes perdidas, es necesario pensar en una estrategia para cubrirse.

En los derivados existe un instrumento, el cual son las opciones y nos permite hacer coberturas ante escenarios específicos. Otra alternativa sería cambiar el portafolio por activos menos volatiles pero esto llevaría probablemente una reducción en cierta medida del rendimiento, por lo que si el portafolio es atractivo a nivel de rendimiento, pero preocupa el nivel de riesgo se puede emplear este instrumento para cubrirse.

Cubrimiento a partir de las opciones americanas y europeas

Para hacer uso de estas opciones es importante crear las funciones que me permitirán ingresar unos parámetros de entrada. Por lo tanto, las siguientes funciones me sirven para valorar opciones tanto americanas como europeas y a su vez, construir el arbol de precios.

# Función para la valuación de una opción europea
European_option = function(S, K, N, h, r, delta, u, d, psubir, pbajar, type) {
  stock_tree = stock_tree(S, N, u, d)
  option_tree = matrix(0, nrow=nrow(stock_tree), ncol=ncol(stock_tree))
  
  # Nodos terminales
  if(type == "call") {
    option_tree[nrow(option_tree), ] = pmax(stock_tree[nrow(stock_tree), ] - K, 0)
  } else if(type == "put") {
    option_tree[nrow(option_tree), ] = pmax(K - stock_tree[nrow(stock_tree), ], 0)
  }
  
  
  for(i in (nrow(option_tree)-1):1) {
    for(j in 1:i) {
      option_tree[i,j] = exp(-r * h) * (psubir * option_tree[i+1,j+1] + pbajar * option_tree[i+1,j])
    }
  }
  return(option_tree)
}

# Función para construir el árbol de precios
stock_tree = function(S, N, u, d) {
  tree = matrix(0, nrow=N+1, ncol=N+1)
  
  for(i in 1:(N+1)) {
    for(j in 1:i) {
      tree[i,j] = S * u^(j-1) * d^((i-1)-(j-1))
    }
  }
  return(tree)
}


#Función para la valuación de una opción americana
American_option = function(S, K, N, h, r, delta, u, d, psubir, pbajar, type) {
  stock_tree = stock_tree(S, N, u, d)
  option_tree = matrix(0, nrow = nrow(stock_tree), ncol = ncol(stock_tree))
  
  # Nodos terminales
  if (type == "call") {
    option_tree[nrow(option_tree), ] = pmax(stock_tree[nrow(stock_tree), ] - K, 0)
    
    # Revisión de ejercicio anticipado (call americana)
    for (i in (nrow(option_tree)-1):1) {
      for (j in 1:i) {
        NO = exp(-r * h) * (psubir * option_tree[i+1, j+1] + pbajar * option_tree[i+1, j])
        EX = pmax(stock_tree[i, j] - K, 0)
        option_tree[i, j] = max(NO, EX)
      }
    }
    
  } else if (type == "put") {
    option_tree[nrow(option_tree), ] = pmax(K - stock_tree[nrow(stock_tree), ], 0)
    
    # Revisión de ejercicio anticipado (put americana)
    for (i in (nrow(option_tree)-1):1) {
      for (j in 1:i) {
        NO = exp(-r * h) * (psubir * option_tree[i+1, j+1] + pbajar * option_tree[i+1, j])
        EX = pmax(K - stock_tree[i, j], 0)
        option_tree[i, j] = max(NO, EX)
      }
    }
  }
  
  return(option_tree)
}

Se trabajaran con unos supuestos para la valuación de opciones para hacer cobertura de la inversión del portafolio.

1. Se tiene un presupuesto de 850.000 USD para hacer compra de opciones y realizar una estrategia de cobertura

2. La tasa libre de riesgo se convertirá a trimestral continua

3. Se comprará en todos los casos una opción de venta Put para hacer un cubrimiento ante las caídas de los precios

4. Los precios strike estan determinados por la zona In the money, teniendo en cuenta la diferencia entre los precios bid y ask para determinar un mercado liquido, con alto interés y una menor volatilidad implícita en lo posible

rf_continua_trimestral<-log(1+rf)/4
dt<-63/252
periodos<-8
inversion_cobertura<-inversion*0.85
cantidad_acciones_cobertura<-(inversion_cobertura*pesos_mediavarianza)/precios_iniciales
valor_portafolio_trimestral_cobertura <- precios_matriz %*% cantidad_acciones_cobertura

Analizar caídas de precios y afectación al portafolio

print(precios_trimestrales)
##   Trimestre       LNG     META     NMIH
## 1         1 226.23000 576.7400 36.00000
## 2         2 154.16044 429.1114 35.33478
## 3         3 108.66933 343.1802 34.46755
## 4         4 100.17856 253.8332 28.74147
## 5         5  78.97424 300.7899 23.74417
## 6         6  82.62166 245.2843 22.57431
## 7         7  70.52824 210.1138 16.69711
## 8         8  63.45896 150.1591 12.80924
perdida_sin_cobertura <- diff(valor_portafolio_trimestral_cobertura)
print(perdida_sin_cobertura)
##            [,1]
## [1,] -149724.15
## [2,]  -94817.27
## [3,] -109462.28
## [4,]  -40637.11
## [5,]  -37602.73
## [6,]  -84963.60
## [7,]  -75100.74

Nota: Para considerar la cobertura que se obtiene con las opciones de venta Put se trabajará con una matriz de pérdidas/ganancias. En este caso como se tomaron trayectorias en caídas lo más normal es que se obtengan caídas y por ende pérdidas.

La idea es sumarle el Payoff obtenido al momento que se liquide la opción, ya sea si se usa opción americana y se puede sumar en el mismo periodo o en el caso de la opción europea, se suma en el último periodo.

Definir compra de paquete de opciones para cada activo

#Al momento de hacer cobertura con opciones, estas se venden por paquete y cada opcion contiene 100 acciones
cantidad_acciones_cobertura<-floor(cantidad_acciones_cobertura / 100) * 100

valor_portafolio_trimestral_cobertura <- precios_matriz %*% cantidad_acciones_cobertura

#Numero de acciones que tendrán cobertura
print(cantidad_acciones_cobertura)
## [1]  800  500 9400
#Valor del portafolio sin cobertura
print(valor_portafolio_trimestral_cobertura)
##          [,1]
## [1,] 807754.0
## [2,] 670031.0
## [3,] 582520.5
## [4,] 477229.3
## [5,] 436769.5
## [6,] 400938.0
## [7,] 318432.4
## [8,] 246253.6

Cantidad de paquetes de opciones a comprar

En EEUU, las opciones sobre acciones comúnmente se negocian en lotes estandarizados de 100 acciones por contrato, conforme a las especificaciones establecidas por la CBOE.Tampoco se encontró reportes de pago de dividendos que afecten el número de acciones negociadas por paquetes o algún acontecimiento anormal consultado desde la web de CBOE.

#Cantidad de paquetes a comprar
print(cantidad_acciones_cobertura/100)
## [1]  8  5 94

Arbol de precios LNG

#LNG
sigma_LNG_trimestral<-sigma_LNG*sqrt(dt)
su_LNG<-exp(sigma_LNG_trimestral*sqrt(dt))
sd_LNG<-1/su_LNG
dividendo_LNG<-0.0187/4
psubir_LNG<-(exp((rf_continua_trimestral-dividendo_LNG)*dt)-sd_LNG)/(su_LNG-sd_LNG)
pbajar_LNG<-1-psubir_LNG
peso_LNG<-pesos_mediavarianza[1]
q_LNG<-(peso_LNG*inversion_cobertura)/S0_LNG
KPut_LNG<-240

Se tomó el precio Strike (K) de un contrato de opción de venta Put en Yahoo Finance basado en términos de liquidez.

Fuente: Yahoo Finance (2025)
Fuente: Yahoo Finance (2025)

Se tomó el Precio Strike (K) de 240 ya que como se observa en la imagen es el que nos proporciona menor diferencia entre los precios Bid-Ask, lo cual es un índice de liquidez. Además se tiene un Open Interest alto, lo que también indica que efectivamente hay liquidez y que estamos ante probablemente un precio más justo.

# Valuación de PUT (comprada)
opcion_put_LNG <- American_option(S0_LNG, KPut_LNG,periodos, dt, rf_continua_trimestral, 
                                  dividendo_LNG, su_LNG, sd_LNG, psubir_LNG, pbajar_LNG, "put")

tree_LNG <- stock_tree(S0_LNG, periodos, su_LNG, sd_LNG)
# Asegurar que es matriz numérica
tree_LNG <- as.matrix(tree_LNG)
print(tree_LNG)
##           [,1]     [,2]     [,3]     [,4]     [,5]     [,6]     [,7]    [,8]
##  [1,] 226.2300   0.0000   0.0000   0.0000   0.0000   0.0000   0.0000   0.000
##  [2,] 210.3738 243.2813   0.0000   0.0000   0.0000   0.0000   0.0000   0.000
##  [3,] 195.6289 226.2300 261.6179   0.0000   0.0000   0.0000   0.0000   0.000
##  [4,] 181.9175 210.3738 243.2813 281.3364   0.0000   0.0000   0.0000   0.000
##  [5,] 169.1671 195.6289 226.2300 261.6179 302.5412   0.0000   0.0000   0.000
##  [6,] 157.3103 181.9175 210.3738 243.2813 281.3364 325.3443   0.0000   0.000
##  [7,] 146.2846 169.1671 195.6289 226.2300 261.6179 302.5412 349.8660   0.000
##  [8,] 136.0317 157.3103 181.9175 210.3738 243.2813 281.3364 325.3443 376.236
##  [9,] 126.4973 146.2846 169.1671 195.6289 226.2300 261.6179 302.5412 349.866
##           [,9]
##  [1,]   0.0000
##  [2,]   0.0000
##  [3,]   0.0000
##  [4,]   0.0000
##  [5,]   0.0000
##  [6,]   0.0000
##  [7,]   0.0000
##  [8,]   0.0000
##  [9,] 404.5936
# Convertir con melt
tree_df_LNG <- melt(tree_LNG, varnames = c("T", "Nodo"), value.name = "Precio")

# Quitar ceros o valores vacíos (nodos no existentes)
tree_df_LNG <- subset(tree_df_LNG, Precio > 0)

# Agregar una columna que identifique si el precio sube o baja respecto al nodo anterior
tree_df_LNG <- tree_df_LNG[order(tree_df_LNG$T, tree_df_LNG$Nodo), ]
tree_df_LNG$Movimiento <- ifelse(tree_df_LNG$Precio >= lag(tree_df_LNG$Precio, default = tree_df_LNG$Precio[1]), "Sube", "Baja")

#Grafico del arbol binomial precios
ggplot(tree_df_LNG, aes(x = T-1, y = Precio, color = Movimiento)) +
  geom_point(size = 3) +
  geom_text(aes(label = round(Precio, 2)), vjust = -0.5, size = 3) + 
  geom_line(aes(group = T), color = "gray") +
  scale_color_manual(values = c("Sube" = "green3", "Baja" = "red3")) +
  labs(title = "Árbol Binomial de Precios - LNG", x = "Trimestre", y = "Precio del activo", color = "Movimiento") +
  theme_light()

Valuación de opción put LNG

#Valor opcion PUT para LNG
valor_actual_put_LNG <- opcion_put_LNG[1,1]

option_df_put_LNG <- melt(opcion_put_LNG, varnames = c("T", "Nodo"), value.name = "Valor")
option_df_put_LNG <- subset(option_df_put_LNG, Valor > 0)
option_df_put_LNG <- option_df_put_LNG[order(option_df_put_LNG$T, option_df_put_LNG$Nodo), ]
option_df_put_LNG$Movimiento <- ifelse(option_df_put_LNG$Valor >= lag(option_df_put_LNG$Valor, default = option_df_put_LNG$Valor[1]), "Sube", "Baja")

ggplot(option_df_put_LNG, aes(x = T-1, y = Valor, color = Movimiento)) +
  geom_point(size = 3) +
  geom_text(aes(label = round(Valor, 2)), vjust = -0.5, size = 3) +
  geom_line(aes(group = T), color = "gray") +
  scale_color_manual(values = c("Sube" = "blue", "Baja" = "orange")) +
  labs(title = "Árbol Binomial - Valor Opción PUT LNG", x = "Trimestre", y = "Valor de la opción", color = "Movimiento") +
  theme_light()

En la gráfica se presentan los aumentos en el valor de las opciones debido a que como estamos en un Put, a medida de que el precio cae, el valor de la opción aumenta. Dado que se trata de una opción americana, se evalúa en cada nodo la posibilidad de ejercerla anticipadamente, lo cual explica los incrementos en valor frente a trayectorias bajistas. Esto resulta útil para cubrir caídas esperadas en el precio del activo, reduciendo así el riesgo del portafolio en escenarios adversos.

Es decir la Put gana valor conforme cae el precio del activo, y pierde valor cuando el precio sube.

Cobertura con opción americana en el trimestre 4 y 6

La estrategia de cobertura en este caso se fundamenta en que la opción americana nos permite ejercer anticipadamente lo cual es conveniente en esos trimestres ya que es donde se ve una mayor caída del precio. Como las opciones se adquieren en el instante en el primer trimestre, al tener un Precio Strike más alto y con las caídas pronunciadas del precio en esos periodos, permite obtener una mayor compensación.

#Cobertura con opcion americana en el trimestre 4
costo_cobertura_LNG=cantidad_acciones_cobertura[1]*valor_actual_put_LNG
print(costo_cobertura_LNG)
## [1] 21910.33
precio_LNG_t4 <- precios_trimestrales %>%
  filter(Trimestre == 4) %>%
  pull(LNG)

print(precio_LNG_t4)
## [1] 100.1786
compensacion_LNG_t4<-max(KPut_LNG-precio_LNG_t4,0)*cantidad_acciones_cobertura[1]-costo_cobertura_LNG
print(compensacion_LNG_t4)
## [1] 89946.82
compensacion_LNG_t4 <- matrix(c(0, 0, compensacion_LNG_t4, 0, 0, 0, 0), ncol = 1)

#Cobertura con opción americana en el trimestre 6
precio_LNG_t6 <- precios_trimestrales %>%
  filter(Trimestre == 6) %>%
  pull(LNG)

print(precio_LNG_t6)
## [1] 82.62166
compensacion_LNG_t6<-max(KPut_LNG-precio_LNG_t6,0)*cantidad_acciones_cobertura[1]-costo_cobertura_LNG
print(compensacion_LNG_t6)
## [1] 103992.3
compensacion_LNG_t6 <- matrix(c(0, 0, 0, 0, compensacion_LNG_t6, 0, 0), ncol = 1)

#Calcular la cobertura obtenida con las opciones ejercidas
perdida_con_cobertura_LNG=perdida_sin_cobertura+compensacion_LNG_t4+compensacion_LNG_t6

print(perdida_con_cobertura_LNG)
##            [,1]
## [1,] -149724.15
## [2,]  -94817.27
## [3,]  -19515.46
## [4,]  -40637.11
## [5,]   66389.61
## [6,]  -84963.60
## [7,]  -75100.74
### Cobertura con las opciones Put en LNG comparado con el portafolio sin cobertura

# Crear data frame con tramos
df_LNG <- tibble(
  Tramo = paste0("T", 1:7),
  Sin_cobertura = as.numeric(perdida_sin_cobertura),
  Con_cobertura = as.numeric(perdida_con_cobertura_LNG)
)

# Pasar a formato largo para ggplot
df_largo_LNG <- df_LNG %>%
  pivot_longer(cols = c(Sin_cobertura, Con_cobertura),
               names_to = "Tipo_de_Perdida",
               values_to = "Perdida")

# Reemplazar guiones bajos por espacios (opcional, por estética)
df_largo_LNG$Tipo_de_Perdida <- recode(df_largo_LNG$Tipo_de_Perdida,
                                   "Sin_cobertura" = "Sin cobertura",
                                   "Con_cobertura" = "Con cobertura")

# Crear gráfico
ggplot(df_largo_LNG, aes(x = Tramo, y = Perdida, fill = Tipo_de_Perdida)) +
  geom_bar(stat = "identity", position = "dodge") +
  scale_fill_manual(values = c("Sin cobertura" = "firebrick", "Con cobertura" = "steelblue")) +
  labs(
    title = "Comparación de pérdidas/ganancias por tramo - LNG",
    x = "Tramo",
    y = "Pérdida en USD",
    fill = "Tipo de Pérdida"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "right"
  )

Arbol de precios META

sigma_META_trimestral <- sigma_META * sqrt(dt)
su_META <- exp(sigma_META_trimestral * sqrt(dt))
sd_META <- 1 / su_META
dividendo_META <- 0.02 / 4
psubir_META <- (exp((rf_continua_trimestral - dividendo_META) * dt) - sd_META) / (su_META - sd_META)
pbajar_META <- 1 - psubir_META
peso_META <- pesos_mediavarianza[2]
q_META <- (peso_META * inversion_cobertura) / S0_META
KPut_META <- 510

Se tomó el precio Strike (K) de un contrato de opción de venta Put en Yahoo Finance basado en términos de liquidez.

Fuente: Yahoo Finance (2025)
Fuente: Yahoo Finance (2025)

Se tomó el Precio Strike (K) de 510 ya que como se observa en la imagen es el que nos proporciona menor diferencia entre los precios Bid-Ask, lo cual es un índice de liquidez. Además se tiene un Open Interest que relfleja que hay liquidez en ese contrato a pesar de que el precio Strike en 520 es ligeramente mayor con un mayor volúmen inclusive. Sin embargo, se quiso priorizar el spread, ya que la diferencia en términos de Open Interest tampoco es muy significativa.

# Valuación de PUT (comprada)
opcion_put_META <- American_option(S0_META, KPut_META, periodos, dt, rf_continua_trimestral, 
                                   dividendo_META, su_META, sd_META, psubir_META, pbajar_META, "put")

tree_META <- stock_tree(S0_META, periodos, su_META, sd_META)
# Asegurar que es matriz numérica
tree_META <- as.matrix(tree_META)
print(tree_META)
##           [,1]     [,2]     [,3]     [,4]     [,5]     [,6]      [,7]     [,8]
##  [1,] 576.7400   0.0000   0.0000   0.0000   0.0000   0.0000    0.0000    0.000
##  [2,] 516.8282 643.5969   0.0000   0.0000   0.0000   0.0000    0.0000    0.000
##  [3,] 463.1400 576.7400 718.2040   0.0000   0.0000   0.0000    0.0000    0.000
##  [4,] 415.0290 516.8282 643.5969 801.4596   0.0000   0.0000    0.0000    0.000
##  [5,] 371.9158 463.1400 576.7400 718.2040 894.3665   0.0000    0.0000    0.000
##  [6,] 333.2811 415.0290 516.8282 643.5969 801.4596 998.0433    0.0000    0.000
##  [7,] 298.6599 371.9158 463.1400 576.7400 718.2040 894.3665 1113.7386    0.000
##  [8,] 267.6351 333.2811 415.0290 516.8282 643.5969 801.4596  998.0433 1242.845
##  [9,] 239.8331 298.6599 371.9158 463.1400 576.7400 718.2040  894.3665 1113.739
##           [,9]
##  [1,]    0.000
##  [2,]    0.000
##  [3,]    0.000
##  [4,]    0.000
##  [5,]    0.000
##  [6,]    0.000
##  [7,]    0.000
##  [8,]    0.000
##  [9,] 1386.919
# Convertir con melt
tree_df_META <- melt(tree_META, varnames = c("T", "Nodo"), value.name = "Precio")

# Quitar ceros o valores vacíos (nodos no existentes)
tree_df_META <- subset(tree_df_META, Precio > 0)

# Agregar una columna que identifique si el precio sube o baja respecto al nodo anterior
tree_df_META <- tree_df_META[order(tree_df_META$T, tree_df_META$Nodo), ]
tree_df_META$Movimiento <- ifelse(tree_df_META$Precio >= lag(tree_df_META$Precio, default = tree_df_META$Precio[1]), "Sube", "Baja")

# Gráfico del árbol binomial de precios
ggplot(tree_df_META, aes(x = T-1, y = Precio, color = Movimiento)) +
  geom_point(size = 3) +
  geom_text(aes(label = round(Precio, 2)), vjust = -0.5, size = 3) + 
  geom_line(aes(group = T), color = "gray") +
  scale_color_manual(values = c("Sube" = "green3", "Baja" = "red3")) +
  labs(title = "Árbol Binomial de Precios - META", x = "Trimestre", y = "Precio del activo", color = "Movimiento") +
  theme_light()

Valuación de opción put META

# Valor opción PUT para META
valor_actual_put_META <- opcion_put_META[1,1]

option_df_put_META <- melt(opcion_put_META, varnames = c("T", "Nodo"), value.name = "Valor")
option_df_put_META <- subset(option_df_put_META, Valor > 0)
option_df_put_META <- option_df_put_META[order(option_df_put_META$T, option_df_put_META$Nodo), ]
option_df_put_META$Movimiento <- ifelse(option_df_put_META$Valor >= lag(option_df_put_META$Valor, default = option_df_put_META$Valor[1]), "Sube", "Baja")

ggplot(option_df_put_META, aes(x = T-1, y = Valor, color = Movimiento)) +
  geom_point(size = 3) +
  geom_text(aes(label = round(Valor, 2)), vjust = -0.5, size = 3) +
  geom_line(aes(group = T), color = "gray") +
  scale_color_manual(values = c("Sube" = "blue", "Baja" = "orange")) +
  labs(title = "Árbol Binomial - Valor Opción PUT META", x = "Trimestre", y = "Valor de la opción", color = "Movimiento") +
  theme_light()

Al comparar este árbol con el del valor de la opción PUT, se evidencia cómo el valor de la cobertura crece conforme el activo pierde valor, cumpliendo su función como mecanismo de protección frente a escenarios adversos.

Cobertura con opción americana en el trimestre 3 y 4

En ambos trimestres se evidenció las mayores caídas del precio en terminos absolutos, por lo que se decide usar una opción americana que permita mitigar las pérdidas ocasionadas en los mismos periodos al tener la posibilidad de ejercer, ya que es la acción que cuenta con un mayor precio y esto termina ocasionando grandes perdidas cuando su precio cae rápidamente.

#Cobertura en el trimestre 3 con opción americana
costo_cobertura_META_americana = cantidad_acciones_cobertura[2] * valor_actual_put_META
print(costo_cobertura_META_americana)
## [1] 20408.22
precio_META_t3 <- precios_trimestrales %>%
  filter(Trimestre == 3) %>%
  pull(META)

print(precio_META_t3)
## [1] 343.1802
compensacion_META_t3<-max(KPut_META-precio_META_t3,0)*cantidad_acciones_cobertura[2]-costo_cobertura_META_americana
print(compensacion_META_t3)
## [1] 63001.66
compensacion_META_t3 <- matrix(c(0, compensacion_META_t3, 0, 0, 0, 0, 0), ncol = 1)

#Cobertura en el trimestre 4 con opción americana
precio_META_t4 <- precios_trimestrales %>%
  filter(Trimestre == 4) %>%
  pull(META)

print(precio_META_t4)
## [1] 253.8332
compensacion_META_t4<-max(KPut_META-precio_META_t4,0)*cantidad_acciones_cobertura[2]-costo_cobertura_META_americana
print(compensacion_META_t4)
## [1] 107675.2
compensacion_META_t4 <- matrix(c(0, 0, compensacion_META_t4, 0, 0, 0, 0), ncol = 1)

Cobertura con opción europea en el trimestre 8

Al comparar el precio inicial de la acción y según este análisis visualizar a cuanto cae en el ultimo trimestre, se quiso incluir estrategicamente una opción europea que por definición es menos costosa que una americana ya que solo se ejerce al final del plazo. Esto nos permite con esta opción absorber las pérdidas acumuladas de los anteriores trimestre y obtener una compensación mucho más grande ya que el diferencial entre el precio strike y el precio actual de la acción será mucho más grande, lo cual es ideal ante caídas muy grandes, ya que la compensación que genera es muy superior al costo que representa.

#Cobertura en el trimestre 8 con opción europea
opcion_put_META <- European_option(S0_META, KPut_META, periodos, dt, rf_continua_trimestral, 
                                   dividendo_META, su_META, sd_META, psubir_META, pbajar_META, "put")

valor_actual_put_META <- opcion_put_META[1,1]
costo_cobertura_META_europea = cantidad_acciones_cobertura[2] * valor_actual_put_META
print(costo_cobertura_META_europea)
## [1] 20406.13
precio_META_t8 <- precios_trimestrales %>%
  filter(Trimestre == 8) %>%
  pull(META)

print(precio_META_t8)
## [1] 150.1591
compensacion_META_t8<-max(KPut_META-precio_META_t8,0)*cantidad_acciones_cobertura[2]-costo_cobertura_META_europea
print(compensacion_META_t8)
## [1] 159514.3
compensacion_META_t8 <- matrix(c(0, 0, 0, 0, 0, 0, compensacion_META_t8), ncol = 1)

Al mitigar las pérdidas con la cobertura que nos brindan las dos opciones americanas y una opción europea se obtiene:

perdida_con_cobertura_META=perdida_sin_cobertura+compensacion_META_t3+compensacion_META_t4+compensacion_META_t8
print(perdida_con_cobertura_META)
##             [,1]
## [1,] -149724.147
## [2,]  -31815.612
## [3,]   -1787.103
## [4,]  -40637.109
## [5,]  -37602.734
## [6,]  -84963.598
## [7,]   84413.562
### Cobertura con las opciones Put en META comparado con el portafolio sin cobertura

# Crear data frame con tramos
df_META <- tibble(
  Tramo = paste0("T", 1:7),
  Sin_cobertura = as.numeric(perdida_sin_cobertura),
  Con_cobertura = as.numeric(perdida_con_cobertura_META)
)

# Pasar a formato largo para ggplot
df_largo_META <- df_META %>%
  pivot_longer(cols = c(Sin_cobertura, Con_cobertura),
               names_to = "Tipo_de_Perdida",
               values_to = "Perdida")

# Reemplazar guiones bajos por espacios (opcional, por estética)
df_largo_META$Tipo_de_Perdida <- recode(df_largo_META$Tipo_de_Perdida,
                                       "Sin_cobertura" = "Sin cobertura",
                                       "Con_cobertura" = "Con cobertura")

# Crear gráfico
ggplot(df_largo_META, aes(x = Tramo, y = Perdida, fill = Tipo_de_Perdida)) +
  geom_bar(stat = "identity", position = "dodge") +
  scale_fill_manual(values = c("Sin cobertura" = "firebrick", "Con cobertura" = "steelblue")) +
  labs(
    title = "Comparación de pérdidas/ganancias por tramo - META",
    x = "Tramo",
    y = "Pérdida en USD",
    fill = "Tipo de Pérdida"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "right"
  )

Arbol de precios NMIH

#NMIH
sigma_NMIH_trimestral <- sigma_NMIH * sqrt(dt)
su_NMIH <- exp(sigma_NMIH_trimestral * sqrt(dt))
sd_NMIH <- 1 / su_NMIH
dividendo_NMIH <- 0  # No tiene tasa de dividendos
psubir_NMIH <- (exp((rf_continua_trimestral - dividendo_NMIH) * dt) - sd_NMIH) / (su_NMIH - sd_NMIH)
pbajar_NMIH <- 1 - psubir_NMIH
peso_NMIH <- pesos_mediavarianza[3]
q_NMIH <- (peso_NMIH * inversion_cobertura) / S0_NMIH
KPut_NMIH <- 35

Se tomó el precio Strike (K) de un contrato de opción de venta Put en Yahoo Finance basado en términos de liquidez.

Fuente: Yahoo Finance (2025)
Fuente: Yahoo Finance (2025)

Se tomó el Precio Strike (K) de 35. A pesar de que no es el que tiene menor spread, el precio de 40 nos indica una mayor liquidez en términos de volumen y Open Interest, esto sumado a que el diferencial tampoco representa una diferencial muy grande con el que contrato que tiene precio strike de 40. Esto puede deberse a las expectativas que se tienen sobre el activo según el análisis fundamental que se hizo al inicio.

# Valuación de PUT (comprada)
opcion_put_NMIH <- European_option(S0_NMIH, KPut_NMIH, periodos, dt, rf_continua_trimestral, 
                                   dividendo_NMIH, su_NMIH, sd_NMIH, psubir_NMIH, pbajar_NMIH, "put")

tree_NMIH <- stock_tree(S0_NMIH, periodos, su_NMIH, sd_NMIH)
# Asegurar que es matriz numérica
tree_NMIH <- as.matrix(tree_NMIH)
print(tree_NMIH)
##           [,1]     [,2]     [,3]     [,4]     [,5]     [,6]     [,7]     [,8]
##  [1,] 36.00000  0.00000  0.00000  0.00000  0.00000  0.00000  0.00000  0.00000
##  [2,] 33.64985 38.51429  0.00000  0.00000  0.00000  0.00000  0.00000  0.00000
##  [3,] 31.45311 36.00000 41.20419  0.00000  0.00000  0.00000  0.00000  0.00000
##  [4,] 29.39979 33.64985 38.51429 44.08195  0.00000  0.00000  0.00000  0.00000
##  [5,] 27.48051 31.45311 36.00000 41.20419 47.16069  0.00000  0.00000  0.00000
##  [6,] 25.68653 29.39979 33.64985 38.51429 44.08195 50.45447  0.00000  0.00000
##  [7,] 24.00966 27.48051 31.45311 36.00000 41.20419 47.16069 53.97828  0.00000
##  [8,] 22.44226 25.68653 29.39979 33.64985 38.51429 44.08195 50.45447 57.74820
##  [9,] 20.97718 24.00966 27.48051 31.45311 36.00000 41.20419 47.16069 53.97828
##           [,9]
##  [1,]  0.00000
##  [2,]  0.00000
##  [3,]  0.00000
##  [4,]  0.00000
##  [5,]  0.00000
##  [6,]  0.00000
##  [7,]  0.00000
##  [8,]  0.00000
##  [9,] 61.78142
# Convertir con melt
tree_df_NMIH <- melt(tree_NMIH, varnames = c("T", "Nodo"), value.name = "Precio")

# Quitar ceros o valores vacíos (nodos no existentes)
tree_df_NMIH <- subset(tree_df_NMIH, Precio > 0)

# Agregar una columna que identifique si el precio sube o baja respecto al nodo anterior
tree_df_NMIH <- tree_df_NMIH[order(tree_df_NMIH$T, tree_df_NMIH$Nodo), ]
tree_df_NMIH$Movimiento <- ifelse(tree_df_NMIH$Precio >= lag(tree_df_NMIH$Precio, default = tree_df_NMIH$Precio[1]), "Sube", "Baja")

# Gráfico del árbol binomial de precios
ggplot(tree_df_NMIH, aes(x = T-1, y = Precio, color = Movimiento)) +
  geom_point(size = 3) +
  geom_text(aes(label = round(Precio, 2)), vjust = -0.5, size = 3) + 
  geom_line(aes(group = T), color = "gray") +
  scale_color_manual(values = c("Sube" = "green3", "Baja" = "red3")) +
  labs(title = "Árbol Binomial de Precios - NMIH", x = "Trimestre", y = "Precio del activo", color = "Movimiento") +
  theme_light()

Valuación de opción put NMIH

# Valor opción PUT para NMIH
valor_actual_put_NMIH <- opcion_put_NMIH[1,1]

option_df_put_NMIH <- melt(opcion_put_NMIH, varnames = c("T", "Nodo"), value.name = "Valor")
option_df_put_NMIH <- subset(option_df_put_NMIH, Valor > 0)
option_df_put_NMIH <- option_df_put_NMIH[order(option_df_put_NMIH$T, option_df_put_NMIH$Nodo), ]
option_df_put_NMIH$Movimiento <- ifelse(option_df_put_NMIH$Valor >= lag(option_df_put_NMIH$Valor, default = option_df_put_NMIH$Valor[1]), "Sube", "Baja")

ggplot(option_df_put_NMIH, aes(x = T-1, y = Valor, color = Movimiento)) +
  geom_point(size = 3) +
  geom_text(aes(label = round(Valor, 2)), vjust = -0.5, size = 3) +
  geom_line(aes(group = T), color = "gray") +
  scale_color_manual(values = c("Sube" = "blue", "Baja" = "orange")) +
  labs(title = "Árbol Binomial - Valor Opción PUT NMIH", x = "Trimestre", y = "Valor de la opción", color = "Movimiento") +
  theme_light()

A diferencia de activos como LNG o META, los movimientos en NMIH son más moderados, con un rango de precios más acotado. Este comportamiento sugiere que la opción Put podría no generar valores extremos, aunque sí es útil en escenarios bajistas.

Al ser una opción europea, su capacidad de protección está limitada a eventos extremos al vencimiento. Aun así, en casos donde el precio cae por debajo de 30, comienza a generar valor que puede compensar las pérdidas en el portafolio.

A medida que avanza el tiempo y la acción cae, el valor de la opción crece, En escenarios donde el precio cae a aproximadamente 21, la PUT vale hasta 14.02 USD al vencimiento. Por otro lado, en escenarios donde el precio sube, precio > 36, el valor converge hacia 0.

Cobertura con opción americana en el trimestre 5

Teniendo en cuenta que los pesos de inversión en el portafolio fue muy equilibrada y NMIH al ser una acción que tiene el precio más bajo, el portafolio adquiere un mayor número de acciones en este activo, lo que lleva la precaución de tener cuidado con las variaciones negativas de los precios ya que esto puede desencadenar una caída fuerte en la valoración del portafolio, es por eso que se decide hacer uso de una opción americana en un instante intermedio de la inversión para proteger en mayor medida esas fluctuaciones en caída.

#Cobertura en el trimestre 5 con opción americana
opcion_put_NMIH <- American_option(S0_NMIH, KPut_NMIH, periodos, dt, rf_continua_trimestral, dividendo_NMIH, su_NMIH, sd_NMIH, psubir_NMIH, pbajar_NMIH, "put")

valor_actual_put_NMIH <- opcion_put_NMIH[1,1]
costo_cobertura_NMIH_americana = cantidad_acciones_cobertura[3] * valor_actual_put_NMIH
print(costo_cobertura_NMIH_americana)
## [1] 20224.32
precio_NMIH_t5 <- precios_trimestrales %>%
  filter(Trimestre == 5) %>%
  pull(NMIH)

print(precio_NMIH_t5)
## [1] 23.74417
compensacion_NMIH_t5<-max(KPut_NMIH-precio_NMIH_t5,0)*cantidad_acciones_cobertura[3]-costo_cobertura_NMIH_americana
print(compensacion_NMIH_t5)
## [1] 85580.52
compensacion_NMIH_t5 <- matrix(c(0, 0, 0, compensacion_NMIH_t5, 0, 0, 0), ncol = 1)

De igual forma que se hizo con META, se decide hacer uso de una opción europea que se pueda ejercer al final de la inversión para que esta pueda absorber esas perdidas acumuladas y se pueda mitigar de cierta forma en esa caída, lo que daría que en el trimestre 8, en donde el portafolio sin cobertura tiene el valor más bajo, pueda sumar el efecto de las opciones europeas.

#Cobertura en el trimestre 8 con opción europea
opcion_put_NMIH <- European_option(S0_NMIH, KPut_NMIH, periodos, dt, rf_continua_trimestral, 
                                   dividendo_NMIH, su_NMIH, sd_NMIH, psubir_NMIH, pbajar_NMIH, "put")

valor_actual_put_NMIH <- opcion_put_NMIH[1,1]
costo_cobertura_NMIH_europea = cantidad_acciones_cobertura[3] * valor_actual_put_NMIH
print(costo_cobertura_NMIH_americana)
## [1] 20224.32
precio_NMIH_t8 <- precios_trimestrales %>%
  filter(Trimestre == 8) %>%
  pull(NMIH)

print(precio_NMIH_t8)
## [1] 12.80924
compensacion_NMIH_t8<-max(KPut_NMIH-precio_NMIH_t8,0)*cantidad_acciones_cobertura[3]-costo_cobertura_NMIH_europea
compensacion_NMIH_t8 <- matrix(c(0, 0, 0, 0, 0, 0, compensacion_NMIH_t8), ncol = 1)

Al mitigar las pérdidas con la cobertura que nos brindan la opción americana y la opción europea se obtiene:

perdida_con_cobertura_NMIH=perdida_sin_cobertura+compensacion_NMIH_t5+compensacion_NMIH_t8
print(perdida_con_cobertura_NMIH)
##            [,1]
## [1,] -149724.15
## [2,]  -94817.27
## [3,] -109462.28
## [4,]   44943.41
## [5,]  -37602.73
## [6,]  -84963.60
## [7,]  113380.04
### Cobertura con las opciones Put en NMIH comparado con el portafolio sin cobertura

# Crear data frame con tramos
df_NMIH <- tibble(
  Tramo = paste0("T", 1:7),
  Sin_cobertura = as.numeric(perdida_sin_cobertura),
  Con_cobertura = as.numeric(perdida_con_cobertura_NMIH)
)

# Pasar a formato largo para ggplot
df_largo_NMIH <- df_NMIH %>%
  pivot_longer(cols = c(Sin_cobertura, Con_cobertura),
               names_to = "Tipo_de_Perdida",
               values_to = "Perdida")

# Reemplazar guiones bajos por espacios (opcional, por estética)
df_largo_NMIH$Tipo_de_Perdida <- recode(df_largo_NMIH$Tipo_de_Perdida,
                                       "Sin_cobertura" = "Sin cobertura",
                                       "Con_cobertura" = "Con cobertura")

# Crear gráfico
ggplot(df_largo_NMIH, aes(x = Tramo, y = Perdida, fill = Tipo_de_Perdida)) +
  geom_bar(stat = "identity", position = "dodge") +
  scale_fill_manual(values = c("Sin cobertura" = "firebrick", "Con cobertura" = "steelblue")) +
  labs(
    title = "Comparación de pérdidas/ganancias por tramo - NMIH",
    x = "Tramo",
    y = "Pérdida en USD",
    fill = "Tipo de Pérdida"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "right"
  )

Conclusión

Número de acciones que asumirán todo el riesgo del mercado

Debido a que la cobertura se hace sobre el 85% de la inversión, esto significado que el 15% restande asumirá totalmente el riesgo del mercado. Debido a que las opciones se compran por paquetes de 100 acciones, puede que el porcentaje sobre el número de acciones sin cubrir sea ligeramente mayor.

#Acciones sin cobertura
cantidad_acciones<-(inversion*pesos_mediavarianza)/precios_iniciales
cantidad_acciones_sin_cobertura<-cantidad_acciones-cantidad_acciones_cobertura
valor_portafolio_trimestral_sin_cobertura<-precios_matriz %*% cantidad_acciones_sin_cobertura
print(cantidad_acciones_sin_cobertura)
## [1]  246.3907  132.4617 1669.6974
#Valor del portafolio sin cobertura
print(valor_portafolio_trimestral_sin_cobertura)
##           [,1]
## [1,] 192246.01
## [2,] 153822.91
## [3,] 129783.71
## [4,] 106295.79
## [5,]  98947.21
## [6,]  90540.23
## [7,]  73088.65
## [8,]  56913.59

Comportamiento del 85% de la inversión sin el uso de opciones

print(valor_portafolio_trimestral_sin_cobertura+valor_portafolio_trimestral_cobertura)
##           [,1]
## [1,] 1000000.0
## [2,]  823853.9
## [3,]  712304.2
## [4,]  583525.1
## [5,]  535716.7
## [6,]  491478.2
## [7,]  391521.0
## [8,]  303167.2

Cobertura obtenida por las opciones de venta Put para compensar caidas de precios en las acciones

#Estimar el costo total de la cobertura con las opciones americanas y europeas hechas en cada uno de los activos teniendo en cuenta el costo financiero, ya que es un recurso que se obtiene mediante el apalancamiento

costo_cobertura<-2*costo_cobertura_LNG+2*costo_cobertura_META_americana+costo_cobertura_META_europea+costo_cobertura_NMIH_europea+costo_cobertura_NMIH_americana


intereses<-inversion_cobertura*((1+rf)^2-1)
print(intereses)
## [1] 23703.93
costo_cobertura_con_intereses=costo_cobertura+intereses
print(costo_cobertura_con_intereses)
## [1] 169083.8
cobertura_total<-compensacion_LNG_t4+compensacion_LNG_t6+compensacion_META_t3+compensacion_META_t4+compensacion_META_t8+compensacion_NMIH_t5+compensacion_NMIH_t8
print(cobertura_total)
##           [,1]
## [1,]      0.00
## [2,]  63001.66
## [3,] 197622.00
## [4,]  85580.52
## [5,] 103992.34
## [6,]      0.00
## [7,] 347995.08

En este caso, tras analizar los diferentes escenarios de forma empírica, según los datos arrojados por la simulación de los precios con el MBG y la estrategia realizada para cubrir aquellos trimestres con las caídas individuales de los precios de cada acción, se obtuvo que:

1. Según la estrategia de cobertura, no fue necesario utilizar todo el capital que se tenía destinado para comprar opciones, debido a que estamos utilizando un posible escenario de caída de precios, el análisis fundamental y las expectativas de mercado indican que el precio puede tener un crecimiento moderado, por lo que tal vez un escenario pesimista a como está el mercado hoy en día puede ser poco probable. Si se compraban más opciones lo que se genera en el caso de que el precio de las acciones aumenten y el rendimiento del portafolio sea bueno o moderado, hace que se limiten las ganancias

2. Asumiendo que el apalancamiento es tomado con la tasa libre de riesgo TBond 5Y, esta en terminos EA, es una gran opción ya que el interés a pagar sobre el capital es muy bajo, lo que no compromete significativamente el valor presente de este capital

3. Basándonos en el análisis fundamental y descriptivo de cada una de las acciones y al no tener expectativas de aumentos de precios muy grandes, puede que el uso de estas opciones que en si cumplen un papel muy importante ante escenarios de caída, en esecenarios más probables bajo las expectativas de mercado pueden anular las ganancias debido al costo de hacer este tipo de coberturas, lo que dejaría dos alternativas en términos de expectativas para el inversionista, o el precio sube por alguna condición anormal del mercado y se compensan esos costos o se tiene una oportunidad de ganancia potencial dada la estrategia definida ante un escenario de caídas, ya que puede vender el activo mucho más costoso que al precio actual. Sin embargo, ambos son escenarios extremos que podrían generar ganancias en caso tal de que ocurran

Visualización de la cobertura obtenida con las opciones

# Crear un nuevo objeto con los valores originales
valor_portafolio_con_cobertura <- valor_portafolio_trimestral

# Sumar cobertura_total a los tramos 2 al 8 (posición 2 a 8)
valor_portafolio_con_cobertura[2:8, 1] <- valor_portafolio_trimestral[2:8, 1] + cobertura_total

# Verifica que el resultado se vea bien
valor_portafolio_con_cobertura
##           [,1]
## [1,] 1000000.0
## [2,]  823853.9
## [3,]  775305.9
## [4,]  781147.1
## [5,]  621297.2
## [6,]  595470.5
## [7,]  391521.0
## [8,]  651162.3
#GRAFICA
# Crear vector con los valores sin cobertura
portafolio_sin_cobertura <- as.vector(valor_portafolio_trimestral)

# Crear vector con los valores con cobertura
portafolio_con_cobertura <- as.vector(valor_portafolio_con_cobertura)

# Crear etiquetas de tramos
tramos <- paste0("T", 1:8)

# Construir el data frame para graficar
df_portafolio <- data.frame(
  Tramo = rep(tramos, 2),
  Valor = c(portafolio_sin_cobertura, portafolio_con_cobertura),
  Tipo = rep(c("Sin cobertura", "Con cobertura"), each = 8)
)

# Asegurar el orden correcto de los factores
df_portafolio$Tramo <- factor(df_portafolio$Tramo, levels = tramos)
df_portafolio$Tipo <- factor(df_portafolio$Tipo, levels = c("Sin cobertura", "Con cobertura"))

# Crear el gráfico
ggplot(df_portafolio, aes(x = Tramo, y = Valor, fill = Tipo)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.8), width = 0.7) +
  scale_fill_manual(values = c("firebrick", "steelblue")) +
  labs(title = "Evolución del valor del portafolio con y sin cobertura",
       y = "Valor del Portafolio (USD)",
       x = "Trimestre",
       fill = "Escenario") +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = "right",
    legend.title = element_text(face = "bold"),
    plot.title = element_text(face = "bold", hjust = 0.5),
    axis.text.x = element_text(face = "bold"),
    axis.title = element_text(face = "bold")
  )

La estrategia de cobertura estuvo basada en usar algunas opciones americanas en periodos intermedios de la inversión para compensar alguna de las pérdidas obtenidas en los trimestres que no tuvieron cobertura. No se pensó en hacer una cobertura por ejemplo en el trimestre 2, ya que se esperaba que la diferencia entre el precio strike y el precio de la acción fuera positivamente más grande para obtener una mayor compensación.

En el caso de las opciones europeas, su impacto fue muy grande ya que si se compara el precio final de la acción con el precio strike, hace que el diferencial sea aún más grande y se compensen esas pérdidas acumuladas. Se podría plantear entonces por qué no simplemente hacer uso de las opciones europeas ante este tipo de escenarios y a pesar de que se obtiene una mayor compensación, también se piensa en el rol del inversionista y que este requiere de cierta manera obtener liquidez a medida que transcurre su inversión.

Tal vez en la gráfica no se logra ver el impacto total de la cobertura ya que el 15% de las acciones asumieron el riesgo de mercado entonces se suaviza un poco más el resultado. Pero para ser un escenario muy extremo, el resultado obtenido es más que aceptable, lo que se podría recomendar debido a que no se usó totalmente el presupuesto, es que se haga una cobertura total de la inversión, que solo queden por fuera aquellas acciones que no logren a completar el paquete de acciones, esto en el caso de que se tengan expectativas de mercado decreciente.

Referencias

Yahoo Finance – Datos de precios históricos de acciones Yahoo Finance. (2025). META, LNG, NMIH stock data. Yahoo. https://finance.yahoo.com

Yahoo Finance – Opciones financieras (strike prices) Yahoo Finance. (2025). Options data for META, LNG, NMIH. Yahoo. https://finance.yahoo.com/options

Finviz – Análisis fundamental Finviz. (2025). Stock screener: META, LNG, NMIH – fundamental data. https://finviz.com

U.S. Department of the Treasury – Tasa libre de riesgo U.S. Department of the Treasury. (2025). Daily Treasury Real Yield Curve Rates. https://home.treasury.gov/resource-center/data-chart-center/interest-rates/TextView?type=daily_treasury_real_yield_curve&field_tdr_date_value_month=202503

Bailey, D. H., & López de Prado, M. M. (2012). The Sharpe ratio efficient frontier (Working paper). Lawrence Berkeley National Laboratory.

Chicago Board Options Exchange (CBOE). (n.d.). Options contract specifications. Cboe Global Markets. https://www.cboe.com/education/options-contract-specifications/

Lee, M. (2018, May 31). Portfolio optimization in R. Coding Finance. https://www.codingfinance.com/post/2018-05-31-portfolio-opt-in-r/

Charlotte, L. (n.d.). VDerivatives - Functions for Pricing Call Options with Binomial Models/Trees https://www.rpubs.com/charlottelorena/751144