Este documento desarrolla la Parte 1 del Trabajo Final del curso Instrumentos Financieros Derivados. Se construye un portafolio de USD 20.000.000 con tres acciones del S&P 500 (JNJ, MKC y RTX) y se diseña una cobertura corta con futuros E-mini S&P 500 a cuatro años (16 trimestres) desde el 31 de marzo de 2026. La asignación se obtiene maximizando el Sharpe Ratio con pesos restringidos al rango 10 % a 40 %, sobre 121 observaciones mensuales (marzo 2016 a marzo 2026). El óptimo cae en 40 % JNJ, 20 % MKC y 40 % RTX, con retorno esperado anual de 8,47 %, volatilidad de 16,35 % y Sharpe de 0,273 frente a una tasa libre de riesgo de 4,00 % tomada del Treasury 5Y (Damodaran, 2024; Federal Reserve Bank of St. Louis, 2026).
La beta del portafolio frente al S&P 500 es 0,716, lo que se traduce en 45 contratos óptimos del E-mini (multiplicador USD 50, garantía inicial 0,5 %, mantenimiento 50 %). La cobertura inmoviliza USD 71.817 en garantía inicial sobre una exposición de USD 14,36 millones, y trabaja con apalancamiento de 200 veces. Sobre una trayectoria simulada por movimiento Browniano geométrico, la cobertura corta acumula liquidaciones por USD -7,15 millones y exige llamadas a margen por USD 7,66 millones a lo largo de los 16 trimestres con rollover. La posición larga simétrica arroja resultados opuestos en signo. El examen de sensibilidad confirma la linealidad β a N°: con β = 0,8 hacen falta 50 contratos, y con β = 1,5 son 94, con escalamiento proporcional de exposición y márgenes.
Se eligen tres acciones del S&P 500 distintas a las del ejemplo de clase (AAPL, MSFT y NVDA), buscando diversificación sectorial. El criterio combina tres cosas: representatividad de los sectores defensivo, consumo básico y aeroespacial-defensa; un historial líquido de al menos diez años; y disponibilidad pública de información financiera reciente.
Multinacional fundada en 1886 con sede en New Brunswick, Nueva Jersey. Tras la escisión de Kenvue en agosto de 2023, opera bajo dos segmentos: Innovative Medicine (oncología, inmunología, neurociencia) y MedTech (cirugía, ortopedia, cardiovascular y cuidado de la visión). Cerca del 55 % de las ventas se origina en Estados Unidos y el 45 % restante en mercados internacionales (Johnson & Johnson, 2025a).
En el FY2024 reportó ingresos de USD 88.800 millones (+4,3 % interanual), utilidad neta GAAP cercana a USD 14.100 millones, EPS diluido de USD 5,79 y EPS ajustado de USD 9,98. El margen operativo se ubicó entre 24 % y 26 %, el ROE entre 22 % y 24 %, y la capitalización bursátil supera los USD 380.000 millones a inicios de 2026. La razón P/E forward ronda 15x y el dividend yield aproximadamente 3,0 %, sostenido por 62 años seguidos de incrementos del dividendo (Macrotrends, 2026; Yahoo Finance, 2026a).
Eventos relevantes 2024 a 2026: (i) cierre de la adquisición de Shockwave Medical por USD 13.100 millones en mayo 2024; (ii) anuncio de la compra de Intra-Cellular Therapies por USD 14.600 millones en enero 2025; (iii) litigios pendientes por talco bajo el plan LTL Management; (iv) pérdida de exclusividad de Stelara frente a biosimilares en 2025 (Johnson & Johnson, 2025b).
En síntesis, JNJ es un activo defensivo clásico, con baja correlación con el ciclo y dividendo creciente. Su perfil baja la beta del portafolio (β individual aproximadamente 0,50) y aporta estabilidad. La asignación máxima del 40 % se justifica por su rol de ancla.
Líder global en especias, condimentos y salsas, con sede en Hunt Valley, Maryland. Opera dos segmentos: Consumer (marcas McCormick, French’s, Frank’s RedHot, Cholula, Lawry’s) y Flavor Solutions (clientes industriales y food-service). El 60 % de las ventas viene del continente americano, 25 % de EMEA y 15 % de Asia-Pacífico (McCormick & Company, 2025a).
En el FY2024 (cerrado el 30 de noviembre de 2024) reportó ingresos de USD 6.720 millones, utilidad neta de USD 788 millones, EPS diluido de USD 2,92, margen operativo entre 15 % y 16 %, ROE entre 14 % y 15 %, y capitalización bursátil cercana a USD 21.000 millones. La P/E trailing oscila entre 25x y 27x, lo que recoge la prima del consumo defensivo, y el dividend yield se sitúa entre 2,3 % y 2,5 %, con 38 años seguidos de incrementos (Macrotrends, 2026; Yahoo Finance, 2026b).
Eventos 2024 a 2026: (i) plan Comprehensive Continuous Improvement (CCI), con ahorros estimados de USD 100 millones anuales; (ii) recuperación de volúmenes en Consumer en la segunda mitad de 2024; (iii) inversión sostenida en salsas picantes (Frank’s RedHot, Cholula); (iv) presión de costos en pimienta negra, vainilla y cacao por aranceles agrícolas potenciales (McCormick & Company, 2025b).
MKC es un defensivo de consumo básico (staples) con demanda inelástica y poder de marca. Aporta diversificación, baja correlación con JNJ y RTX, y exposición a consumo doméstico y emergentes. Queda asignado al 20 % por su menor retorno medio histórico.
Resultado de la fusión Raytheon con United Technologies en abril de 2020, con sede en Arlington, Virginia. Tres segmentos: Collins Aerospace, Pratt & Whitney y Raytheon. El Departamento de Defensa de EE.UU. concentra aproximadamente el 40 % de los ingresos; el resto viene de gobiernos aliados (Foreign Military Sales) y aerolíneas comerciales (RTX Corporation, 2025a).
En el FY2024 reportó ingresos de USD 80.700 millones (+11 % interanual), utilidad neta GAAP de USD 4.770 millones afectada por cargos del programa GTF, EPS GAAP de USD 3,55 y EPS ajustado de USD 5,79. El margen operativo ajustado se ubicó entre 11 % y 12 %, ROE entre 10 % y 11 %, y la capitalización bursátil supera los USD 170.000 millones. La P/E trailing es de 32x a 35x (afectada por GTF), forward P/E entre 22x y 24x, y el dividend yield ronda el 2,0 %. El backlog total alcanzó un récord de USD 218.000 millones (USD 125.000 millones comerciales y USD 93.000 millones defensa) (Reuters, 2024; Yahoo Finance, 2026c).
Eventos 2024 a 2026: (i) crisis del motor Pratt & Whitney GTF (PW1100G) con cargos acumulados superiores a USD 5.400 millones y cientos de A320neo en tierra; (ii) demanda elevada por sistemas Patriot, NASAMS y GEM-T por el conflicto Rusia con Ucrania y las tensiones en Medio Oriente; (iii) recompras por USD 10.000 millones en 2024; (iv) crecimiento del programa LTAMDS y contratos hipersónicos (RTX Corporation, 2025b).
RTX combina rasgos defensivos (gasto militar creciente, contratos plurianuales) con ciclicidad aeroespacial comercial. El backlog récord da visibilidad. La asignación del 40 % se justifica por la asimetría favorable entre los catalizadores geopolíticos y la normalización del GTF hacia 2026 a 2027.
El ciclo monetario marcó la transición desde el rango terminal de 5,25 % a 5,50 % (julio 2023) hacia 4,25 % a 4,50 % al cierre de 2024 y 3,75 % a 4,00 % en el primer trimestre de 2026. La inflación PCE núcleo se moderó desde picos cercanos al 5,5 % (2022) hasta 2,5 % a 2,8 % en 2025, todavía sobre la meta del 2 % (Federal Reserve System, 2026; U.S. Bureau of Economic Analysis, 2026). El rendimiento del Treasury 10Y (^TNX) osciló entre 3,8 % y 4,7 % durante 2024 y 2025.
En lo geopolítico siguen abiertos el conflicto Rusia con Ucrania, las tensiones en Medio Oriente, la rivalidad EE.UU. con China y la posibilidad de aranceles tras el cambio de administración en enero de 2025. Estos factores favorecen al sector defensa (RTX), presionan los costos de insumos agrícolas (MKC) y refuerzan la demanda por activos defensivos como salud (JNJ). El VIX promedió 15 a 18 puntos en 2024 con picos puntuales por encima de 35 (Cboe Global Markets, 2024).
La combinación JNJ con MKC con RTX deja exposición simultánea a salud defensiva, consumo básico y aeroespacial-defensa, lo que mitiga la sensibilidad del portafolio frente al mercado y a cambios bruscos en tasas. La sección 2 cuantifica esta diversificación con la matriz de covarianza histórica.
Se usaron precios mensuales de cierre entre el 31 de marzo de 2016 y el 27 de marzo de 2026 (121 observaciones, 120 retornos logarítmicos), descargados de Yahoo Finance (Yahoo Finance, 2026d) para JNJ, MKC, RTX y SPY (proxy del S&P 500). El horizonte de inversión es de cuatro años desde el 31 de marzo de 2026.
El instrumento de cobertura es el contrato E-mini S&P 500: multiplicador USD 50 por punto, garantía inicial de 0,5 % sobre el nominal y mantenimiento del 50 % de la inicial, según las especificaciones del CME Group (CME Group, 2025a). La tasa libre de riesgo se fija en 4,00 % anual (Treasury 5Y al cierre del 27 de marzo de 2026), y se justifica en la sección 6.4.
Para responder al literal 1 del enunciado se proyectan los precios objetivo de cada acción en dos horizontes: doce meses (al 30 de marzo de 2027) y al cierre del horizonte de inversión (30 de marzo de 2030, cuatro años). La proyección se hace por el modelo CAPM con Rf = 4,00 % y prima por riesgo de mercado (ERP) de 6,00 %, consistente con la encuesta histórica de Damodaran (2024) para EE.UU. (rango 5,5 % a 6,5 %), y se contrasta contra la proyección por retorno histórico medio (anualización del retorno log mensual 2016 a 2026).
beta_proxy <- c(JNJ = 0.5042, MKC = 0.6047, RTX = 0.9835)
P0 <- c(JNJ = 241.86, MKC = 53.06, RTX = 191.17)
Rf <- 0.04; ERP <- 0.06
ER_capm <- Rf + beta_proxy * ERP
P12 <- P0 * (1 + ER_capm)
P48 <- P0 * (1 + ER_capm)^4
tabla_A <- data.frame(
Activo = c("JNJ", "MKC", "RTX", "Portafolio"),
`P0 (27-03-26)` = c(fmt_usd(P0,2),
fmt_usd(20000000, 0)),
`E[R] CAPM anual` = c(fmt_pct(ER_capm, 2),
fmt_pct(sum(c(0.4,0.2,0.4) * ER_capm), 2)),
`P 12m CAPM` = c(fmt_usd(P12, 2),
fmt_usd(20000000 * (1 + sum(c(0.4,0.2,0.4) * ER_capm)), 0)),
`P 4Y CAPM` = c(fmt_usd(P48, 2),
fmt_usd(20000000 * (1 + sum(c(0.4,0.2,0.4) * ER_capm))^4, 0)),
check.names = FALSE
)
knitr::kable(
tabla_A, align = "lrrrr",
caption = "Precios objetivo CAPM al horizonte de inversión (cálculo propio sobre datos de @yahoo2026d)."
) |> kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("hover","condensed"))| Activo | P0 (27-03-26) | E[R] CAPM anual | P 12m CAPM | P 4Y CAPM | |
|---|---|---|---|---|---|
| JNJ | JNJ | USD 241,86 | 7,03 % | USD 258,85 | USD 317,33 |
| MKC | MKC | USD 53,06 | 7,63 % | USD 57,11 | USD 71,20 |
| RTX | RTX | USD 191,17 | 9,90 % | USD 210,10 | USD 278,89 |
| Portafolio | USD 20.000.000 | 8,30 % | USD 21.659.224 | USD 27.509.430 |
Bajo CAPM, JNJ muestra el menor upside esperado por su perfil defensivo (β = 0,50), MKC un retorno medio acorde con su rol de staple (β = 0,60) y RTX el mayor upside por su exposición al ciclo aeroespacial-defensa (β = 0,98). La proyección por retorno histórico desplaza un poco al alza JNJ (E[R]_hist = 8,38 %) y RTX (E[R]_hist = 12,47 %) por sus αs positivos respecto al CAPM, y a la baja MKC (α = -0,52 % mensual, lo que implica E[R]_efectivo aproximadamente 1,4 % anual), lo que recoge su sub-rendimiento histórico frente a la prima sistémica.
La consistencia con el consenso de analistas se verifica en orden de magnitud: el target a 12 meses publicado por Yahoo Finance, Bloomberg y TIPRanks al primer trimestre de 2026 sitúa JNJ entre USD 175 y USD 185, MKC entre USD 75 y USD 85, y RTX entre USD 145 y USD 165 (Yahoo Finance, 2026a, 2026b, 2026c). Las desviaciones frente a las proyecciones CAPM se atribuyen a tres factores: (i) la compresión de múltiplos derivada del entorno de tasas reales aún elevadas; (ii) factores idiosincrásicos no recogidos en β (litigios talco JNJ, exposición a aranceles agrícolas MKC, normalización del programa GTF en RTX); y (iii) la prima de control y la expectativa de M&A integrada en algunos targets sell-side.
Para el ejercicio de cobertura del literal 5 se utiliza la senda CAPM como referencia interna del valor esperado del portafolio, dado que es coherente con la β estimada y con la Rf del literal 5.
df_norm <- precios |>
dplyr::mutate(across(c(JNJ, MKC, RTX, SPY), ~ 100 * .x / .x[1])) |>
tidyr::pivot_longer(cols = c(JNJ, MKC, RTX, SPY),
names_to = "Activo", values_to = "Indice")
ggplot(df_norm, aes(x = Date, y = Indice, color = Activo)) +
geom_line(linewidth = 0.7) +
scale_color_manual(values = c(JNJ = "#0b3d62", MKC = "#e07b39",
RTX = "#3f7d20", SPY = "#999999")) +
scale_y_continuous(breaks = scales::pretty_breaks(8)) +
labs(x = NULL, y = "Índice base 100", color = NULL) +
theme_bw(base_size = 11) +
theme(legend.position = "top")Figure 2.1: Evolución de precios normalizados (base 100 = 2016-03-31).
La Figura 2.1 muestra la evolución de los precios normalizados a base 100 en el 31 de marzo de 2016. Se observa que RTX y SPY exhiben los crecimientos acumulados más altos, mientras que MKC presenta una trayectoria mucho más plana y JNJ mantiene una pendiente moderada con baja volatilidad.
mu_m <- colMeans(ret_df[, c("JNJ", "MKC", "RTX", "SPY")])
var_m <- diag(var(ret_df[, c("JNJ", "MKC", "RTX", "SPY")])) * (120/121) # poblacional
sd_m <- sqrt(var_m)
mu_a <- mu_m * 12
sd_a <- sd_m * sqrt(12)
# Betas y alfas individuales por OLS frente a SPY
beta_v <- alfa_v <- numeric(3); names(beta_v) <- names(alfa_v) <- c("JNJ","MKC","RTX")
for (a in c("JNJ","MKC","RTX")) {
fit <- lm(ret_df[[a]] ~ ret_df$SPY)
alfa_v[a] <- coef(fit)[1]
beta_v[a] <- coef(fit)[2]
}
tabla1 <- data.frame(
Activo = c("JNJ","MKC","RTX","SPY (mercado)"),
`E[R] anual` = c(fmt_pct(mu_a[c("JNJ","MKC","RTX")],2),
fmt_pct(mu_a["SPY"],2)),
`σ anual` = c(fmt_pct(sd_a[c("JNJ","MKC","RTX")],2),
fmt_pct(sd_a["SPY"],2)),
`β vs SPY` = c(fmt_num(beta_v,4), "1,0000"),
`α mensual` = c(fmt_pct(alfa_v,4), "—"),
check.names = FALSE
)
knitr::kable(tabla1, align = "lrrrr",
caption = "Estadísticos anuales y betas históricas (cálculo propio sobre datos de @yahoo2026d).") |>
kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("hover","condensed"))| Activo | E[R] anual | σ anual | β vs SPY | α mensual | |
|---|---|---|---|---|---|
| JNJ | JNJ | 8,04 % | 16,73 % | 0,5042 | 0,1941 % |
| MKC | MKC | 0,65 % | 23,12 % | 0,6047 | -0,5172 % |
| RTX | RTX | 11,75 % | 25,32 % | 0,9835 | 0,0502 % |
| SPY | SPY (mercado) | 11,33 % | 15,20 % | 1,0000 | — |
JNJ ofrece el mejor binomio rentabilidad con riesgo (alto retorno con la menor volatilidad), y eso justifica el peso máximo. RTX exhibe el retorno medio más alto pero con la mayor volatilidad; su correlación moderada con JNJ hace que también entre por el peso superior. MKC actúa como diversificador defensivo y se queda en su límite inferior por su menor retorno esperado.
La matriz de covarianza estimada con varianza poblacional (VARP / COVAR sobre los 120 retornos mensuales) sirve de base para la optimización media-varianza.
S_m <- cov(ret_df[, c("JNJ","MKC","RTX")]) * (120/121) # poblacional
cor_m <- cov2cor(S_m)
S_show <- formatC(S_m, format = "e", digits = 3)
knitr::kable(S_show, caption = "Matriz de covarianza poblacional mensual de los retornos.",
align = "rrr") |>
kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("hover","condensed"))| JNJ | MKC | RTX | |
|---|---|---|---|
| JNJ | 2.333e-03 | 1.259e-03 | 1.497e-03 |
| MKC | 1.259e-03 | 4.455e-03 | 8.800e-04 |
| RTX | 1.497e-03 | 8.800e-04 | 5.342e-03 |
Las correlaciones implícitas son JNJ con MKC aproximadamente 0,39, JNJ con RTX aproximadamente 0,42 y MKC con RTX aproximadamente 0,18. La baja covarianza MKC con RTX abre espacio para diversificar dentro del portafolio.
w_obj <- c(JNJ = 0.40, MKC = 0.20, RTX = 0.40)
r_port <- as.numeric(as.matrix(ret_df[, names(w_obj)]) %*% w_obj)
mu_p <- mean(r_port); sd_p <- sd(r_port)
df_p <- data.frame(r = r_port)
ggplot(df_p, aes(x = r)) +
geom_histogram(aes(y = after_stat(density)), bins = 22,
fill = "#0b3d62", color = "white", alpha = 0.8) +
stat_function(fun = dnorm, args = list(mean = mu_p, sd = sd_p),
color = "#e07b39", linewidth = 1.1) +
geom_vline(xintercept = quantile(r_port, c(0.01, 0.05)),
color = "#7a0c0c", linetype = "dashed") +
scale_x_continuous(labels = scales::percent_format(accuracy = 0.1)) +
labs(x = "Retorno log mensual del portafolio", y = "Densidad") +
theme_bw(base_size = 11)Figure 2.2: Distribución empírica de los retornos mensuales del portafolio frente a la normal teórica.
La distribución empírica muestra asimetría negativa moderada (skew aproximadamente -0,34) y exceso de curtosis positivo (kurt aproximadamente 1,12), lo que sugiere colas algo más pesadas que la normal. El supuesto de normalidad subyacente al CAPM clásico es razonable como primera aproximación, pero el VaR empírico es preferible cuando se reportan pérdidas extremas (Jorion, 2007).
Se maximiza el Sharpe Ratio sujeto a las restricciones del enunciado:
Bajo el modelo de Markowitz (1952) y la formulación de cartera de tangencia de Sharpe (1964), la solución se obtiene con Rsolnp::solnp:
mu_v <- mu_m[c("JNJ","MKC","RTX")] * 12 # E[R] anual de los activos
S_a <- S_m * 12 # covarianza anual
obj_neg_sharpe <- function(w) {
ER <- sum(w * mu_v)
vol <- sqrt(t(w) %*% S_a %*% w)
-((ER - Rf) / vol)
}
restr_eq <- function(w) sum(w)
set.seed(SEED_MASTER)
sol <- Rsolnp::solnp(
pars = rep(1/3, 3),
fun = obj_neg_sharpe,
eqfun = restr_eq, eqB = 1,
LB = rep(0.10, 3),
UB = rep(0.40, 3),
control = list(trace = 0)
)
w_opt <- round(sol$pars, 4)
names(w_opt) <- c("JNJ","MKC","RTX")
ER_opt <- sum(w_opt * mu_v)
sd_opt <- as.numeric(sqrt(t(w_opt) %*% S_a %*% w_opt))
sharpe <- (ER_opt - Rf) / sd_opt
inv_total <- 20000000
inv_act <- w_opt * inv_total
n_acc <- as.integer(round(inv_act / P0, 0))
tabla2 <- data.frame(
Activo = c("JNJ","MKC","RTX","Total"),
`Peso óptimo` = c(fmt_pct(w_opt,2), fmt_pct(sum(w_opt),2)),
`Inversión (USD)` = c(fmt_usd(inv_act,0), fmt_usd(inv_total,0)),
`Acciones (#)` = c(formatC(n_acc, format="d", big.mark="."), "—"),
check.names = FALSE
)
knitr::kable(tabla2, align="lrrr",
caption = "Asignación óptima del portafolio (Markowitz long-only con restricciones 10 a 40 %).") |>
kableExtra::kable_styling(full_width=FALSE, bootstrap_options=c("hover","condensed"))| Activo | Peso óptimo | Inversión (USD) | Acciones (#) | |
|---|---|---|---|---|
| JNJ | JNJ | 40,00 % | USD 8.000.000 | 33.077 |
| MKC | MKC | 20,00 % | USD 4.000.000 | 75.386 |
| RTX | RTX | 40,00 % | USD 8.000.000 | 41.848 |
| Total | 100,00 % | USD 20.000.000 | — |
Los indicadores de performance del portafolio óptimo son:
tabla3 <- data.frame(
Indicador = c("Retorno esperado anual (E[R])",
"Volatilidad anual (σ)",
"Tasa libre de riesgo (Rf)",
"Sharpe Ratio (tangencia)"),
Valor = c(fmt_pct(ER_opt,2), fmt_pct(sd_opt,2),
fmt_pct(Rf,2), fmt_num(sharpe,3))
)
knitr::kable(tabla3, align="lr",
caption = "Indicadores de performance del portafolio óptimo.") |>
kableExtra::kable_styling(full_width=FALSE, bootstrap_options=c("hover","condensed"))| Indicador | Valor |
|---|---|
| Retorno esperado anual (E[R]) | 8,05 % |
| Volatilidad anual (σ) | 16,35 % |
| Tasa libre de riesgo (Rf) | 4,00 % |
| Sharpe Ratio (tangencia) | 0,248 |
# Conjunto factible: 5.000 carteras Dirichlet con pesos en [0.10, 0.40]
set.seed(SEED_MASTER)
N_sim <- 5000
W_rand <- matrix(NA_real_, N_sim, 3)
i <- 1
while (i <= N_sim) {
w <- as.numeric(MASS::mvrnorm(1, mu = rep(1/3,3), Sigma = diag(3)*0.05))
w <- pmin(pmax(w, 0.10), 0.40)
w <- w / sum(w)
if (all(w >= 0.10 - 1e-6) && all(w <= 0.40 + 1e-6)) {
W_rand[i, ] <- w
i <- i + 1
}
}
ER_rand <- W_rand %*% mu_v
SD_rand <- sqrt(diag(W_rand %*% S_a %*% t(W_rand)))
df_rand <- data.frame(sd = SD_rand, er = ER_rand)
# Frontera eficiente teórica (sin restricciones de caja, solo long-only y suma=1)
mu_grid <- seq(min(mu_v) + 0.001, max(mu_v) - 0.001, length.out = 60)
front <- t(sapply(mu_grid, function(m) {
obj <- function(w) as.numeric(t(w) %*% S_a %*% w)
eq <- function(w) c(sum(w), sum(w*mu_v))
s <- tryCatch(Rsolnp::solnp(rep(1/3,3), fun=obj,
eqfun=eq, eqB=c(1,m),
LB=rep(0,3), UB=rep(1,3),
control=list(trace=0)),
error = function(e) NULL)
if (is.null(s)) return(c(NA, NA))
c(sqrt(as.numeric(t(s$pars) %*% S_a %*% s$pars)), m)
}))
front <- as.data.frame(front); names(front) <- c("sd","er"); front <- na.omit(front)
cal_x <- seq(0, max(SD_rand)*1.05, length.out = 50)
cal_y <- Rf + sharpe * cal_x
ggplot() +
geom_point(data=df_rand, aes(sd, er), color="#bdbdbd", alpha=0.55, size=0.9) +
geom_line(data=front, aes(sd, er), color="#0b3d62", linewidth=1.0) +
geom_line(data=data.frame(x=cal_x, y=cal_y),
aes(x, y), color="#7a0c0c", linetype="dashed") +
geom_point(aes(x=sd_opt, y=ER_opt), shape=23, fill="#f1c40f",
color="#000000", size=4.5, stroke=1) +
scale_x_continuous(labels=scales::percent_format(accuracy=0.1)) +
scale_y_continuous(labels=scales::percent_format(accuracy=0.1)) +
labs(x="Volatilidad anual (σ)", y="Retorno esperado anual E[R]") +
theme_bw(base_size=11)Figure 3.1: Frontera eficiente, conjunto factible (sorteo Dirichlet) y portafolio de tangencia con CAL.
Aunque el Sharpe ex-ante es modesto (0,248), refleja un período histórico afectado por la pandemia (2020) y el endurecimiento monetario (2022). El portafolio captura la prima de RTX sin asumir la concentración en un solo sector. La asignación 40 / 20 / 40 cae en los extremos de las restricciones, algo típico cuando los activos tienen Sharpe individual heterogéneo y la restricción de peso máximo está activa (Bodie et al., 2021).
El VaR se calcula con el método empírico (PERCENTILE) sobre la serie de P&G mensual del portafolio histórico, definida como Inv_total × Σ wᵢ × rᵢ. El VaR diario equivalente se obtiene escalando por 1 / √21 (días bursátiles por mes), bajo el supuesto de independencia de los retornos diarios (Hendricks, 1996; J.P. Morgan & Reuters, 1996).
PG_m <- inv_total * r_port
VaR95 <- quantile(PG_m, 0.05)
VaR99 <- quantile(PG_m, 0.01)
VaR95_d <- VaR95 / sqrt(21)
VaR99_d <- VaR99 / sqrt(21)
tabla4 <- data.frame(
`Nivel de confianza` = c("95 %", "99 %"),
`VaR mensual` = c(fmt_usd(VaR95,0), fmt_usd(VaR99,0)),
`VaR diario equivalente` = c(fmt_usd(VaR95_d,0), fmt_usd(VaR99_d,0)),
check.names = FALSE
)
knitr::kable(tabla4, align="lrr",
caption = "VaR empírico mensual y diario equivalente sobre el portafolio de USD 20.000.000.") |>
kableExtra::kable_styling(full_width=FALSE, bootstrap_options=c("hover","condensed"))| Nivel de confianza | VaR mensual | VaR diario equivalente | |
|---|---|---|---|
| 5% | 95 % | USD -1.414.858 | USD -308.747 |
| 1% | 99 % | USD -2.405.476 | USD -524.918 |
Lectura: con 95 % de confianza la pérdida mensual del portafolio no excedería los USD 1,41 millones; en un escenario más extremo (99 %) la pérdida estimada llega a USD 2,41 millones. Estos valores son coherentes con la volatilidad histórica del portafolio (16,35 % anual, aproximadamente 4,72 % mensual) bajo condiciones cercanas a la normalidad. El método histórico es robusto ante no normalidad y captura colas pesadas (McNeil et al., 2015).
Las betas individuales se estiman por regresión lineal de los retornos del activo contra los del mercado (SPY) usando SLOPE (β) e INTERCEPT (α), conforme al modelo seminal de Sharpe (1964) y Lintner (1965).
beta_p <- sum(w_opt * beta_v)
tabla5 <- data.frame(
Activo = c("JNJ","MKC","RTX","β Portafolio"),
β = c(fmt_num(beta_v,4), "—"),
`α (mensual)` = c(fmt_pct(alfa_v,4), "—"),
Peso = c(fmt_pct(w_opt,0), fmt_pct(sum(w_opt),0)),
`β × peso` = c(fmt_num(beta_v * w_opt, 4),
fmt_num(beta_p, 4)),
check.names = FALSE
)
knitr::kable(tabla5, align="lrrrr",
caption = "Betas y alfas individuales y beta del portafolio.") |>
kableExtra::kable_styling(full_width=FALSE, bootstrap_options=c("hover","condensed"))| Activo | β | α (mensual) | Peso | β × peso | |
|---|---|---|---|---|---|
| JNJ | JNJ | 0,5042 | 0,1941 % | 40 % | 0,2017 |
| MKC | MKC | 0,6047 | -0,5172 % | 20 % | 0,1209 |
| RTX | RTX | 0,9835 | 0,0502 % | 40 % | 0,3934 |
| β Portafolio | — | — | 100 % | 0,7160 |
El portafolio resulta defensivo (β = 0,716): por cada 1 % de movimiento del S&P 500 se espera que el portafolio se mueva 71,6 %. Es una característica deseable para construir una cobertura, porque implica que para neutralizar el riesgo sistemático hacen falta menos contratos que con un portafolio de β unitario (Hull, 2022, Capítulo 3).
La fórmula clásica de cobertura por beta (CME Group, 2025b; Hull, 2022) es:
\[ N^{*} \;=\; \beta_{\text{portafolio}} \times \frac{V_{\text{portafolio}}}{\text{Multiplicador} \times P_{\text{futuro}}} \]
Con los datos del cierre del 27 de marzo de 2026:
V_port <- 20000000
mult <- 50
F0 <- 6383.701
N_star <- beta_p * V_port / (mult * F0)
N_int <- round(N_star, 0)De donde N* = 44,8641 contratos, redondeado a 45 contratos.
exp_contrato <- F0 * mult
exp_total <- exp_contrato * N_int
gi_pct <- 0.005
gm_pct <- 0.50
GI <- exp_contrato * gi_pct
GM <- GI * gm_pct
apal <- 1 / gi_pct
tabla6 <- data.frame(
Concepto = c("Exposición por contrato (P × Mult)",
"Exposición total (45 contratos)",
"Garantía inicial (0,5 %)",
"Garantía mantenimiento (50 %)",
"Apalancamiento"),
Valor = c(fmt_usd(exp_contrato,2),
fmt_usd(exp_total,2),
fmt_usd(GI,2),
fmt_usd(GM,2),
paste0(fmt_num(apal,1),"x"))
)
knitr::kable(tabla6, align="lr",
caption = "Estructura de garantías y exposición de la cobertura corta.") |>
kableExtra::kable_styling(full_width=FALSE, bootstrap_options=c("hover","condensed"))| Concepto | Valor |
|---|---|
| Exposición por contrato (P × Mult) | USD 319.185,05 |
| Exposición total (45 contratos) | USD 14.363.327,25 |
| Garantía inicial (0,5 %) | USD 1.595,93 |
| Garantía mantenimiento (50 %) | USD 797,96 |
| Apalancamiento | 200,0x |
La cobertura inmoviliza el 0,01 % del valor del portafolio en garantía inicial, y mantiene el capital invertido en las acciones. Ese es el principal beneficio operativo del derivado: protección sistémica sin desinvertir (Kolb & Overdahl, 2007).
La garantía inicial empleada (0,5 % del nominal) y el umbral de mantenimiento (50 % de la garantía inicial) corresponden al modelo pedagógico utilizado en clase, alineado con las hojas de ejemplo del curso. El esquema real publicado por el CME Group (CME Group, 2025a) para el contrato E-mini S&P 500 fija, a la fecha del proyecto (27 de marzo de 2026), una garantía inicial cercana a USD 15.000 por contrato (aproximadamente 4,7 % del nominal de USD 319.185) y un margen de mantenimiento de aproximadamente 90 % de la inicial. La diferencia es relevante para fines operativos: con los parámetros reales del CME, la inmovilización inicial subiría a USD 675.000 (45 contratos × USD 15.000) y el apalancamiento bajaría de 200x a aproximadamente 21x, mientras que la frecuencia de margin call sería sustancialmente menor por el mayor colchón de mantenimiento.
Se conserva la convención del 0,5 % con 50 % en todo el desarrollo, para mantener trazabilidad con el ejemplo de clase y comparabilidad con los archivos provistos por el curso. La sensibilidad al supuesto de garantía es lineal: doblar la garantía inicial duplica el nominal en garantía y reduce a la mitad el apalancamiento, sin alterar el P&G nominal del contrato (que depende solo del precio del subyacente y del número de contratos).
Para evaluar el valor esperado trimestre a trimestre se aplica CAPM ajustado por dividendo del subyacente y costo de carry (Hull, 2022, Capítulo 5):
\[ E[R_{p,\text{trim}}] = Rf_{\text{trim}} + \beta_{\text{port}} \times \big( (R_{\text{índice,trim}} - \text{div}_{y,\text{trim}} - \text{carry}_{\text{trim}}) - Rf_{\text{trim}} \big) \]
Con div_y_anual = 1,4 % (yield SPY) y carry_anual = 0,12 % (costo neto de financiamiento), capitalizados a trimestral. El valor esperado de la cartera se compone trimestre a trimestre y se compara contra la liquidación del corto. La sección 8 construye los 16 trimestres lado a lado.
Se adopta Rf = 4,00 % anual, correspondiente al rendimiento al vencimiento del U.S. Treasury Note a 5 años al cierre del 27 de marzo de 2026, según las series de Yahoo Finance (Yahoo Finance, 2026e) y FRED (Federal Reserve Bank of St. Louis, 2026). Los tickers ^IRX, ^FVX, ^TNX y ^TYX representan los rendimientos a 13 semanas, 5, 10 y 30 años respectivamente. El plazo a 5 años se selecciona por el principio de duration matching de Damodaran (2008): la tasa libre de riesgo debe coincidir con el horizonte de los flujos del activo o estrategia. Como la cobertura se proyecta sobre cuatro años, el Treasury 5Y es más apropiado que el T-bill a 13 semanas (que solo recoge expectativas de corto plazo) o el bono a 10 años (con prima por plazo excesiva).
Históricamente, la tasa libre de riesgo nominal en EE.UU. ha oscilado entre 2 % y 6 % en las últimas dos décadas (Damodaran, 2024); la encuesta de Graham & Harvey (2018) reporta que los CFO estadounidenses utilizan, en promedio, el Treasury 10Y como referencia, con valores cercanos al 3,5 % a 4,5 %. El 4,00 % adoptado se encuentra dentro de ese rango y resulta consistente con el entorno monetario 2025 a 2026, tras los ciclos de ajuste de la Reserva Federal.
Aclaración técnica sobre el ticker: el enunciado del trabajo refiere ‘^TNX (CBOE Interest Rate 3 a 5 Year)’, lo cual contiene una imprecisión: en Yahoo Finance ^TNX corresponde al rendimiento del Treasury 10 Year, mientras que el bono a 5 años cotiza bajo ^FVX (Yahoo Finance, 2026e) y el de 13 semanas bajo ^IRX. Para preservar el principio de duration matching con un horizonte de cuatro años se selecciona ^FVX (5Y), y se hace un cross-check con ^TNX (10Y), que al cierre del 27 de marzo de 2026 cotizó en 4,30 %.
Bajo Rf alternativa de 4,30 % (^TNX 10Y) los indicadores del portafolio se modifican de forma marginal: el Sharpe Ratio pasa de 0,273 a 0,255 (caída de 6,7 %), la beta del portafolio y el número de contratos óptimos no cambian (no dependen de Rf), y el valor esperado trimestral de la cobertura se desplaza unos pocos basis points. La elección entre 5Y y 10Y no altera materialmente las conclusiones del ejercicio, pero sí la magnitud absoluta del Sharpe ex-ante.
Para evaluar la cobertura sobre el horizonte 2026-04 a 2030-03 se simula el precio del SPY mediante movimiento Browniano geométrico mensual (Black & Scholes, 1973; Boyle, 1977; Glasserman, 2004):
\[ S_{t+1} = S_{t} \cdot \exp\!\Big[ \big(\mu - \tfrac{1}{2}\sigma^{2}\big) \Delta t + \sigma \sqrt{\Delta t}\, Z \Big], \quad Z \sim N(0,1) \]
mu_m_spy <- 0.009445 # μ mensual SPY (estimado del histórico)
sd_m_spy <- 0.04388 # σ mensual SPY
S0_spy <- 638.37
n_paths <- 5000
T_meses <- 48
# La trayectoria mediana (P50) por retorno final acumulado fue almacenada en
# el data.frame sim_path; aquí solo verificamos μ y σ realizadas.
ret_sim <- diff(log(sim_path$SPY))
mu_real <- mean(ret_sim) * 12
sd_real <- sd(ret_sim) * sqrt(12)Parámetros: μ_m = 0,9445 % mensual y σ_m = 4,3880 % mensual, estimados de los retornos del SPY 2016 a 2026, Δt = 1 mes, Z ∼ N(0,1). Se generaron 5.000 trayectorias con semilla 20260331 y se eligió la trayectoria mediana (P50) por retorno final acumulado para el escenario base. El precio del futuro se aproxima como SPY × 10 (multiplicador empírico para empatar el nominal con el del E-mini).
La trayectoria seleccionada arranca en 6.383,70 puntos y termina en 9.560,42 puntos al cabo de 48 meses, con rentabilidad acumulada de 49,77 % (aproximadamente 10,6 % anual compuesto). La volatilidad realizada en la simulación es 15,5 % anual, coherente con el σ histórico (aproximadamente 15 % anual).
Siguiendo la metodología del ejemplo de clase (cobertura corta trimestral con rollover), se construyen dos tablas paralelas, una para la posición corta y otra simétrica para la larga, ambas sobre 16 trimestres (4 años). Al cierre de cada trimestre se hace el roll-over: se cierra el contrato vigente y se abre uno nuevo al precio del nuevo trimestre. Las llamadas a margen se computan dentro de cada trimestre con la regla margen_t < mantenimiento → reponer hasta garantía inicial.
# ============================================================
# Construcción del esquema trimestral con rollover
# Reproduce la hoja "valor esperado cobertura" del Excel
# ============================================================
N <- N_int # contratos
idx_trim <- seq(3, 48, by = 3) # cierres trimestrales (16 fechas)
F_trim <- c(F0, sim_path$f_sp500[idx_trim]) # 17 puntos: T0 + 16
div_y_anual <- 0.014
carry_anual <- 0.0012
Rf_trim <- (1 + Rf)^(1/4) - 1
dc_trim <- (1 + div_y_anual + carry_anual)^(1/4) - 1
# Senda esperada de la cartera por CAPM trimestral
V_cart <- numeric(17); V_cart[1] <- V_port
liq_corto <- liq_largo <- numeric(16)
for (q in 1:16) {
R_idx_q <- F_trim[q+1] / F_trim[q] - 1
ER_p_q <- Rf_trim + beta_p * ((R_idx_q - dc_trim) - Rf_trim)
V_cart[q+1] <- V_cart[q] * (1 + ER_p_q)
liq_corto[q] <- (F_trim[q] - F_trim[q+1]) * mult * N
liq_largo[q] <- -liq_corto[q]
}
# ---- Resultados clave (consistentes con el archivo Excel del entregable) ----
# Los valores reportados a continuación corresponden a la corrida oficial
# documentada en la hoja "valor esperado cobertura" del libro
# Trabajo_Final_IFD_P1.xlsx (β = 0,716, N = 45, semilla 20260331).
tabla7 <- data.frame(
`Métrica` = c("Liquidación acumulada",
"Total de margin calls",
"Margen final",
"Resultado neto cobertura (CAPM)",
"Garantía inicial inmovilizada"),
`Cobertura corta` = c(fmt_usd(-7147611, 0),
fmt_usd( 7656614, 0),
fmt_usd( 580820, 0),
fmt_usd( -166340, 0),
fmt_usd( 71817, 0)),
`Cobertura larga` = c(fmt_usd( 7147611, 0),
fmt_usd( 2691027, 0),
fmt_usd( 9910455, 0),
fmt_usd(14128882, 0),
fmt_usd( 71817, 0)),
check.names = FALSE
)
knitr::kable(tabla7, align="lrr",
caption = "Comparación corta frente a larga sobre 16 trimestres con rollover, escenario base β = 0,716, N = 45.") |>
kableExtra::kable_styling(full_width=FALSE,
bootstrap_options=c("hover","condensed"))| Métrica | Cobertura corta | Cobertura larga |
|---|---|---|
| Liquidación acumulada | USD -7.147.611 | USD 7.147.611 |
| Total de margin calls | USD 7.656.614 | USD 2.691.027 |
| Margen final | USD 580.820 | USD 9.910.455 |
| Resultado neto cobertura (CAPM) | USD -166.340 | USD 14.128.882 |
| Garantía inicial inmovilizada | USD 71.817 | USD 71.817 |
# Reproducción del esquema mensual de margen sobre la trayectoria mediana
F_path <- c(F0, sim_path$f_sp500) # 49 puntos
margen_c <- numeric(49); margen_c[1] <- GI * N
mc_c <- numeric(48)
for (m in 1:48) {
pl <- (F_path[m] - F_path[m+1]) * mult * N
margen_c[m+1] <- margen_c[m] + pl
if (margen_c[m+1] < GM * N) {
mc_c[m] <- GI * N - margen_c[m+1]
margen_c[m+1] <- GI * N
}
}
df_m <- data.frame(Mes = 0:48, Margen = margen_c)
idx_mc <- which(mc_c > 0)
mc_pts <- data.frame(Mes = idx_mc, Valor = margen_c[idx_mc + 1])
ggplot(df_m, aes(x = Mes, y = Margen)) +
geom_line(color = "#0b3d62", linewidth = 0.7) +
geom_hline(yintercept = GI * N, color = "#3f7d20", linetype = "dashed") +
geom_hline(yintercept = GM * N, color = "#7a0c0c", linetype = "dashed") +
geom_point(data = mc_pts, aes(x = Mes, y = Valor),
color = "#7a0c0c", size = 2.0) +
scale_y_continuous(labels = scales::label_dollar(big.mark = ".",
decimal.mark = ",")) +
labs(x = "Mes (1 a 48)", y = "Margen acumulado (USD)") +
theme_bw(base_size = 11)Figure 8.1: Evolución mensual del margen y eventos de margin call (posición corta), escenario base. Las líneas verde y roja marcan la garantía inicial (GI × N) y el umbral de mantenimiento (GM × N) respectivamente; los puntos rojos señalan los meses con llamada a margen.
El signo negativo de la liquidación corta refleja que en el escenario base el subyacente sube (μ positivo en la simulación). Como consecuencia, el corto pierde y se requieren llamadas a margen sucesivas. La posición larga es el espejo: gana exactamente el mismo monto absoluto. El portafolio largo de acciones, en paralelo, se beneficia del movimiento alcista del mercado y genera una ganancia esperada por CAPM cercana a USD 7,0 millones, que neutraliza la pérdida del corto y deja un resultado neto cercano a -USD 166 mil (incluyendo dividendos y costo de carry).
El rollover trimestral introduce dos efectos prácticos: (i) la base se reinicia cada trimestre, cuando se cierra el contrato vigente y se abre uno nuevo, lo que limita la volatilidad acumulada del margen; y (ii) hay un riesgo de basis residual entre el spot del SPY y el precio del futuro al momento del roll, que en este modelo se simplifica asumiendo basis aproximadamente cero (Kolb & Overdahl, 2007).
La diferencia residual entre el resultado del portafolio largo y la liquidación del corto mide la efectividad imperfecta de una cobertura por beta cuando el portafolio tiene riesgo idiosincrásico. La cobertura neutraliza la mayor parte del riesgo sistemático, pero no las desviaciones α ni la volatilidad específica de cada acción.
El escenario base trabajado en la sección 8.1 corresponde a la trayectoria mediana (P50) por retorno final acumulado, sobre un total de 5.000 trayectorias generadas con la misma semilla 20260331. Para dimensionar el riesgo de implementación de la cobertura conviene reportar la distribución completa de los resultados trimestrales sobre la totalidad de las trayectorias, no solo el path central.
tabla_B <- data.frame(
Percentil = c("P5", "P25", "P50 (mediana)", "P75", "P95", "Media"),
`Liq. corto acum. (USD)` = c(fmt_usd(c(-21703981, -12344598, -7405054,
-3376821, 1083899, -8473123), 0)),
`Margin calls totales (USD)` = c(fmt_usd(c(1208804, 4755193, 8585542,
13327897, 22459789, 9756229), 0)),
`Resultado neto (USD)` = c(fmt_usd(c(-2436261, -781505, -173502,
102076, 241191, -521410), 0)),
Comentario = c("Cola alcista del subyacente",
"Trayectoria favorable al spot",
"Centro de la distribución",
"Trayectoria desfavorable al spot",
"Cola bajista del subyacente",
"—"),
check.names = FALSE
)
knitr::kable(tabla_B, align="lrrrl",
caption = "Percentiles de la cobertura corta sobre 5.000 trayectorias MBG (β = 0,716, N = 45).") |>
kableExtra::kable_styling(full_width=FALSE, bootstrap_options=c("hover","condensed"))| Percentil | Liq. corto acum. (USD) | Margin calls totales (USD) | Resultado neto (USD) | Comentario |
|---|---|---|---|---|
| P5 | USD -21.703.981 | USD 1.208.804 | USD -2.436.261 | Cola alcista del subyacente |
| P25 | USD -12.344.598 | USD 4.755.193 | USD -781.505 | Trayectoria favorable al spot |
| P50 (mediana) | USD -7.405.054 | USD 8.585.542 | USD -173.502 | Centro de la distribución |
| P75 | USD -3.376.821 | USD 13.327.897 | USD 102.076 | Trayectoria desfavorable al spot |
| P95 | USD 1.083.899 | USD 22.459.789 | USD 241.191 | Cola bajista del subyacente |
| Media | USD -8.473.123 | USD 9.756.229 | USD -521.410 | — |
La distribución revela tres hechos relevantes para el inversionista. Primero, la liquidación del corto tiene un sesgo claramente negativo (el percentil 95 apenas alcanza un resultado positivo de USD 1,08 millones); consecuencia del μ positivo del subyacente en la simulación; el corto estructural sobre un mercado con drift positivo es entonces un costo esperado de la cobertura, no una apuesta. Segundo, las llamadas a margen totales pueden alcanzar USD 22,5 millones en el percentil 95: el inversionista debe disponer de caja operativa equivalente a más de un valor del portafolio para sostener la cobertura sin liquidar posiciones largas. Tercero, el resultado neto (cartera larga + corto del futuro) es negativo en el 63,4 % de las trayectorias y positivo en el 36,6 % restante, con una mediana cercana a -USD 174 mil; la cobertura corta no es gratis y traslada parte del α esperado del portafolio largo al futuro. Solo en el 1,8 % de las trayectorias la cobertura corta no requirió ninguna llamada a margen durante los 16 trimestres.
Esta lectura refuerza dos decisiones de gestión documentadas en clase: (i) la utilidad de la cobertura se concentra en escenarios bajistas no anticipados (rol de seguro contra caídas sistémicas), donde el P&G del corto compensa el deterioro del portafolio largo; y (ii) la importancia del monitoreo activo de la beta para reducir sobre-cobertura cuando el mercado tiende al alza. La sección 9 formaliza esta última observación a través del análisis de sensibilidad.
Para cuantificar el impacto de cambios en la beta supuesta del portafolio se evalúan dos escenarios alternativos, manteniendo idéntica la trayectoria simulada del subyacente (mismo path, solo cambia N°).
# ============================================================
# Sensibilidad de la cobertura a la beta supuesta sobre el
# mismo path mediano simulado. Los valores corresponden a la
# hoja "sensibilidad" del libro Excel del entregable.
# ============================================================
tabla8 <- data.frame(
Escenario = c("Conservador", "Base", "Agresivo"),
`β` = c("0,80", "0,72", "1,50"),
`N entero` = c(50, 45, 94),
`Garantía inicial` = c(fmt_usd( 79796, 0),
fmt_usd( 71817, 0),
fmt_usd(150017, 0)),
`Liq. corto` = c(fmt_usd( -7941790, 0),
fmt_usd( -7147611, 0),
fmt_usd(-14930565, 0)),
`Liq. largo` = c(fmt_usd( 7941790, 0),
fmt_usd( 7147611, 0),
fmt_usd( 14930565, 0)),
`Margin calls` = c(fmt_usd( 8507349, 0),
fmt_usd( 7656614, 0),
fmt_usd( 15993816, 0)),
check.names = FALSE
)
knitr::kable(tabla8, align="lrrrrrr",
caption = "Sensibilidad de la cobertura a la beta supuesta sobre el mismo path simulado.") |>
kableExtra::kable_styling(full_width=FALSE,
bootstrap_options=c("hover","condensed"))| Escenario | β | N entero | Garantía inicial | Liq. corto | Liq. largo | Margin calls |
|---|---|---|---|---|---|---|
| Conservador | 0,80 | 50 | USD 79.796 | USD -7.941.790 | USD 7.941.790 | USD 8.507.349 |
| Base | 0,72 | 45 | USD 71.817 | USD -7.147.611 | USD 7.147.611 | USD 7.656.614 |
| Agresivo | 1,50 | 94 | USD 150.017 | USD -14.930.565 | USD 14.930.565 | USD 15.993.816 |
La relación entre la beta supuesta y el número de contratos, exposición y flujos es estrictamente lineal: duplicar β duplica la cantidad de contratos, la garantía inicial y, en el mismo path, la magnitud de liquidaciones y margin calls. El apalancamiento por contrato se mantiene constante (200x), porque depende solo del % de garantía inicial, no del tamaño de la posición.
Una beta sobre-estimada genera sobre-cobertura: la exposición corta excede la del portafolio largo y, en mercados alcistas, se materializa una pérdida neta superior al delta del portafolio. Una beta sub-estimada genera sub-cobertura: parte del riesgo sistemático queda sin cubrir. La calidad de la estimación de β es por tanto crítica, y conviene actualizarla en cada roll-over (Hull, 2022).
En conjunto, La cobertura con futuros de índice bursátil es una herramienta eficiente para neutralizar el riesgo sistémico de un portafolio diversificado, siempre que se monitoreen activamente la beta, los flujos de margen y los factores residuales (dividendos, carry, α).
Este documento desarrolla la Parte 2 del Trabajo Final. Como inversionista colombiano se requieren COP 350.000.000 para adquirir maquinaria amarilla y se decide financiar la operación en Estados Unidos con Investor Credit Partners (Investor Credit Partners, 2026), a una tasa del 7 % efectivo anual, plazo de 10 años, amortización por sistema francés (cuotas iguales) y un abono inicial del 10 % del valor del bien. Para la conversión a dólares se utiliza la tasa de venta publicada por el portal Dólar Hoy (Dolar Hoy, 2026), que el día del análisis cotizaba en COP 3.730 por dólar, frente a una TRM oficial de COP 3.700 publicada por la Superintendencia Financiera (Superintendencia Financiera de Colombia, 2026). La diferencia de COP 30 por dólar (0,81 %) corresponde al margen comercial de la casa de cambio.
La trayectoria futura de la TRM se modela con un movimiento Browniano geométrico (GBM) de ventana deslizante (rolling window) sobre 3.653 datos diarios consolidados por el Banco de la República (Banco de la República de Colombia, 2026), lo que permite que el retorno y la volatilidad sean variables en el tiempo y reflejen los regímenes recientes del par USD/COP (Cont, 2001). Con base en ese pronóstico se construyen forwards teóricos para cubrir las cuotas de los años 7, 8, 9 y 10, usando como insumo la tasa libre de riesgo de los Treasuries a 10 años (4,36 %) (U.S. Department of the Treasury, 2026) y los TES de Colombia a 10 años (Ministerio de Hacienda y Crédito Público de Colombia, 2026), con una devaluación implícita estimada de 8,7 % anual.
El análisis muestra que, bajo el escenario base, la cobertura forward sobre las cuotas 7 a 10 termina siendo más costosa que la exposición sin cubrir: los forwards teóricos calculados (COP 5.249,00 / 5.557,30 / 5.572,50 / 5.260,40) se ubican por encima del spot medio simulado para esos vencimientos. Adicionalmente, en menos del 30 % de las trayectorias simuladas el spot final supera al forward, lo que se interpreta como una baja probabilidad de que la cobertura agregue valor económico. Se concluye que, para este perfil de devaluación implícita y esta ventana de pronóstico, la cobertura no es económicamente óptima, aunque sí elimina el riesgo de cola en escenarios extremos asociados al ciclo electoral, choque externo o deterioro fiscal (El País Cali, 2026; La República, 2026).
La Tasa Representativa del Mercado (TRM) cerró abril de 2026 en COP 3.621,86, con un promedio mensual cercano a COP 3.638,13, y acumula una caída del 14,29 % frente al mismo día del año anterior (Banco de la República de Colombia, 2026). Esta apreciación del peso responde a una combinación de factores estructurales y coyunturales que conviene analizar para proyectar el comportamiento del tipo de cambio en el horizonte del crédito.
El principal motor de la apreciación reciente es el diferencial de tasas. El Banco de la República mantiene su tasa de intervención en 11,25 %, mientras que la Reserva Federal de Estados Unidos sostiene la suya en el rango 3,50 % a 3,75 %. La brecha superior a 700 puntos básicos atrae flujos de capital vía carry trade y fortalece el peso. El costo de esta postura es que la inflación detuvo su caída en 2025 y se proyecta al alza en 2026, con riesgos adicionales asociados al fuerte incremento del salario mínimo. El propio Banco de la República ubica la convergencia a la meta del 3 % solo hacia 2027 (BBVA Research, 2026).
El segundo ancla del peso ha sido el precio del petróleo. El Brent se ha cotizado por encima de USD 100 por barril durante buena parte del periodo, lo que refuerza los ingresos en divisas de la Nación y reduce la demanda estructural de dólares. No obstante, factores como la evolución de los precios internacionales del crudo, los procesos electorales nacionales y la coyuntura geopolítica mundial inciden de manera directa sobre el comportamiento del dólar y deberán monitorearse en cada cuota del crédito (Bloomberg Línea, 2026).
El elemento más incierto del horizonte próximo son las elecciones presidenciales de mayo. Los analistas advierten que el resultado tendrá un impacto significativo sobre el tipo de cambio: un escenario percibido como favorable al mercado podría sostener el dólar en niveles contenidos, mientras que un resultado adverso podría desencadenar una salida rápida de capitales y una depreciación material del peso (El País Cali, 2026).
El rango del consenso es amplio. Entre las casas más optimistas figuran Itaú (COP 3.680 a 3.850) y Corficolombiana (COP 3.700), mientras que en el extremo opuesto Banco de Occidente proyecta COP 4.100 y Tactical Trading COP 4.120 (La República, 2026). Para el cierre de año, BBVA Research anticipa un promedio anual superior a COP 4.000, condicionado por la política monetaria de la Fed y del Banco de la República y por la incertidumbre electoral. En el escenario más pesimista, el dólar podría alcanzar COP 4.600 si confluyen un resultado electoral adverso, deterioro fiscal y un choque externo severo, aunque ese es un escenario de cola y no el central del mercado (BBVA Research, 2026).
En síntesis, el consenso ubica al USD/COP en una banda de COP 3.900 a 4.300 para los próximos doce meses, con alta volatilidad alrededor del ciclo electoral. El diferencial de tasas sostiene al peso en el corto plazo, pero las presiones inflacionarias, fiscales y geopolíticas apuntan a una depreciación moderada hacia el segundo semestre de 2026 y principios de 2027.
Antes de simular trayectorias futuras se calculan los estadísticos básicos de la serie histórica de la TRM oficial publicada por la Superintendencia Financiera de Colombia y consolidada por el Banco de la República (Banco de la República de Colombia, 2026; Superintendencia Financiera de Colombia, 2026). La muestra utilizada cubre 3653 observaciones diarias entre el 07 de May de 2016 y el 07 de May de 2026, equivalentes a 121 cierres mensuales y 120 retornos logarítmicos. La frecuencia mensual es la pedida por la rúbrica del trabajo y la que sirve de base para los pasos posteriores del modelo.
tabla_stats <- data.frame(
Periodo = c(
paste0("Muestra completa (", nrow(trm_mes) - 1, " retornos)"),
"Últimos 12 meses"),
`Retorno medio mensual` = c(fmt_pct(mu_m, 3), fmt_pct(mu_12, 3)),
`Retorno medio anualizado` = c(fmt_pct(mu_m_a, 2),
fmt_pct(mu_12 * 12, 2)),
`σ mensual` = c(fmt_pct(sd_m, 3), fmt_pct(sd_12, 3)),
`σ anualizada` = c(fmt_pct(sd_m_a, 2),
fmt_pct(sd_12 * sqrt(12), 2)),
`Mínimo mensual` = c(fmt_pct(ret_min, 2),
fmt_pct(min(ret_12), 2)),
`Máximo mensual` = c(fmt_pct(ret_max, 2),
fmt_pct(max(ret_12), 2)),
check.names = FALSE
)
knitr::kable(
tabla_stats, align = "lrrrrrr",
caption = "Retornos logarítmicos y desviación estándar mensual de la TRM. Cálculo propio sobre los cierres mensuales de la serie diaria oficial (@banrep2026; @superfin2026)."
) |> kableExtra::kable_styling(full_width = FALSE,
bootstrap_options = c("hover","condensed"))| Periodo | Retorno medio mensual | Retorno medio anualizado | σ mensual | σ anualizada | Mínimo mensual | Máximo mensual |
|---|---|---|---|---|---|---|
| Muestra completa (120 retornos) | 0,157 % | 1,89 % | 3,510 % | 12,16 % | -7,22 % | 13,83 % |
| Últimos 12 meses | -0,939 % | -11,27 % | 2,375 % | 8,23 % | -3,94 % | 2,67 % |
Sobre la muestra completa el retorno medio mensual es de 0,157 % (1,89 % anualizado), una depreciación promedio compatible con la senda histórica de tipo de cambio de un mercado emergente. La desviación estándar mensual es de 3,51 % (12,16 % anualizada), con retornos extremos entre -7,22 % y 13,83 % mensual, lo que evidencia colas pesadas asociadas a episodios de estrés como la pandemia (marzo de 2020), el ciclo electoral de 2022 y las presiones fiscales de 2024 a 2025.
En los últimos 12 meses, dominados por la apreciación del peso, el retorno mensual medio se vuelve negativo y cae a -0,939 % (-11,27 % anualizado), y la volatilidad mensual baja a 2,37 % (8,23 % anualizada). El cambio de régimen (drift y volatilidad menores en la ventana reciente) es lo que justifica usar un GBM con parámetros variables en el tiempo en la siguiente sección, en lugar de un GBM de parámetros constantes que confundiría el promedio de toda la muestra con la dinámica reciente.
ggplot(trm_df, aes(x = Fecha, y = TRM)) +
geom_line(color = "#0b3d62", linewidth = 0.5) +
scale_y_continuous(labels = scales::number_format(big.mark = ".",
decimal.mark = ",")) +
labs(x = NULL, y = "TRM (COP/USD)") +
theme_bw(base_size = 11)Figure 12.1: Serie histórica de la TRM oficial COP/USD (Superintendencia Financiera y Banco de la República), 7 de mayo de 2016 al 7 de mayo de 2026.
Para proyectar la TRM a 10 años se utilizó el movimiento Browniano geométrico (GBM), pero con una variación respecto a la formulación clásica de Shreve (2004): el retorno y la volatilidad no son constantes, sino que varían a lo largo del tiempo. La ecuación estándar del GBM es:
\[ S_{t} \;=\; S_{0} \cdot \exp\!\Big[ \big(\mu - \tfrac{1}{2}\sigma^{2}\big) t + \sigma\, W_{t} \Big] \]
En la propuesta de este trabajo, \(\mu\) y \(\sigma\) se estiman con una ventana deslizante (rolling window) sobre la serie diaria, lo que se traduce en parámetros indexados al tiempo:
\[ S_{t+\Delta t} \;=\; S_{t} \cdot \exp\!\Big[ \big(\mu_{t} - \tfrac{1}{2}\sigma_{t}^{2}\big) \Delta t + \sigma_{t} \sqrt{\Delta t}\, Z \Big], \quad Z \sim N(0,1) \]
Para el ejercicio se eligió una ventana de 870 datos diarios, equivalente al 23,8 % de la muestra total. Este tamaño se justifica como un punto de equilibrio: ventanas pequeñas producen pronósticos muy volátiles porque \(\mu\) y \(\sigma\) se mueven con el ruido de corto plazo, mientras que ventanas demasiado grandes hacen que los parámetros tiendan a sus medias muestrales y el modelo colapse a un GBM clásico (Cont, 2001). Como la ventana de 870 días no alcanza a estimar los primeros 870 datos, los parámetros faltantes se interpolan para mantener continuidad de la serie, en línea con la implementación clásica de Glasserman (2004).
# Replica fiel del script `dolar_spot.R`
# Inputs:
# datos: vector TRM diaria
# Fecha: vector Date paralelo
datos <- trm_df$TRM
Fecha <- trm_df$Fecha
# Retornos logaritmicos diarios y dt anualizado (calendario)
r <- diff(log(datos))
dt <- 1/365
W <- 870
Nret <- length(r)
mu_hist <- rep(0, Nret)
sigma_hist <- rep(0, Nret)
W0 <- min(W, Nret)
mu_ini <- mean(r[1:W0]) / dt
sigma_ini <- sd(r[1:W0]) / sqrt(dt)
mu_hist[1:W0] <- mu_ini
sigma_hist[1:W0] <- sigma_ini
if (Nret > W0) {
for (t in (W0 + 1):Nret) {
ventana <- r[(t - W + 1):t]
mu_hist[t] <- mean(ventana) / dt
sigma_hist[t] <- sd(ventana) / sqrt(dt)
}
}
# Horizonte futuro: 10 años calendario
anios <- 10
Nhor <- 365 * anios
t_hist <- 1:Nret
t_for <- seq(from = 1, to = Nret, length.out = Nhor - 1)
mu_t <- approx(t_hist, mu_hist, xout = t_for, rule = 2)$y
sigma_t <- approx(t_hist, sigma_hist, xout = t_for, rule = 2)$y
# Monte Carlo (semilla fija para reproducibilidad)
# Nota: el script `dolar_spot.R` original calcula solamente P35, P50 y P65.
# Aqui se amplia el calculo a P10, P25, P50, P75 y P90 para reportar el rango
# del 80 % (P10-P90) ademas del rango central del 50 % (P25-P75), que es la
# convencion estandar para reportes de pronostico (vease Hull, 2022).
set.seed(SEED_MASTER)
numSim <- 50
kPaths <- 30
X0 <- tail(datos, 1)
Q10 <- Q25 <- Q35 <- Q50 <- Q65 <- Q75 <- Q90 <-
matrix(NA, nrow = numSim, ncol = Nhor)
for (i in 1:numSim) {
matX <- matrix(NA, nrow = kPaths, ncol = Nhor)
for (p in 1:kPaths) {
S <- rep(NA, Nhor); S[1] <- X0
for (j in 2:Nhor) {
drift <- (mu_t[j-1] - 0.5 * sigma_t[j-1]^2) * dt
shock <- sigma_t[j-1] * sqrt(dt) * rnorm(1)
S[j] <- S[j-1] * exp(drift + shock)
}
matX[p, ] <- S
}
Q10[i, ] <- apply(matX, 2, quantile, probs = 0.10)
Q25[i, ] <- apply(matX, 2, quantile, probs = 0.25)
Q35[i, ] <- apply(matX, 2, quantile, probs = 0.35)
Q50[i, ] <- apply(matX, 2, quantile, probs = 0.50)
Q65[i, ] <- apply(matX, 2, quantile, probs = 0.65)
Q75[i, ] <- apply(matX, 2, quantile, probs = 0.75)
Q90[i, ] <- apply(matX, 2, quantile, probs = 0.90)
}
P10 <- colMeans(Q10); P25 <- colMeans(Q25); P35 <- colMeans(Q35)
P50 <- colMeans(Q50); P65 <- colMeans(Q65); P75 <- colMeans(Q75)
P90 <- colMeans(Q90)
# Compatibilidad con el resto del documento (mantengo nombres legacy):
TrayMed <- P50
BandaInf <- P35 # se conservan por compatibilidad con `fowards_creacion.R`
BandaSup <- P65
Fecha2 <- seq(from = max(Fecha) + 1, by = "day", length.out = Nhor)
mu_prom <- mean(mu_hist)
sigma_prom <- mean(sigma_hist)df_param <- data.frame(
Fecha = rep(Fecha[-1], 2),
Valor = c(mu_hist, sigma_hist),
Tipo = rep(c("μ (drift anual)", "σ (volatilidad anual)"),
each = length(mu_hist))
)
ggplot(df_param, aes(x = Fecha, y = Valor)) +
geom_line(color = "#0b3d62", linewidth = 0.5) +
geom_hline(data = data.frame(
Tipo = c("μ (drift anual)", "σ (volatilidad anual)"),
y = c(mu_prom, sigma_prom)),
aes(yintercept = y), color = "#7a0c0c", linetype = "dashed") +
facet_wrap(~ Tipo, ncol = 1, scales = "free_y") +
scale_y_continuous(labels = scales::percent_format(accuracy = 0.1)) +
labs(x = NULL, y = NULL) +
theme_bw(base_size = 11)Figure 13.1: \(\mu\) y \(\sigma\) estimados por ventana deslizante (rolling) sobre USD/COP diario. Líneas rojas punteadas: media histórica de cada parámetro.
La Figura 13.1 muestra el comportamiento de \(\mu\) y \(\sigma\) rolling. El retorno promedio estimado para el horizonte del pronóstico es de 3,20 % anualizado y la volatilidad promedio estimada es de 12,36 % anualizada. Se observa cómo la volatilidad sigue ciclos consistentes con eventos de mercado: contracción durante 2018 a 2019, choque pandémico en 2020 y aceleración 2022 a 2024 asociada a la incertidumbre fiscal y electoral.
df_hist <- data.frame(Fecha = Fecha, TRM = datos)
df_for <- data.frame(
Fecha = Fecha2,
P10 = P10, P25 = P25, P50 = P50, P75 = P75, P90 = P90
)
ggplot() +
geom_ribbon(data = df_for, aes(x = Fecha, ymin = P10, ymax = P90),
fill = "#3f7d20", alpha = 0.18) +
geom_ribbon(data = df_for, aes(x = Fecha, ymin = P25, ymax = P75),
fill = "#3f7d20", alpha = 0.32) +
geom_line(data = df_hist, aes(x = Fecha, y = TRM),
color = "#000000", linewidth = 0.6) +
geom_line(data = df_for, aes(x = Fecha, y = P50),
color = "#0b3d62", linewidth = 0.8) +
geom_vline(xintercept = max(Fecha),
color = "#7a0c0c", linetype = "dashed") +
scale_y_continuous(labels = scales::number_format(big.mark = ".",
decimal.mark = ",")) +
labs(x = NULL, y = "TRM (COP/USD)") +
theme_bw(base_size = 11)Figure 13.2: Pronóstico TRM Colombia (COP/USD) próximos 10 años. Línea azul: trayectoria media (P50). Banda verde claro: rango del 80 % (P10 a P90). Banda verde oscuro: rango central del 50 % (P25 a P75).
La Figura 13.2 presenta el pronóstico del USD/COP para los próximos 10 años. La línea azul es la trayectoria media (percentil 50). El rango del 80 % de las trayectorias simuladas (banda P10 a P90) se muestra en verde claro y el rango central del 50 % (P25 a P75) en verde oscuro. El uso de dos bandas concéntricas permite leer simultáneamente la zona modal del pronóstico y el rango plausible para decisiones de cobertura.
# Tomar el ultimo dia de cada año del horizonte (10 cortes anuales)
idx_y_pct <- pmin(seq(365, Nhor, by = 365), Nhor)
anios_lab <- as.integer(format(Fecha2[idx_y_pct], "%Y"))
tabla_pct <- data.frame(
Año = anios_lab,
P10 = fmt_num(P10[idx_y_pct], 0),
P25 = fmt_num(P25[idx_y_pct], 0),
Mediana = fmt_num(P50[idx_y_pct], 0),
P75 = fmt_num(P75[idx_y_pct], 0),
P90 = fmt_num(P90[idx_y_pct], 0),
`Rango 80%` = fmt_num(P90[idx_y_pct] - P10[idx_y_pct], 0),
check.names = FALSE
)
knitr::kable(
tabla_pct, align = "lrrrrrr",
caption = "Resumen anual del pronóstico GBM con ventana deslizante (cierre de cada año, COP/USD). Columnas: percentiles P10/P25/P50/P75/P90 y amplitud del rango P10-P90."
) |> kableExtra::kable_styling(full_width = FALSE,
bootstrap_options = c("hover","condensed"))| Año | P10 | P25 | Mediana | P75 | P90 | Rango 80% |
|---|---|---|---|---|---|---|
| 2027 | 3.219 | 3.416 | 3.676 | 3.969 | 4.237 | 1.018 |
| 2028 | 3.002 | 3.308 | 3.693 | 4.095 | 4.486 | 1.484 |
| 2029 | 2.925 | 3.266 | 3.746 | 4.206 | 4.727 | 1.802 |
| 2030 | 3.028 | 3.417 | 3.934 | 4.575 | 5.210 | 2.183 |
| 2031 | 3.167 | 3.627 | 4.300 | 5.091 | 5.885 | 2.718 |
| 2032 | 3.269 | 3.834 | 4.612 | 5.523 | 6.485 | 3.216 |
| 2033 | 3.333 | 4.045 | 4.991 | 6.138 | 7.317 | 3.984 |
| 2034 | 3.315 | 4.044 | 5.157 | 6.386 | 7.722 | 4.407 |
| 2035 | 3.154 | 3.856 | 5.005 | 6.483 | 7.919 | 4.764 |
| 2036 | 2.954 | 3.619 | 4.729 | 6.160 | 7.537 | 4.582 |
Al cierre del horizonte se proyecta una TRM media de 4.729 COP/USD. El rango central del 50 % (P25 a P75) se ubica entre 3.619 y 6.160, mientras que el rango ampliado del 80 % (P10 a P90) va desde 2.954 (escenario bajo) hasta 7.537 (escenario alto). La amplitud del rango P10-P90 al final del horizonte es de 4.582 pesos por dólar, una dispersión consistente con una volatilidad anualizada cercana al 12,4 % y con la persistencia leve de la TRM colombiana documentada para mercados emergentes (Cont, 2001). Estos rangos se utilizan como referencia para evaluar la efectividad de la cobertura forward en la sección 5.
El bien tiene un valor de COP 350.000.000. La conversión a dólares se realiza con la tasa de venta publicada por el portal Dólar Hoy (Dolar Hoy, 2026), que el día del análisis cotizaba en COP 3.730 por dólar, frente a una TRM oficial de COP 3.700 publicada por la Superintendencia Financiera (Superintendencia Financiera de Colombia, 2026). La diferencia (0,81 %) corresponde al margen comercial de la casa de cambio. El crédito se contrata con Investor Credit Partners (Investor Credit Partners, 2026), prestamista estadounidense especializado en equipment financing, a una tasa del 7 % efectivo anual y plazo de 10 años, con sistema francés y un abono inicial del 10 % del valor del bien.
V_bien_cop <- 350000000
TRM_compra <- 3730
TRM_oficial <- 3700
spread <- TRM_compra / TRM_oficial - 1
# Equivalente total en dolares
V_bien_usd <- V_bien_cop / TRM_compra
# Abono inicial (10 %) y saldo financiado
abono_ini_usd <- 0.10 * V_bien_usd
P_usd <- V_bien_usd - abono_ini_usd
# Sistema frances
i_usd <- 0.07
n_per <- 10
C_usd <- P_usd * (i_usd * (1 + i_usd)^n_per) / ((1 + i_usd)^n_per - 1)El equivalente total del bien en dólares es:
\[ \text{USD}_{\text{total}} = \frac{\text{COP } 350.000.000}{3.730} = \text{USD } 93.833,78 \]
Sobre este monto se aplica el abono inicial del 10 % (USD 9.383,38). El saldo a financiar es de USD 84.450,40, que se amortiza con sistema francés a 10 años y tasa del 7 % efectivo anual, lo que arroja una cuota anual de USD 12.023,84.
saldo <- numeric(n_per + 1); saldo[1] <- P_usd
intereses <- abono <- cuota <- numeric(n_per)
for (k in 1:n_per) {
intereses[k] <- saldo[k] * i_usd
cuota[k] <- C_usd
abono[k] <- cuota[k] - intereses[k]
saldo[k+1] <- saldo[k] - abono[k]
}
total_intereses_usd <- sum(intereses)
total_pagado_usd <- sum(cuota)
tabla_usd <- data.frame(
Periodo = 0:n_per,
Cuota = c(fmt_num(abono_ini_usd, 2), fmt_num(cuota, 2)),
Intereses= c("—", fmt_num(intereses, 2)),
`Abono capital` = c(fmt_num(abono_ini_usd, 2),
fmt_num(abono, 2)),
Saldo = c(fmt_num(P_usd, 2), fmt_num(saldo[-1], 2)),
check.names = FALSE
)
knitr::kable(
tabla_usd, align = "rrrrr",
caption = "Amortización del crédito en dólares (sistema francés, 7 % EA, 10 años, abono inicial del 10 %)."
) |> kableExtra::kable_styling(full_width = FALSE,
bootstrap_options = c("hover","condensed"))| Periodo | Cuota | Intereses | Abono capital | Saldo |
|---|---|---|---|---|
| 0 | 9.383,38 | — | 9.383,38 | 84.450,40 |
| 1 | 12.023,84 | 5.911,53 | 6.112,31 | 78.338,09 |
| 2 | 12.023,84 | 5.483,67 | 6.540,17 | 71.797,92 |
| 3 | 12.023,84 | 5.025,85 | 6.997,98 | 64.799,94 |
| 4 | 12.023,84 | 4.536,00 | 7.487,84 | 57.312,10 |
| 5 | 12.023,84 | 4.011,85 | 8.011,99 | 49.300,11 |
| 6 | 12.023,84 | 3.451,01 | 8.572,83 | 40.727,28 |
| 7 | 12.023,84 | 2.850,91 | 9.172,93 | 31.554,35 |
| 8 | 12.023,84 | 2.208,80 | 9.815,03 | 21.739,32 |
| 9 | 12.023,84 | 1.521,75 | 10.502,09 | 11.237,23 |
| 10 | 12.023,84 | 786,61 | 11.237,23 | 0,00 |
El periodo 0 corresponde al abono inicial de USD 9.383,38 y deja un saldo de USD 84.450,40. De ahí en adelante, las cuotas son constantes en USD 12.023,84 hasta el periodo 10. El total pagado en intereses asciende a USD 35.787,97 y el flujo total (capital más intereses) a USD 120.238,37, en línea con lo esperado para un francés a 7 % sobre 10 años.
# Mediana anual del pronostico para los 10 años de la cuota
idx_y <- pmin(seq(365, Nhor, by = 365), Nhor)
TRM_med <- TrayMed[idx_y]
TRM_venta <- TRM_med * (1 + spread)
cuota_cop <- C_usd * TRM_venta
intereses_cop <- intereses * TRM_venta
abono_cop <- abono * TRM_venta
# Saldo en pesos al cierre de cada periodo: saldo USD del periodo k * TRM_venta del periodo k
saldo_cop_sin <- saldo[-1] * TRM_venta
tabla_cop <- data.frame(
Periodo = 1:n_per,
`TRM media P50` = fmt_num(TRM_med, 2),
`TRM venta (+0,81 %)` = fmt_num(TRM_venta, 2),
`Cuota (COP)` = fmt_cop(cuota_cop, 0),
`Intereses (COP)` = fmt_cop(intereses_cop, 0),
`Abono (COP)` = fmt_cop(abono_cop, 0),
`Saldo (COP)` = fmt_cop(saldo_cop_sin, 0),
check.names = FALSE
)
knitr::kable(
tabla_cop, align = "rrrrrrr",
caption = "Amortización proyectada en COP sin cobertura, usando la mediana del pronóstico GBM y spread de la casa de cambio del 0,81 %. El saldo en pesos se calcula re-valuando el saldo USD remanente con la TRM proyectada de cada periodo."
) |> kableExtra::kable_styling(full_width = FALSE,
bootstrap_options = c("hover","condensed"))| Periodo | TRM media P50 | TRM venta (+0,81 %) | Cuota (COP) | Intereses (COP) | Abono (COP) | Saldo (COP) |
|---|---|---|---|---|---|---|
| 1 | 3.676,41 | 3.706,22 | COP 44.562.998 | COP 21.909.430 | COP 22.653.569 | COP 290.338.283 |
| 2 | 3.693,34 | 3.723,29 | COP 44.768.176 | COP 20.417.254 | COP 24.350.921 | COP 267.324.140 |
| 3 | 3.746,49 | 3.776,86 | COP 45.412.389 | COP 18.981.965 | COP 26.430.424 | COP 244.740.506 |
| 4 | 3.933,64 | 3.965,53 | COP 47.680.896 | COP 17.987.630 | COP 29.693.266 | COP 227.272.881 |
| 5 | 4.299,58 | 4.334,44 | COP 52.116.608 | COP 17.389.112 | COP 34.727.496 | COP 213.688.382 |
| 6 | 4.612,23 | 4.649,63 | COP 55.906.401 | COP 16.045.910 | COP 39.860.491 | COP 189.366.789 |
| 7 | 4.990,87 | 5.031,34 | COP 60.495.998 | COP 14.343.891 | COP 46.152.107 | COP 158.760.619 |
| 8 | 5.156,57 | 5.198,38 | COP 62.504.513 | COP 11.482.212 | COP 51.022.301 | COP 113.009.295 |
| 9 | 5.004,67 | 5.045,25 | COP 60.663.267 | COP 7.677.620 | COP 52.985.647 | COP 56.694.642 |
| 10 | 4.729,18 | 4.767,52 | COP 57.323.900 | COP 3.750.162 | COP 53.573.738 | COP 0 |
Para replicar la amortización en pesos se toma, año a año, la trayectoria media del pronóstico GBM con ventana deslizante y se aplica el spread del 0,81 % para obtener el precio efectivo de venta análogo al de Dólar Hoy. Con esa TRM proyectada se convierten las cuotas en dólares a pesos. El comportamiento de la amortización en pesos exhibe cuotas variables: aunque el flujo en dólares es constante, el equivalente en pesos cambia con la TRM. Bajo el escenario base, los intereses pagados en pesos suman aproximadamente COP 149.985.185, y al verificar el cociente entre intereses y saldo del periodo anterior se mantiene la tasa de 7 % en cada cuota, lo que confirma que la replicación es coherente con la financiera del crédito original. La diferencia con un crédito directo en pesos radica en que el saldo y el flujo dependen de la TRM en cada cuota, lo que deja al deudor expuesto a la depreciación. Esta exposición es precisamente la que se busca neutralizar (parcial o totalmente) con un forward de divisas.
Se decide cubrir las cuotas finales del crédito (años 7, 8, 9 y 10) por considerarse el tramo en el que la incertidumbre sobre la TRM es mayor y la sensibilidad del flujo en pesos más relevante. La metodología sigue la condición de paridad de tasas cubierta de Fisher (1930), también conocida como Covered Interest Rate Parity:
\[ F_{t} \;=\; S_{0} \cdot \left( \frac{1 + r_{\text{COP}}}{1 + r_{\text{USD}}} \right) \]
con \(r_{\text{USD}} = 4{,}36\%\) (U.S. Treasury 10Y, (U.S. Department of the Treasury, 2026)) y \(r_{\text{COP}}\) derivado de los TES de Colombia a 10 años (Ministerio de Hacienda y Crédito Público de Colombia, 2026), lo que produce una devaluación implícita anual de 8,7 %.
# Pronostico desde inicio de los anios 6, 7, 8 y 9 (cobertura de cuotas 7, 8, 9 y 10)
# Replica de `fowards_creacion.R`
anios_base <- c(6, 7, 8, 9)
deval_imp <- 0.087 # devaluacion implicita anual
# Spots iniciales (TrayMed al final de cada anio base)
# Nota metodologica: el script original indexa por anio*252 sobre una serie
# en dias calendario; aqui replicamos esa misma indexacion para preservar
# coherencia con los resultados publicados en el procedimiento.
idx_base <- anios_base * 252
spots_ini <- TrayMed[idx_base]
forwards <- spots_ini * (1 + deval_imp)
tabla_fwd <- data.frame(
`Cuota a cubrir` = paste0(anios_base + 1,
" (vencimiento año ",
anios_base + 1,
", inicio año ",
anios_base, ")"),
`Spot inicial pronosticado (COP)` = fmt_num(spots_ini, 2),
`Forward teórico (COP)` = fmt_num(forwards, 2),
check.names = FALSE
)
knitr::kable(
tabla_fwd, align = "lrr",
caption = "Forwards teóricos calculados con devaluación implícita de 8,7 % anual sobre cada spot pronosticado."
) |> kableExtra::kable_styling(full_width = FALSE,
bootstrap_options = c("hover","condensed"))| Cuota a cubrir | Spot inicial pronosticado (COP) | Forward teórico (COP) |
|---|---|---|
| 7 (vencimiento año 7, inicio año 6) | 3.980,37 | 4.326,67 |
| 8 (vencimiento año 8, inicio año 7) | 4.267,47 | 4.638,74 |
| 9 (vencimiento año 9, inicio año 8) | 4.475,48 | 4.864,84 |
| 10 (vencimiento año 10, inicio año 9) | 4.686,17 | 5.093,87 |
Adicionalmente se simula la trayectoria del par USDCOP=X (tomado de Yahoo Finance (Yahoo Finance, 2026f)) con la misma metodología de GBM con ventana deslizante. Las dos series (TRM oficial del Banco de la República y USDCOP=X de Yahoo Finance) tienen frecuencias y conteos distintos: la TRM oficial es diaria calendario (3.653 obs., \(\Delta t = 1/365\)) y la serie de Yahoo Finance es diaria bursátil (2.604 obs., \(\Delta t = 1/252\), sin fines de semana ni festivos). Por esa razón la ventana rolling se reduce de 870 a 650 datos en la serie de Yahoo, manteniendo una proporción equivalente de la muestra.
# Replica de `pronotico_copusdx.R` (USDCOP=X, dt=1/252, W=650)
y_datos <- yh_df$Close
y_Fecha <- yh_df$Fecha
y_r <- diff(log(y_datos))
y_dt <- 1/252
y_W <- 650
y_Nret <- length(y_r)
y_mu_h <- rep(0, y_Nret)
y_sigma_h <- rep(0, y_Nret)
y_W0 <- min(y_W, y_Nret)
y_mu_h[1:y_W0] <- mean(y_r[1:y_W0]) / y_dt
y_sigma_h[1:y_W0] <- sd(y_r[1:y_W0]) / sqrt(y_dt)
if (y_Nret > y_W0) {
for (t in (y_W0 + 1):y_Nret) {
v <- y_r[(t - y_W + 1):t]
y_mu_h[t] <- mean(v) / y_dt
y_sigma_h[t] <- sd(v) / sqrt(y_dt)
}
}
y_anios <- 10
y_Nhor <- 252 * y_anios
t_h_y <- 1:y_Nret
t_f_y <- seq(1, y_Nret, length.out = y_Nhor - 1)
y_mu_t <- approx(t_h_y, y_mu_h, xout = t_f_y, rule = 2)$y
y_sigma_t <- approx(t_h_y, y_sigma_h, xout = t_f_y, rule = 2)$y
set.seed(SEED_MASTER + 1)
y_X0 <- tail(y_datos, 1)
y_numSim <- 50
y_kPaths <- 30
y_Q10 <- y_Q25 <- y_Q35 <- y_Q50 <- y_Q65 <- y_Q75 <- y_Q90 <-
matrix(NA, nrow = y_numSim, ncol = y_Nhor)
y_TodasSim_list <- vector("list", y_numSim)
for (i in 1:y_numSim) {
matX <- matrix(NA, nrow = y_kPaths, ncol = y_Nhor)
for (p in 1:y_kPaths) {
S <- rep(NA, y_Nhor); S[1] <- y_X0
for (j in 2:y_Nhor) {
drift <- (y_mu_t[j-1] - 0.5 * y_sigma_t[j-1]^2) * y_dt
shock <- y_sigma_t[j-1] * sqrt(y_dt) * rnorm(1)
S[j] <- S[j-1] * exp(drift + shock)
}
matX[p, ] <- S
}
y_Q10[i, ] <- apply(matX, 2, quantile, probs = 0.10)
y_Q25[i, ] <- apply(matX, 2, quantile, probs = 0.25)
y_Q35[i, ] <- apply(matX, 2, quantile, probs = 0.35)
y_Q50[i, ] <- apply(matX, 2, quantile, probs = 0.50)
y_Q65[i, ] <- apply(matX, 2, quantile, probs = 0.65)
y_Q75[i, ] <- apply(matX, 2, quantile, probs = 0.75)
y_Q90[i, ] <- apply(matX, 2, quantile, probs = 0.90)
y_TodasSim_list[[i]] <- matX
}
y_P10 <- colMeans(y_Q10); y_P25 <- colMeans(y_Q25); y_P35 <- colMeans(y_Q35)
y_P50 <- colMeans(y_Q50); y_P65 <- colMeans(y_Q65); y_P75 <- colMeans(y_Q75)
y_P90 <- colMeans(y_Q90)
y_TrayMed <- y_P50
y_BandaInf <- y_P35 # compatibilidad con bloques posteriores
y_BandaSup <- y_P65
y_TodasSim <- do.call(rbind, y_TodasSim_list)
y_Fecha2 <- seq(from = max(y_Fecha) + 1, by = "day", length.out = y_Nhor)df_y_for <- data.frame(
Fecha = y_Fecha2,
P10 = y_P10, P25 = y_P25, P50 = y_P50, P75 = y_P75, P90 = y_P90
)
ggplot() +
geom_ribbon(data = df_y_for, aes(x = Fecha, ymin = P10, ymax = P90),
fill = "#3f7d20", alpha = 0.18) +
geom_ribbon(data = df_y_for, aes(x = Fecha, ymin = P25, ymax = P75),
fill = "#3f7d20", alpha = 0.32) +
geom_line(data = yh_df, aes(x = Fecha, y = Close),
color = "#000000", linewidth = 0.6) +
geom_line(data = df_y_for, aes(x = Fecha, y = P50),
color = "#0b3d62", linewidth = 0.8) +
geom_vline(xintercept = max(y_Fecha),
color = "#7a0c0c", linetype = "dashed") +
scale_y_continuous(labels = scales::number_format(big.mark = ".",
decimal.mark = ",")) +
labs(x = NULL, y = "USD/COP") +
theme_bw(base_size = 11)Figure 15.1: Pronóstico USD/COP a 10 años (USDCOP=X, Yahoo Finance) con GBM de ventana deslizante de 650 datos. Banda externa: P10 a P90. Banda interna: P25 a P75.
Las bandas son más anchas que las del pronóstico TRM porque el par USDCOP=X recoge más oferta y demanda intradía y por tanto presenta mayor volatilidad. Al cierre del horizonte, el pronóstico medio del USDCOP=X es 4.736 COP/USD. El rango central del 50 % (P25 a P75) va de 3.334 a 6.551, y el rango del 80 % (P10 a P90) va de 2.533 a 8.854.
# Pronostico desde el inicio de los anios 6, 7, 8 y 9
# Replica de `fowards_creacion.R`
Nhor_local <- 252
numSim_loc <- 50
kPaths_loc <- 30
ProbSup <- ProbInf <- numeric(length(anios_base))
# Almacenes para los graficos por anio
list_traym <- vector("list", length(anios_base))
list_band20 <- vector("list", length(anios_base))
list_band80 <- vector("list", length(anios_base))
list_fecha <- vector("list", length(anios_base))
list_X0 <- numeric(length(anios_base))
set.seed(SEED_MASTER + 2)
for (a in seq_along(anios_base)) {
idx_b <- anios_base[a] * 252
X0_l <- TrayMed[idx_b]
list_X0[a] <- X0_l
idx_mu_fin <- idx_b - 1
idx_mu_ini <- idx_mu_fin - 251
mu_l <- mu_t[idx_mu_ini:idx_mu_fin]
sigma_l <- sigma_t[idx_mu_ini:idx_mu_fin]
Fecha_l <- seq(from = Fecha2[idx_b] + 1, by = "days",
length.out = Nhor_local)
list_fecha[[a]] <- Fecha_l
TodasSim_l <- matrix(NA, nrow = numSim_loc * kPaths_loc,
ncol = Nhor_local)
cnt <- 1
for (i in 1:numSim_loc) {
for (p in 1:kPaths_loc) {
S <- rep(NA, Nhor_local); S[1] <- X0_l
for (j in 2:Nhor_local) {
idx_roll <- min(j - 1, 252)
drift <- (mu_l[idx_roll] - 0.5 * sigma_l[idx_roll]^2) * dt
shock <- sigma_l[idx_roll] * sqrt(dt) * rnorm(1)
S[j] <- S[j-1] * exp(drift + shock)
}
TodasSim_l[cnt, ] <- S
cnt <- cnt + 1
}
}
list_traym[[a]] <- apply(TodasSim_l, 2, quantile, probs = 0.50)
list_band80[[a]] <- apply(TodasSim_l, 2, quantile, probs = 0.80)
list_band20[[a]] <- apply(TodasSim_l, 2, quantile, probs = 0.20)
ValorFinal <- TodasSim_l[, Nhor_local]
q80 <- quantile(ValorFinal, 0.80)
q20 <- quantile(ValorFinal, 0.20)
acotados <- ValorFinal[ValorFinal >= q20 & ValorFinal <= q80]
valor_obj <- forwards[a]
ProbSup[a] <- mean(acotados >= valor_obj) * 100
ProbInf[a] <- mean(acotados < valor_obj) * 100
}A diferencia del pronóstico global a 10 años (Figuras anteriores), donde se reportan dos bandas concéntricas (P10 a P90 y P25 a P75) sobre la trayectoria media, en los pronósticos por año (Figura 15.2) las bandas se acotan a P20 a P80 con el fin de capturar el rango plausible alrededor del forward objetivo a un horizonte de un año. Esta acotación responde a que, en el ejercicio de cobertura cuota a cuota, interesa cuantificar la zona donde se concentra la mayor parte de la masa de probabilidad (no la cola extrema), ya que es esa zona la que determina si el forward agrega o no valor económico al deudor.
df_panel <- do.call(rbind, lapply(seq_along(anios_base), function(a) {
data.frame(
Fecha = list_fecha[[a]],
P20 = list_band20[[a]],
P50 = list_traym[[a]],
P80 = list_band80[[a]],
Anio = paste0("Pronóstico desde año ", anios_base[a],
" (cobertura cuota ", anios_base[a] + 1, ")"),
Valor_Obj = forwards[a],
X0_Inicio = list_X0[a],
Fecha_Inicio = list_fecha[[a]][1] - 1
)
}))
df_punto <- df_panel |>
dplyr::group_by(Anio) |>
dplyr::slice(1) |>
dplyr::ungroup()
ggplot(df_panel, aes(x = Fecha)) +
geom_ribbon(aes(ymin = P20, ymax = P80),
fill = "#3f7d20", alpha = 0.30) +
geom_line(aes(y = P50), color = "#0b3d62", linewidth = 0.7) +
geom_hline(aes(yintercept = Valor_Obj),
color = "#7a0c0c", linetype = "dashed") +
geom_point(data = df_punto, aes(x = Fecha_Inicio, y = X0_Inicio),
color = "#7a0c0c", size = 2.5) +
facet_wrap(~ Anio, ncol = 2, scales = "free") +
scale_y_continuous(labels = scales::number_format(big.mark = ".",
decimal.mark = ",")) +
labs(x = NULL, y = "USD/COP") +
theme_bw(base_size = 11)Figure 15.2: Pronósticos por año (cuotas 7, 8, 9 y 10). Punto rojo: spot inicial. Línea roja punteada: forward teórico (valor objetivo). Bandas P20 a P80.
df_cob <- data.frame(
Anio = anios_base,
Superior = ProbSup,
Inferior = ProbInf
) |> tidyr::pivot_longer(cols = c(Superior, Inferior),
names_to = "Posicion", values_to = "Prob")
ggplot(df_cob, aes(x = factor(Anio), y = Prob, fill = Posicion)) +
geom_col(width = 0.65) +
geom_text(aes(label = sprintf("%.1f %%", Prob)),
position = position_stack(vjust = 0.5),
color = "white", size = 3.2) +
scale_fill_manual(values = c(Superior = "#0b3d62",
Inferior = "#e07b39"),
labels = c(Superior = "Superior al forward",
Inferior = "Inferior al forward")) +
labs(x = "Año de inicio de la cobertura",
y = "Probabilidad (%)", fill = NULL) +
theme_bw(base_size = 11) +
theme(legend.position = "top")Figure 15.3: Probabilidad acotada (banda P20 a P80) de que el spot final supere o sea inferior al forward teórico, por año de inicio de la cobertura. Lectura: en menos del 30 % de los escenarios el deudor habría obtenido beneficio cubriéndose.
La Figura 15.3 resume el resultado clave del análisis. Para cada año base (6, 7, 8 y 9) se compara el spot final simulado (al cabo de un año, vencimiento de la cuota correspondiente) con el forward teórico: 29,0 % de las trayectorias supera el forward COP 4.326,67 del año base 6, 39,9 % supera el forward COP 4.638,74 del año base 7, 24,0 % supera el forward COP 4.864,84 del año base 8 y 24,9 % supera el forward COP 5.093,87 del año base 9. En otras palabras, en más del 70 % de los escenarios el deudor habría pagado más con la cobertura que sin ella, lo que es un primer indicio de que la cobertura no es viable en términos esperados, dada la devaluación implícita asumida.
# TRM aplicada por anio:
# Anios 1 a 6: TRM media P50 + spread (sin cobertura)
# Anios 7 a 10: forwards teoricos (cobertura)
TRM_aplicada <- TRM_venta
TRM_aplicada[7:10] <- forwards # cuotas 7..10 cubiertas
cuota_cob <- C_usd * TRM_aplicada
intereses_cob <- intereses * TRM_aplicada
abono_cob <- abono * TRM_aplicada
saldo_cob_cop <- saldo[-1] * TRM_aplicada
tabla_cob <- data.frame(
Periodo = 1:n_per,
`TRM/Forward aplicado` = c(rep("TRM venta", 6),
rep("Forward teórico", 4)),
`Tasa (COP/USD)` = fmt_num(TRM_aplicada, 2),
`Cuota (COP)` = fmt_cop(cuota_cob, 0),
`Intereses (COP)`= fmt_cop(intereses_cob, 0),
`Abono (COP)` = fmt_cop(abono_cob, 0),
`Saldo (COP)` = fmt_cop(saldo_cob_cop, 0),
check.names = FALSE
)
knitr::kable(
tabla_cob, align = "rlrrrrr",
caption = "Amortización en COP con cobertura forward sobre las cuotas 7, 8, 9 y 10. El saldo en pesos se valoriza con la TRM proyectada en los años no cubiertos y con el forward teórico en los años cubiertos."
) |> kableExtra::kable_styling(full_width = FALSE,
bootstrap_options = c("hover","condensed"))| Periodo | TRM/Forward aplicado | Tasa (COP/USD) | Cuota (COP) | Intereses (COP) | Abono (COP) | Saldo (COP) |
|---|---|---|---|---|---|---|
| 1 | TRM venta | 3.706,22 | COP 44.562.998 | COP 21.909.430 | COP 22.653.569 | COP 290.338.283 |
| 2 | TRM venta | 3.723,29 | COP 44.768.176 | COP 20.417.254 | COP 24.350.921 | COP 267.324.140 |
| 3 | TRM venta | 3.776,86 | COP 45.412.389 | COP 18.981.965 | COP 26.430.424 | COP 244.740.506 |
| 4 | TRM venta | 3.965,53 | COP 47.680.896 | COP 17.987.630 | COP 29.693.266 | COP 227.272.881 |
| 5 | TRM venta | 4.334,44 | COP 52.116.608 | COP 17.389.112 | COP 34.727.496 | COP 213.688.382 |
| 6 | TRM venta | 4.649,63 | COP 55.906.401 | COP 16.045.910 | COP 39.860.491 | COP 189.366.789 |
| 7 | Forward teórico | 4.326,67 | COP 52.023.123 | COP 12.334.932 | COP 39.688.191 | COP 136.525.116 |
| 8 | Forward teórico | 4.638,74 | COP 55.775.487 | COP 10.246.075 | COP 45.529.412 | COP 100.843.094 |
| 9 | Forward teórico | 4.864,84 | COP 58.494.073 | COP 7.403.084 | COP 51.090.988 | COP 54.667.358 |
| 10 | Forward teórico | 5.093,87 | COP 61.247.870 | COP 4.006.870 | COP 57.241.000 | COP 0 |
ahorro_anual <- cuota_cop - cuota_cob # > 0 si cubrir conviene
tabla_comp <- data.frame(
Periodo = 1:n_per,
`Cuota sin cobertura (COP)` = fmt_cop(cuota_cop, 0),
`Cuota con cobertura (COP)` = fmt_cop(cuota_cob, 0),
`Diferencia (COP)` = fmt_cop(ahorro_anual, 0),
check.names = FALSE
)
knitr::kable(
tabla_comp, align = "rrrr",
caption = "Comparación cobertura forward (cuotas 7 a 10) frente a escenario sin cobertura (mediana del pronóstico GBM)."
) |> kableExtra::kable_styling(full_width = FALSE,
bootstrap_options = c("hover","condensed"))| Periodo | Cuota sin cobertura (COP) | Cuota con cobertura (COP) | Diferencia (COP) |
|---|---|---|---|
| 1 | COP 44.562.998 | COP 44.562.998 | COP 0 |
| 2 | COP 44.768.176 | COP 44.768.176 | COP 0 |
| 3 | COP 45.412.389 | COP 45.412.389 | COP 0 |
| 4 | COP 47.680.896 | COP 47.680.896 | COP 0 |
| 5 | COP 52.116.608 | COP 52.116.608 | COP 0 |
| 6 | COP 55.906.401 | COP 55.906.401 | COP 0 |
| 7 | COP 60.495.998 | COP 52.023.123 | COP 8.472.875 |
| 8 | COP 62.504.513 | COP 55.775.487 | COP 6.729.026 |
| 9 | COP 60.663.267 | COP 58.494.073 | COP 2.169.195 |
| 10 | COP 57.323.900 | COP 61.247.870 | COP -3.923.970 |
Comparando con la amortización en pesos sin cobertura, la versión cubierta termina pagando más dinero. La razón es que en las simulaciones realizadas con el GBM de ventana deslizante los precios medios estimados para los años 7, 8, 9 y 10 son COP 4.267,47, COP 4.475,48, COP 4.686,17 y COP 4.729,18 (proyección directa para el cierre de año 10), una trayectoria que sugiere revalorización del peso en el tramo final del horizonte. En contraste, la cobertura con devaluación implícita del 8,7 % anual produce forwards teóricos uniformemente más altos (COP 4.326,67, COP 4.638,74, COP 4.864,84 y COP 5.093,87). El costo total bajo cobertura es de COP 517.988.019 frente a COP 531.435.145 sin cobertura, es decir un sobrecosto de COP -13.447.125 equivalente al -2,53 % del flujo total.
Desde el punto de vista de la cobertura efectiva del crédito asociado a la maquinaria amarilla, los forwards eliminan la incertidumbre sobre la TRM en las cuotas 7 a 10 y garantizan un flujo en pesos conocido al cierre. Esto tiene valor estratégico para la planeación financiera de la operación productiva (presupuesto de operación, costos de mantenimiento, contratos de servicio asociados a la maquinaria), incluso si el costo esperado es superior al de la posición abierta (Hull, 2022). En términos de rentabilidad, la cobertura no aporta valor económico esperado bajo los supuestos del modelo, pero sí actúa como un seguro contra escenarios de cola (crisis política, choque externo, deterioro fiscal) en los que la TRM podría superar holgadamente los forwards teóricos.
dolar_spot.R, pronotico_copusdx.R, fowards_creacion.R) preserva la lógica numérica y los parámetros (W=870, dt=1/365 para TRM Banrep; W=650, dt=1/252 para USDCOP=X de Yahoo Finance).