Este taller práctico simula una situación real donde, como inversores, requerimos financiar la adquisición de maquinaria amarilla por 300 millones de pesos a través de un crédito estadounidense a 10 años con sistema de pago francés. Dado que los pagos del crédito se realizarán en dólares mientras nuestros ingresos son en pesos colombianos, implementaremos una estrategia de cobertura utilizando futuros de TRM. Se realizará una cobertura del 75% de la inversión durante los últimos cuatro años del crédito, período en el cual se anticipa mayor volatilidad cambiaria y una posible apreciación del dólar. A través de este ejercicio, aplicaremos conceptos fundamentales de derivados financieros, específicamente el uso de futuros como instrumento de cobertura, empleando datos históricos de la Bolsa de Valores de Colombia y replicando las condiciones reales del mercado financiero.
options(repos = c(CRAN = "https://cran.rstudio.com/"))
install.packages("citmre")
## Installing package into 'C:/Users/jmora/AppData/Local/R/win-library/4.3'
## (as 'lib' is unspecified)
## package 'citmre' successfully unpacked and MD5 sums checked
##
## The downloaded binary packages are in
## C:\Users\jmora\AppData\Local\Temp\RtmpKmpovb\downloaded_packages
library(citmre)
## Warning: package 'citmre' was built under R version 4.3.3
rmre_data()
## rmre
## 1991-12-02 643.42
## 1991-12-03 639.22
## 1991-12-04 635.70
## 1991-12-05 631.51
## 1991-12-06 627.16
## 1991-12-09 638.06
## 1991-12-10 622.92
## 1991-12-11 627.46
## 1991-12-12 633.09
## 1991-12-13 632.35
## ...
## 2025-09-09 3945.29
## 2025-09-10 3919.13
## 2025-09-11 3921.58
## 2025-09-12 3903.18
## 2025-09-15 3906.24
## 2025-09-16 3897.57
## 2025-09-17 3881.92
## 2025-09-18 3880.01
## 2025-09-19 3892.45
## 2025-09-22 3891.19
data <- rmre_data(start_date = "2015-01-01", end_date = "2025-09-15")
head(data)
## rmre
## 2015-01-02 2392.46
## 2015-01-05 2383.37
## 2015-01-06 2412.82
## 2015-01-07 2452.11
## 2015-01-08 2434.31
## 2015-01-09 2405.03
data_m <- rmre_data(start_date = "2015-01-01", end_date = "2025-09-15", frequency = 12)
head(data_m)
## rmre
## 2015-01-31 2397.35
## 2015-02-28 2484.58
## 2015-03-31 2598.36
## 2015-04-30 2388.06
## 2015-05-31 2533.79
## 2015-06-30 2598.68
data_log <- rmre_data(start_date = "2015-01-01", end_date = "2025-09-15", log_return = TRUE)
head(data_log)
## log_return
## 2015-01-05 -0.0038066728
## 2015-01-06 0.0122807354
## 2015-01-07 0.0161526905
## 2015-01-08 -0.0072855296
## 2015-01-09 -0.0121009713
## 2015-01-13 0.0006982921
plot(data_m)
La TRM constituye el promedio aritmético de las cotizaciones ponderadas resultantes de las transacciones de compra y venta de dólares estadounidenses por pesos colombianos, ejecutadas por entidades del sistema financiero nacional incluyendo bancos comerciales, corporaciones financieras, comisionistas de bolsa, compañías de financiamiento, la FDN y Bancoldex. Estas operaciones se caracterizan por su liquidación inmediata en ambas divisas el mismo día de contratación (Banco de la República de Colombia, s.f.).
Contexto Macroeconómico Actual (2025)
En agosto de 2025, la inflación interanual en Colombia fue de 4,85%, inferior al 4,89% observado en julio. La persistencia de la inflación por encima de la meta del 3% anual establecida por la Junta Directiva del Banco de la República, mantiene la presión sobre la política monetaria y genera expectativas de un proceso de convergencia más lento de lo inicialmente previsto. La economía colombiana muestra una recuperación moderada, con un crecimiento estimado del 2,6% en 2025 y una proyección de 3,4% para 2026. Esta mejora estaría sustentada en una política monetaria más flexible y en la reducción gradual de la inflación (Banco de la República, Informe de Política Monetaria, 2025).
Análisis de Tendencias Recientes
Durante la ventana temporal comprendida entre el segundo semestre de 2024 y la fecha actual, la TRM ha exhibido una tendencia a la baja, reflejando un fortalecimiento sostenido del peso colombiano frente al dólar estadounidense. Esta dinámica,ha estado influenciada por factores de política monetaria tanto domésticos como internacionales.
En la búsqueda de controlar la inflación y hacer más atractivo el peso colombiano para la inversión extranjera de corto plazo, el BanRep ha mantenido la tasa de interés de política monetaria en un nivel relativamente alto (9,25% a partir de mayo), lo que ha contribuido a la apreciación del peso, por otro lado, el Sistema de la Reserva Federal (FED) ha implemetado recortes graduales en sus tasas de referencia, debilitando la posición relativa del dólar.
Proyecciones y Expectativas del Mercado
Los resultados de la Encuesta Mensual de Expectativas (EME) del Banco de la República correspondiente a julio de 2025 revelan una perspectiva contradictoria pero reveladora: el consentimiento del mercado anticipa una depreciación gradual pero sostenida del peso colombiano, proyectando que la TRM alcance niveles de $4,180-$4,200 hacia finales de 2026, lo que representa una depreciación aproximada del 3.4% anual desde los niveles actuales. Sin embargo, la alta dispersión de los datos analizados de la encuesta, resalta que el futuro de la TRM dependerá de la evolución de múltiples factores económicos, tanto globales como nacionales.
Para la construcción de la simulación se tomará el histórico de la TRM de los últimos 10 años, estos datos son obtenidos desde el aplicativo RStudio a través de un paquete llamado Citmre, con histórico de la TRM, se realiza la conversión de los datos a periodos mensuales.
options ( scipen = 999)
set.seed (2134)
sigma <- sd(data_log$log_return)
mu <- mean(data_log$log_return)
s0 <- tail(data_m$rmre, 1)
N =10000
T =120
vec = rep (s0 ,N)
mb= matrix ( ncol =N, nrow =T)
mb [1 ,]= vec
for (i in 1:N) {
for (t in 2:T) {
mb[t,i]= mb [(t -1) ,i]* exp ((mu -(0.5 *( sigma ^2) ))*(1/ 252) +
sigma *(1/ (252) ^(1 /2))* qnorm ( runif (1, min = 0, max = 1)))
}
}
df_mb <- data.frame(Mes = 1:T, TRM = as.vector(mb))
matplot (mb , type ="l")
q1= quantile (mb[T ,], 0.975)
q2= quantile (mb[T ,], 0.025)
plot ( density (mb[T ,]) , ylab ="", xlab ="",
main =" Distribución normal ", lwd = 3)
abline (h=NULL , v=q1 , col = " blue ",lwd = 2)
abline (h=NULL , v=q2 , col = " green ",lwd = 2)
Los resultados de la simulación a 10 años revelan un comportamiento
relativamente estable de la TRM con un rendimiento mensual promedio de
0.019331% (equivalente a aproximadamente 0.23% anual), lo que sugiere
una depreciación muy gradual del peso colombiano frente al dólar
estadounidense. La volatilidad mensual de 0.8542% (aproximadamente 2.96%
anualizada) indica un nivel de fluctuación moderado, esta volatilidad
relativamente contenida sugiere que, aunque existen períodos de mayor
incertidumbre cambiaria, la TRM no presenta movimientos extremos
sostenidos, lo que valida la efectividad de las políticas de
estabilización del Banco de la República y la robustez del régimen
cambiario flexible.
Para la compra de la maquinaria amarilla el valor de la TRM del día 15 de septiembre de 2025, la cual fue de 3.906,24 y un valor total a financiar de 65280,17 USD, equivalente al 85% del crédito total, este queda con cuotas fijas mensuales a 10 años y se utilizó una tasa comercial del 16.99% APR (Citibank).
Posterior a la simulación del comportamiento de la TRM, se seleccionaron tres escenarios clave que servirán como base para estrategias de cobertura con el futuro de TRX.
Simulación de Mayor Dispersión
En este se evidencia una máxima volatilidad y una tendencia alcista por lo cual se asumiría una posición larga para tener una mejor cobertura en futuros TRX.
Simulación de Menor Dispersión
En este se evidencia una mínima volatilidad y una tendencia bajista por lo cual se asumiría una posición corta para tener una mejor cobertura en futuros TRM contra depreciación del dólar.
Simulación Promedio Escenario más probable estadísticamente y en este es en que se va a hacer un análisis más profundo y con base a este se van a generar una estrategia de cobertura y de gestión de riesgo con base a los datos generados en las simulaciones del futuro en TRX. Al tener presente los dos escenarios extremos se busca mostrar un análisis de más objetivo al no estar en los límites, pero teniéndolos presentes en medio del estudio realizado.
# Parámetros del préstamo
P <- (300000000/3906.24)*0.85
# tasa citibank 16.99% APR
E_A <- (1+0.1699/12)^12-1
i_annual <- E_A
n_months <- 120
i <- (1+E_A)^(1/12)-1
n <- n_months
cuota <- P * (i * (1 + i)^n) / ((1 + i)^n - 1)
tabla <- data.frame(
Periodo = 1:n,
Cuota = rep(round(cuota, 2), n),
Interes = numeric(n),
Amortizacion = numeric(n),
Saldo = numeric(n)
)
saldo_restante <- P
for (t in 1:n) {
interes <- round(saldo_restante * i, 2)
amortizacion <- round(cuota - interes, 2)
saldo_restante <- round(saldo_restante - amortizacion, 2)
tabla$Interes[t] <- interes
tabla$Amortizacion[t] <- amortizacion
tabla$Saldo[t] <- ifelse(saldo_restante < 0, 0, saldo_restante)
}
print(tabla)
## Periodo Cuota Interes Amortizacion Saldo
## 1 1 1134.14 924.26 209.88 65070.29
## 2 2 1134.14 921.29 212.85 64857.44
## 3 3 1134.14 918.27 215.87 64641.57
## 4 4 1134.14 915.22 218.92 64422.65
## 5 5 1134.14 912.12 222.02 64200.63
## 6 6 1134.14 908.97 225.17 63975.46
## 7 7 1134.14 905.79 228.35 63747.11
## 8 8 1134.14 902.55 231.59 63515.52
## 9 9 1134.14 899.27 234.87 63280.65
## 10 10 1134.14 895.95 238.19 63042.46
## 11 11 1134.14 892.58 241.56 62800.90
## 12 12 1134.14 889.16 244.98 62555.92
## 13 13 1134.14 885.69 248.45 62307.47
## 14 14 1134.14 882.17 251.97 62055.50
## 15 15 1134.14 878.60 255.54 61799.96
## 16 16 1134.14 874.98 259.16 61540.80
## 17 17 1134.14 871.32 262.82 61277.98
## 18 18 1134.14 867.59 266.55 61011.43
## 19 19 1134.14 863.82 270.32 60741.11
## 20 20 1134.14 859.99 274.15 60466.96
## 21 21 1134.14 856.11 278.03 60188.93
## 22 22 1134.14 852.17 281.97 59906.96
## 23 23 1134.14 848.18 285.96 59621.00
## 24 24 1134.14 844.13 290.01 59330.99
## 25 25 1134.14 840.03 294.11 59036.88
## 26 26 1134.14 835.86 298.28 58738.60
## 27 27 1134.14 831.64 302.50 58436.10
## 28 28 1134.14 827.36 306.78 58129.32
## 29 29 1134.14 823.01 311.13 57818.19
## 30 30 1134.14 818.61 315.53 57502.66
## 31 31 1134.14 814.14 320.00 57182.66
## 32 32 1134.14 809.61 324.53 56858.13
## 33 33 1134.14 805.02 329.12 56529.01
## 34 34 1134.14 800.36 333.78 56195.23
## 35 35 1134.14 795.63 338.51 55856.72
## 36 36 1134.14 790.84 343.30 55513.42
## 37 37 1134.14 785.98 348.16 55165.26
## 38 38 1134.14 781.05 353.09 54812.17
## 39 39 1134.14 776.05 358.09 54454.08
## 40 40 1134.14 770.98 363.16 54090.92
## 41 41 1134.14 765.84 368.30 53722.62
## 42 42 1134.14 760.62 373.52 53349.10
## 43 43 1134.14 755.33 378.81 52970.29
## 44 44 1134.14 749.97 384.17 52586.12
## 45 45 1134.14 744.53 389.61 52196.51
## 46 46 1134.14 739.02 395.12 51801.39
## 47 47 1134.14 733.42 400.72 51400.67
## 48 48 1134.14 727.75 406.39 50994.28
## 49 49 1134.14 721.99 412.15 50582.13
## 50 50 1134.14 716.16 417.98 50164.15
## 51 51 1134.14 710.24 423.90 49740.25
## 52 52 1134.14 704.24 429.90 49310.35
## 53 53 1134.14 698.15 435.99 48874.36
## 54 54 1134.14 691.98 442.16 48432.20
## 55 55 1134.14 685.72 448.42 47983.78
## 56 56 1134.14 679.37 454.77 47529.01
## 57 57 1134.14 672.93 461.21 47067.80
## 58 58 1134.14 666.40 467.74 46600.06
## 59 59 1134.14 659.78 474.36 46125.70
## 60 60 1134.14 653.06 481.08 45644.62
## 61 61 1134.14 646.25 487.89 45156.73
## 62 62 1134.14 639.34 494.80 44661.93
## 63 63 1134.14 632.34 501.80 44160.13
## 64 64 1134.14 625.23 508.91 43651.22
## 65 65 1134.14 618.03 516.11 43135.11
## 66 66 1134.14 610.72 523.42 42611.69
## 67 67 1134.14 603.31 530.83 42080.86
## 68 68 1134.14 595.79 538.35 41542.51
## 69 69 1134.14 588.17 545.97 40996.54
## 70 70 1134.14 580.44 553.70 40442.84
## 71 71 1134.14 572.60 561.54 39881.30
## 72 72 1134.14 564.65 569.49 39311.81
## 73 73 1134.14 556.59 577.55 38734.26
## 74 74 1134.14 548.41 585.73 38148.53
## 75 75 1134.14 540.12 594.02 37554.51
## 76 76 1134.14 531.71 602.43 36952.08
## 77 77 1134.14 523.18 610.96 36341.12
## 78 78 1134.14 514.53 619.61 35721.51
## 79 79 1134.14 505.76 628.38 35093.13
## 80 80 1134.14 496.86 637.28 34455.85
## 81 81 1134.14 487.84 646.30 33809.55
## 82 82 1134.14 478.69 655.45 33154.10
## 83 83 1134.14 469.41 664.73 32489.37
## 84 84 1134.14 460.00 674.14 31815.23
## 85 85 1134.14 450.45 683.69 31131.54
## 86 86 1134.14 440.77 693.37 30438.17
## 87 87 1134.14 430.95 703.19 29734.98
## 88 88 1134.14 421.00 713.14 29021.84
## 89 89 1134.14 410.90 723.24 28298.60
## 90 90 1134.14 400.66 733.48 27565.12
## 91 91 1134.14 390.28 743.86 26821.26
## 92 92 1134.14 379.74 754.40 26066.86
## 93 93 1134.14 369.06 765.08 25301.78
## 94 94 1134.14 358.23 775.91 24525.87
## 95 95 1134.14 347.25 786.89 23738.98
## 96 96 1134.14 336.10 798.04 22940.94
## 97 97 1134.14 324.81 809.33 22131.61
## 98 98 1134.14 313.35 820.79 21310.82
## 99 99 1134.14 301.73 832.41 20478.41
## 100 100 1134.14 289.94 844.20 19634.21
## 101 101 1134.14 277.99 856.15 18778.06
## 102 102 1134.14 265.87 868.27 17909.79
## 103 103 1134.14 253.57 880.57 17029.22
## 104 104 1134.14 241.11 893.03 16136.19
## 105 105 1134.14 228.46 905.68 15230.51
## 106 106 1134.14 215.64 918.50 14312.01
## 107 107 1134.14 202.63 931.51 13380.50
## 108 108 1134.14 189.45 944.69 12435.81
## 109 109 1134.14 176.07 958.07 11477.74
## 110 110 1134.14 162.51 971.63 10506.11
## 111 111 1134.14 148.75 985.39 9520.72
## 112 112 1134.14 134.80 999.34 8521.38
## 113 113 1134.14 120.65 1013.49 7507.89
## 114 114 1134.14 106.30 1027.84 6480.05
## 115 115 1134.14 91.75 1042.39 5437.66
## 116 116 1134.14 76.99 1057.15 4380.51
## 117 117 1134.14 62.02 1072.12 3308.39
## 118 118 1134.14 46.84 1087.30 2221.09
## 119 119 1134.14 31.45 1102.69 1118.40
## 120 120 1134.14 15.83 1118.31 0.09
cat("\nTotal pagado:", round(sum(tabla$Cuota), 2), "\n")
##
## Total pagado: 136096.8
cat("Intereses totales:", round(sum(tabla$Interes), 2), "\n")
## Intereses totales: 70816.72
final_prices <- mb[T, ]
indice_max <- which.max(final_prices)
trayectoria_maxima <- mb[, indice_max]
indice_min <- which.min(final_prices)
trayectoria_minima <- mb[, indice_min]
trayectoria_media <- rowMeans(mb)
trayectoria_mediana <- apply(mb, 1, median)
df_trayectorias <- data.frame(
Tiempo = 1:T,
Maxima = trayectoria_maxima,
Media = trayectoria_media,
Mediana = trayectoria_mediana,
Minima = trayectoria_minima
)
# Mostrar información de las trayectorias extremas
cat("\n=== TRAYECTORIAS PRINCIPALES ===\n")
##
## === TRAYECTORIAS PRINCIPALES ===
cat("Trayectoria MÁXIMA (Simulación", indice_max, "):\n")
## Trayectoria MÁXIMA (Simulación 1662 ):
cat(" - Precio final:", round(trayectoria_maxima[T], 2), "\n")
## - Precio final: 3992.31
cat(" - Rendimiento total:", round((trayectoria_maxima[T]/s0 - 1)*100, 2), "%\n")
## - Rendimiento total: 2.2 %
cat("\nTrayectoria MÍNIMA (Simulación", indice_min, "):\n")
##
## Trayectoria MÍNIMA (Simulación 6163 ):
cat(" - Precio final:", round(trayectoria_minima[T], 2), "\n")
## - Precio final: 3822.06
cat(" - Rendimiento total:", round((trayectoria_minima[T]/s0 - 1)*100, 2), "%\n")
## - Rendimiento total: -2.16 %
cat("\nTrayectoria MEDIA:\n")
##
## Trayectoria MEDIA:
cat(" - Precio final:", round(trayectoria_media[T], 2), "\n")
## - Precio final: 3906.57
cat(" - Rendimiento total:", round((trayectoria_media[T]/s0 - 1)*100, 2), "%\n")
## - Rendimiento total: 0.01 %
write.csv(df_trayectorias, "trayectorias_principales.csv", row.names = FALSE)
cat("\nTrayectorias guardadas en: trayectorias_principales.csv\n")
##
## Trayectorias guardadas en: trayectorias_principales.csv
library(ggplot2)
library(tidyr)
## Warning: package 'tidyr' was built under R version 4.3.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.3
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
sample_paths <- 30
sample_indices <- sample(1:N, sample_paths)
df_sample <- data.frame(
Time = rep(1:T, sample_paths),
Price = as.vector(mb[, sample_indices]),
Path = rep(paste("Path", sample_indices), each = T),
Type = "Sample"
)
df_main <- data.frame(
Time = rep(1:T, 4),
Price = c(trayectoria_maxima, trayectoria_media, trayectoria_mediana, trayectoria_minima),
Path = rep(c("Máxima", "Media", "Mediana", "Mínima"), each = T),
Type = rep(c("Máxima", "Media", "Mediana", "Mínima"), each = T)
)
df_all <- rbind(df_sample, df_main)
# Gráfico 1: Todas las trayectorias con énfasis en las principales
p1 <- ggplot() +
geom_line(data = df_sample, aes(x = Time, y = Price, group = Path),
alpha = 0.2, color = "lightgray", size = 0.3) +
geom_line(data = subset(df_main, Path == "Máxima"),
aes(x = Time, y = Price), color = "green", size = 1.2) +
geom_line(data = subset(df_main, Path == "Media"),
aes(x = Time, y = Price), color = "blue", size = 1.2) +
geom_line(data = subset(df_main, Path == "Mediana"),
aes(x = Time, y = Price), color = "orange", size = 1.2) +
geom_line(data = subset(df_main, Path == "Mínima"),
aes(x = Time, y = Price), color = "red", size = 1.2) +
geom_hline(yintercept = s0, linetype = "dashed", color = "black", size = 0.8) +
labs(title = "Trayectorias de Simulación Monte Carlo",
subtitle = paste("Trayectorias principales de", N, "simulaciones -", T, "días"),
x = "Días",
y = "Precio") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 10),
legend.position = "bottom"
) +
annotate("text", x = T*0.7, y = max(df_main$Price)*0.9,
label = "Verde: Máxima\nAzul: Media\nNaranja: Mediana\nRojo: Mínima",
size = 3, hjust = 0)
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
df_main_wide <- df_trayectorias %>%
pivot_longer(cols = c(Maxima, Media, Mediana, Minima),
names_to = "Trayectoria", values_to = "Precio")
p2 <- ggplot(df_main_wide, aes(x = Tiempo, y = Precio, color = Trayectoria)) +
geom_line(size = 1.2, alpha = 0.8) +
scale_color_manual(values = c("Maxima" = "green", "Media" = "blue",
"Mediana" = "orange", "Minima" = "red")) +
geom_hline(yintercept = s0, linetype = "dashed", color = "black", alpha = 0.6) +
labs(title = "Trayectorias Principales - Simulación Monte Carlo",
subtitle = "Comparación de trayectorias extremas y central",
x = "Días",
y = "Precio",
color = "Tipo de\nTrayectoria") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 10),
legend.position = "right"
)
p3 <- ggplot(data.frame(Price = final_prices), aes(x = Price)) +
geom_histogram(bins = 50, fill = "lightblue", color = "darkblue", alpha = 0.7) +
geom_vline(xintercept = mean(final_prices), color = "blue", linetype = "dashed", size = 1) +
geom_vline(xintercept = s0, color = "black", linetype = "dashed", size = 1) +
geom_vline(xintercept = max(final_prices), color = "green", linetype = "dashed", size = 1) +
geom_vline(xintercept = min(final_prices), color = "red", linetype = "dashed", size = 1) +
labs(title = "Distribución de Precios Finales",
subtitle = paste("Después de", T, "días -", N, "simulaciones"),
x = "Precio Final",
y = "Frecuencia") +
theme_minimal() +
annotate("text", x = max(final_prices)*0.8, y = Inf, vjust = 2,
label = "Negro: Inicial\nAzul: Media\nVerde: Máximo\nRojo: Mínimo",
size = 3)
print(p1)
print(p2)
print(p3)
get_trayectorias <- function() {
list(
maxima = trayectoria_maxima,
minima = trayectoria_minima,
media = trayectoria_media,
mediana = trayectoria_mediana,
datos_completos = df_trayectorias
)
}
var_95 <- quantile(final_prices, 0.05)
cat("\nValue at Risk (5%):", round(var_95, 2), "\n")
##
## Value at Risk (5%): 3869.52
#Credito trayectoria max
trayectoria_maxima <- as.vector(trayectoria_maxima)
amortizacionCOP <- tabla
columnas_amortizacion <- c("Cuota", "Interes", "Amortizacion", "Saldo")
amortizacionCOP[ , columnas_amortizacion] <- tabla[ , columnas_amortizacion] * trayectoria_maxima
df_pago <- data.frame(Mes = 1:nrow(amortizacionCOP),Pago = amortizacionCOP[, "Cuota"])
ggplot(df_pago, aes(x = Mes, y = trayectoria_maxima)) +
geom_line(color = "#1f4e79", linewidth = 1.5, alpha = 0.8) +
geom_point(color = "#1f4e79", size = 1, alpha = 0.9) +
labs(title = "Comportamiento del Pago Mensual",
subtitle = "Evolución mensual de pagos en pesos colombianos",
x = "Mes",
y = "Pago (COP)",
caption = "Fuente: Datos internos") +
scale_y_continuous(
labels = scales::dollar_format(prefix = "$", suffix = " COP", big.mark = ".", decimal.mark = ",")
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(hjust = 0.5, size = 21, color = "#7f8c8d"),
axis.title = element_text(size = 21, face = "bold"),
axis.text = element_text(size = 10),
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = "#ecf0f1", size = 0.5),
plot.background = element_rect(fill = "#ffffff", color = NA),
panel.background = element_rect(fill = "#ffffff", color = NA)
)
## Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
#Credito trayectoria min
trayectoria_minima <- as.vector(trayectoria_minima)
amortizacionCOP <- tabla
columnas_amortizacion_min <- c("Cuota", "Interes", "Amortizacion", "Saldo")
amortizacionCOP[ , columnas_amortizacion_min] <- tabla[ , columnas_amortizacion_min] * trayectoria_minima
df_pago <- data.frame(Mes = 1:nrow(amortizacionCOP),Pago = amortizacionCOP[, "Cuota"])
ggplot(df_pago, aes(x = Mes, y = trayectoria_minima)) +
geom_line(color = "#1f4e79", linewidth = 1.5, alpha = 0.8) +
geom_point(color = "#1f4e79", size = 1, alpha = 0.9) +
labs(title = "Comportamiento del Pago Mensual",
subtitle = "Evolución mensual de pagos en pesos colombianos",
x = "Mes",
y = "Pago (COP)",
caption = "Fuente: Datos internos") +
scale_y_continuous(
labels = scales::dollar_format(prefix = "$", suffix = " COP", big.mark = ".", decimal.mark = ",")
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(hjust = 0.5, size = 21, color = "#7f8c8d"),
axis.title = element_text(size = 21, face = "bold"),
axis.text = element_text(size = 10),
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = "#ecf0f1", size = 0.5),
plot.background = element_rect(fill = "#ffffff", color = NA),
panel.background = element_rect(fill = "#ffffff", color = NA)
)
# Credito trayectoria media
trayectoria_media <- as.vector(trayectoria_media)
amortizacionCOP <- tabla
columnas_amortizacion_media <- c("Cuota", "Interes", "Amortizacion", "Saldo")
amortizacionCOP[ , columnas_amortizacion_media] <- tabla[ , columnas_amortizacion_media] * trayectoria_media
df_pago <- data.frame(Mes = 1:nrow(amortizacionCOP),Pago = amortizacionCOP[, "Cuota"])
ggplot(df_pago, aes(x = Mes, y = trayectoria_media)) +
geom_line(color = "#1f4e79", linewidth = 1.5, alpha = 0.8) +
geom_point(color = "#1f4e79", size = 1, alpha = 0.9) +
labs(title = "Comportamiento del Pago Mensual",
subtitle = "Evolución mensual de pagos en pesos colombianos",
x = "Mes",
y = "Pago (COP)",
caption = "Fuente: Datos internos") +
scale_y_continuous(
labels = scales::dollar_format(prefix = "$", suffix = " COP", big.mark = ".", decimal.mark = ",")
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(hjust = 0.5, size = 21, color = "#7f8c8d"),
axis.title = element_text(size = 21, face = "bold"),
axis.text = element_text(size = 10),
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = "#ecf0f1", size = 0.5),
plot.background = element_rect(fill = "#ffffff", color = NA),
panel.background = element_rect(fill = "#ffffff", color = NA)
)
El cálculo del precio teórico futuro, derivado de la relación entre tasas nacionales e internacionales, constituye la base metodológica para establecer los parámetros iniciales de la simulación.
Para el cálculo de este se utilizó para el caso de Colombia la tasa promedio ponderada de la superintendencia financiera de Colombia con corte al 12 de septiembre de 2025. Superintendencia Financiera de Colombia. (s.f.). En el caso de EEUU la tasa trabajada para la toma del crédito.
library(dplyr)
library(ggplot2)
library(readxl) AlumSpot <- read_excel(“D:/ESTOCASTICOS/TEMA 80%/AlumSpot.xlsx”)
C:/Users/jmora/OneDrive/Documentos/DERIVAD
“C:/Users/jmora/OneDrive/Documentos/DERIVADOS FROS/futuros.xlsx”
library(readxl)
## Warning: package 'readxl' was built under R version 4.3.3
futuros <- read_excel("C:/Users/jmora/OneDrive/Documentos/DERIVADOS FROS/futuros.xlsx")
# Parámetros
rn <- (1+0.198)^(1/21)-1 # Tasa nacional (19.8)
re <- i # Tasa extranjera semestral (4.13%)
# Precio inicial (último precio)
F0 <- as.numeric(tail(futuros[, "prom_precio_cierre"], 1)) # ✅ tail() en lugar de last()
# Precio teórico del futuro
FT <- F0 * ((1 + rn) / (1 + re))^(1/21)
cat("El precio teórico del futuro basado en la paridad de tasas es:", round(FT, 4), "\n")
## El precio teórico del futuro basado en la paridad de tasas es: 3949.103
# Calcular parámetros usando datos de futuros
retornos_trm <- diff(log(futuros$prom_precio_cierre))
r_trm <- exp(mean(retornos_trm)) - 1
sigma_trm <- sd(retornos_trm)
# Mensualizar los parámetros
r_trm <- r_trm*21
sigma_trm <- sqrt(21)*sigma_trm
#Simulacion TRM
T<-120
dt<-1/21
s0 <- FT
N<-1
set.seed(2032)
vec_trm=rep(s0,N)
mb_trm=matrix(ncol=N,nrow = T)
mb_trm[1,]=vec_trm
for (i in 1:N) {
for (t in 2:T) {
mb_trm[t,i]=mb_trm[(t-1),i]*exp((r_trm-(0.5*(sigma_trm^2)))*(dt) +
sigma_trm*sqrt(dt)*rnorm(1))
}
}
df_trm <- data.frame(Mes = 1:T, TRM = as.vector(mb_trm))
ggplot(df_trm, aes(x = Mes, y = TRM)) + geom_line(color = "blue", size = 1) +
labs(title = "Trayectoria simulada de TRM", x = "Mes", y = "TRM") +
theme_minimal()+theme(plot.title = element_text(hjust = 0.5))
## Cobertura con futuros
Aunque el ejercicio sugiere un nivel de apalancamiento del 75% mediante futuros, esta práctica busca determinar si un porcentaje inferior puede proporcionar una cobertura adecuada sin comprometer significativamente la liquidez corporativa. Para este propósito, se emplearán contratos TRX en lugar de TRM, considerando que estos últimos, con un tamaño contractual de 50,000 USD, impondrían un riesgo excesivo dada la magnitud de cada posición, mientras que los contratos TRX ofrecen mayor granularidad para calibrar la estrategia de cobertura de manera más precisa.
Se toma como valor nominal el valor de la TRM del 19 de septiembre, dato tomado de la BVC. El margen de mantenimiento será del 50% trabajandolo como un estándar dentro de los ejercicios de futuros y el margen incial será del 6,3% basado en la información de apalancamiento de futuros proporcionado por la BVC.
cobertura<-P*0.75
trx<-1000
numero_contratos<-round(cobertura/trx)
print(numero_contratos)
## [1] 49
# Asumiendo los datos de la BVC
nominal<-3891.19
# 1. Criterio de Exposición Total
exp_total<-numero_contratos*nominal
# 2. Criterio de Margen Inicial
margen_inicial<-0.063*exp_total
# 3. Criterio de Margen de Mantenimiento
margen_mantenimiento<-0.5*margen_inicial
print(paste("Exposición Total:", exp_total))
## [1] "Exposición Total: 190668.31"
print(paste("Margen Inicial:", margen_inicial))
## [1] "Margen Inicial: 12012.10353"
print(paste("Margen de Mantenimiento:", margen_mantenimiento))
## [1] "Margen de Mantenimiento: 6006.051765"
generar_tabla_futuros <- function(tiempo, precios_futuros, precio_futuro_inicial, valor_contrato, margen_inicial, margen_mantenimiento_porcentaje = 0.5, posicion = "larga") {
margen_mantenimiento <- margen_inicial * margen_mantenimiento_porcentaje
tabla_futuros <- data.frame(
T = tiempo,
Precio.Futuro = c(precio_futuro_inicial, precios_futuros),
Dif.PF = numeric(length(tiempo)),
Liquidacion = numeric(length(tiempo)),
Margen = numeric(length(tiempo)),
Margin.Call = character(length(tiempo))
)
tabla_futuros$Margen[1] <- margen_inicial
tabla_futuros$Dif.PF[1] <- 0
tabla_futuros$Liquidacion[1] <- 0
tabla_futuros$Margin.Call[1] <- 0
for (i in 2:nrow(tabla_futuros)) {
precio_hoy <- tabla_futuros$Precio.Futuro[i]
precio_ayer <- tabla_futuros$Precio.Futuro[i-1]
if (posicion == "larga") {
tabla_futuros$Dif.PF[i] <- precio_hoy - precio_ayer
} else if (posicion == "corta") {
tabla_futuros$Dif.PF[i] <- precio_ayer - precio_hoy
} else {
stop("La posición debe ser 'larga' o 'corta'.")
}
tabla_futuros$Liquidacion[i] <- tabla_futuros$Dif.PF[i] * valor_contrato
margen_previo <- tabla_futuros$Margen[i-1]
liquidacion_actual <- tabla_futuros$Liquidacion[i]
margin_call_previo <- ifelse(tabla_futuros$Margin.Call[i-1] != 0 & tabla_futuros$Margin.Call[i-1] != "-", as.numeric(tabla_futuros$Margin.Call[i-1]), 0)
margen_actual <- margen_previo + liquidacion_actual + margin_call_previo
tabla_futuros$Margin.Call[i] <- 0
if (margen_actual < margen_mantenimiento) {
monto_margin_call <- margen_inicial - margen_actual
tabla_futuros$Margin.Call[i] <- format(monto_margin_call, scientific = FALSE)
tabla_futuros$Margen[i] <- margen_actual # Guardar el margen ANTES del call
} else {
tabla_futuros$Margen[i] <- margen_actual
}
}
# Formatear la salida
tabla_futuros <- tabla_futuros %>%
mutate(
Dif.PF = ifelse(T == tiempo[1], 0, as.character(Dif.PF)),
Liquidacion = ifelse(T == tiempo[1], 0, as.character(format(Liquidacion, scientific = FALSE))),
Margen = format(Margen, scientific = FALSE),
Margin.Call = ifelse(Margin.Call != 0, Margin.Call, 0)
)
return(tabla_futuros)
}
nominal_contrato <- 1000
num_contratos <- 3
margen_inicial_total <- 0.063 * num_contratos * nominal_contrato
margen_mantenimiento_porcentaje <- 0.5
precio_referencia <- FT
#Simulación diaria del TRM y los Futuros
dias_totales <- 4 * 252
dt_diario <- 1/252
set.seed(2032)
mb_trm_diario <- rep(NA, dias_totales)
mb_trm_diario[1] <- F0
for (t in 2:dias_totales) {
mb_trm_diario[t] = mb_trm_diario[t-1] * exp((r_trm - (0.5 * (sigma_trm^2))) * dt_diario + sigma_trm * sqrt(dt_diario) * rnorm(1))
}
set.seed(2033)
mb_futures_diario <- rep(NA, dias_totales)
mb_futures_diario[1] <- FT
for (t in 2:dias_totales) {
mb_futures_diario[t] = mb_futures_diario[t-1] * exp((r_trm - (0.5 * (sigma_trm^2))) * dt_diario + sigma_trm * sqrt(dt_diario) * rnorm(1))
}
#Función para generar la tabla de futuros
generar_tabla_futuros <- function(tiempo, precios_futuros, precio_futuro_inicial, valor_contrato, margen_inicial, margen_mantenimiento_porcentaje = 0.5, posicion = "larga") {
margen_mantenimiento <- margen_inicial * margen_mantenimiento_porcentaje
tabla_futuros <- data.frame(
T = tiempo,
Precio.Futuro = precios_futuros,
Dif.PF = numeric(length(tiempo)),
Liquidacion = numeric(length(tiempo)),
Margen = numeric(length(tiempo)),
Margin.Call = character(length(tiempo))
)
tabla_futuros$Margen[1] <- margen_inicial
tabla_futuros$Dif.PF[1] <- 0
tabla_futuros$Liquidacion[1] <- 0
tabla_futuros$Margin.Call[1] <- 0
for (i in 2:nrow(tabla_futuros)) {
precio_hoy <- tabla_futuros$Precio.Futuro[i]
precio_ayer <- tabla_futuros$Precio.Futuro[i-1]
if (posicion == "larga") {
tabla_futuros$Dif.PF[i] <- precio_hoy - precio_ayer
} else if (posicion == "corta") {
tabla_futuros$Dif.PF[i] <- precio_ayer - precio_hoy
} else {
stop("La posición debe ser 'larga' o 'corta'.")
}
tabla_futuros$Liquidacion[i] <- tabla_futuros$Dif.PF[i] * valor_contrato
margen_previo <- tabla_futuros$Margen[i-1]
liquidacion_actual <- tabla_futuros$Liquidacion[i]
margin_call_previo <- ifelse(tabla_futuros$Margin.Call[i-1] != 0 & tabla_futuros$Margin.Call[i-1] != "-", as.numeric(tabla_futuros$Margin.Call[i-1]), 0)
margen_actual <- margen_previo + liquidacion_actual + margin_call_previo
tabla_futuros$Margin.Call[i] <- 0
if (margen_actual < margen_mantenimiento) {
monto_margin_call <- margen_inicial - margen_actual
tabla_futuros$Margin.Call[i] <- format(monto_margin_call, scientific = FALSE)
tabla_futuros$Margen[i] <- margen_actual # Guardar el margen ANTES del call
} else {
tabla_futuros$Margen[i] <- margen_actual
}
}
return(tabla_futuros)
}
#Bucle de Rollover y Llamada a la Función
dias_por_periodo <- 6 * 21
resultados_por_periodo <- list()
for (i in 1:8) {
inicio <- (i - 1) * dias_por_periodo + 1
fin <- i * dias_por_periodo
precios_periodo <- mb_futures_diario[inicio:fin]
# Decisión de la posición
if (precios_periodo[1] < precio_referencia) {
posicion_actual <- "larga"
} else {
posicion_actual <- "corta"
}
tabla_periodo <- generar_tabla_futuros(
tiempo = 1:dias_por_periodo,
precios_futuros = precios_periodo,
precio_futuro_inicial = precios_periodo[1],
valor_contrato = nominal_contrato * num_contratos, # Valor total de la posición
margen_inicial = margen_inicial_total,
margen_mantenimiento_porcentaje = margen_mantenimiento_porcentaje,
posicion = posicion_actual
)
resultados_por_periodo[[i]] <- tabla_periodo
}
calcular_flujo_caja_futuros <- function(tabla_futuros, margen_inicial_bloque, es_primera_tabla_serie = FALSE) {
margin_call_numeric <- ifelse(tabla_futuros$Margin.Call == "0" | tabla_futuros$Margin.Call == "-" | is.na(tabla_futuros$Margin.Call),
0,
as.numeric(gsub(",", "", tabla_futuros$Margin.Call)))
liquidacion_numeric <- as.numeric(gsub(",", "", tabla_futuros$Liquidacion))
flujo_caja_por_periodo <- numeric(nrow(tabla_futuros))
if (es_primera_tabla_serie) {
flujo_caja_por_periodo[1] <- -margen_inicial_bloque
} else {
flujo_caja_por_periodo[1] <- 0
}
for (k in 2:(nrow(tabla_futuros) - 1)) {
flujo_caja_por_periodo[k] <- liquidacion_numeric[k] - margin_call_numeric[k]
}
ultimo_periodo_idx <- nrow(tabla_futuros)
flujo_caja_por_periodo[ultimo_periodo_idx] <-
liquidacion_numeric[ultimo_periodo_idx] - margin_call_numeric[ultimo_periodo_idx]
return(flujo_caja_por_periodo)
}
#Inicialización de vectores para acumular datos
flujos_cubiertos <- c()
periodos_cubiertos <- c()
#Bucle de Rollover y Acumulación de Datos
dias_por_periodo <- 6 * 21
num_periodos <- 8
for (i in 1:num_periodos) {
inicio_dias <- (i - 1) * dias_por_periodo + 1
fin_dias <- i * dias_por_periodo
precios_periodo_diario <- mb_futures_diario[inicio_dias:fin_dias]
# Decisión de la posición
if (precios_periodo_diario[1] < precio_referencia) {
posicion_actual <- "larga"
} else {
posicion_actual <- "corta"
}
# Generar la tabla de futuros
tabla_margen <- generar_tabla_futuros(
tiempo = 1:dias_por_periodo,
precios_futuros = precios_periodo_diario,
precio_futuro_inicial = precios_periodo_diario[1],
valor_contrato = nominal_contrato * num_contratos,
margen_inicial = margen_inicial_total,
margen_mantenimiento_porcentaje = margen_mantenimiento_porcentaje,
posicion = posicion_actual
)
# Calcular el flujo de caja del margen usando tu función
es_primera <- (i == 1)
flujo_caja_diario <- calcular_flujo_caja_futuros(
tabla_futuros = tabla_margen,
margen_inicial_bloque = margen_inicial_total,
es_primera_tabla_serie = es_primera
)
# Obtener los períodos (meses del 73 al 120) para el flujo acumulado
meses_del_periodo <- seq(from = 72 + (i-1)*6, to = 72 + i*6, by=1)
periodos_diarios_acumulados <- rep(meses_del_periodo, each = 21, length.out = dias_por_periodo)
# Acumular los datos en los vectores temporales
flujos_cubiertos <- c(flujos_cubiertos, flujo_caja_diario)
periodos_cubiertos <- c(periodos_cubiertos, periodos_diarios_acumulados)
}
#Consolidación y ordenamiento final
flujo_caja_cobertura_con_nombres <- tapply(flujos_cubiertos,
INDEX = periodos_cubiertos,
FUN = sum)
flujo_caja_cobertura_ordenado <- flujo_caja_cobertura_con_nombres[order(as.numeric(names(flujo_caja_cobertura_con_nombres)))]
print(flujo_caja_cobertura_ordenado)
## 72 73 74 75 76 77 78
## 648606.70 539391.68 383569.03 394989.33 562882.70 434027.04 -511795.84
## 79 80 81 82 83 84 85
## -813968.09 -369354.09 -986051.65 -677853.92 -767308.37 -758222.73 -167055.65
## 86 87 88 89 90 91 92
## -500668.46 -591789.50 -673262.44 -690365.10 -627135.07 -523472.73 -234743.15
## 93 94 95 96 97 98 99
## -165190.43 -400876.98 -544746.95 -148881.23 -196720.14 -306053.73 -348255.28
## 100 101 102 103 104 105 106
## -251019.90 -168533.03 -271563.69 -14168.20 -205181.30 -217313.19 -339650.38
## 107 108 109 110 111 112 113
## -249545.18 -232931.51 -252271.30 -191418.38 -199792.92 -257837.54 -52551.75
## 114 115 116 117 118 119
## -172568.87 -215574.59 -169601.61 -77737.05 -156666.14 -207283.35
cuota_usd <- 1134.14
#Bucle principal para el análisis comparativo
dias_por_periodo <- 6 * 21
df_flujo_caja <- data.frame(
Periodo_Cobertura = 1:8,
Posicion = NA,
Costo_Prestamo_Total = NA,
Flujo_Caja_Margen = NA,
Flujo_Caja_Neto_Total = NA
)
for (i in 1:8) {
inicio_dias <- (i - 1) * dias_por_periodo + 1
fin_dias <- i * dias_por_periodo
precios_periodo_diario <- mb_futures_diario[inicio_dias:fin_dias]
if (precios_periodo_diario[1] < precio_referencia) {
posicion_actual <- "larga"
} else {
posicion_actual <- "corta"
}
tabla_margen <- generar_tabla_futuros(
tiempo = 1:dias_por_periodo,
precios_futuros = precios_periodo_diario,
precio_futuro_inicial = precios_periodo_diario[1],
valor_contrato = nominal_contrato * num_contratos,
margen_inicial = margen_inicial_total,
margen_mantenimiento_porcentaje = margen_mantenimiento_porcentaje,
posicion = posicion_actual
)
trm_promedio_mensual <- mb_trm_diario[seq(inicio_dias, fin_dias, by = 21)]
costo_prestamo_total <- sum(cuota_usd * trm_promedio_mensual)
es_primera <- (i == 1)
flujo_caja_futuros_diario <- calcular_flujo_caja_futuros(
tabla_futuros = tabla_margen,
margen_inicial_bloque = margen_inicial_total,
es_primera_tabla_serie = es_primera
)
flujo_caja_margen <- sum(flujo_caja_futuros_diario)
flujo_caja_neto_total <- flujo_caja_margen - costo_prestamo_total
df_flujo_caja[i, "Posicion"] <- posicion_actual
df_flujo_caja[i, "Costo_Prestamo_Total"] <- costo_prestamo_total
df_flujo_caja[i, "Flujo_Caja_Margen"] <- flujo_caja_margen
df_flujo_caja[i, "Flujo_Caja_Neto_Total"] <- flujo_caja_neto_total
}
print(df_flujo_caja)
## Periodo_Cobertura Posicion Costo_Prestamo_Total Flujo_Caja_Margen
## 1 1 corta 24933236 2963466.5
## 2 2 larga 19831044 -4126332.0
## 3 3 larga 15975657 -3381363.9
## 4 4 larga 12537155 -2496165.3
## 5 5 larga 9110904 -1419463.3
## 6 6 larga 7161290 -1297421.9
## 7 7 larga 5496779 -1186803.4
## 8 8 larga 4487724 -999431.6
## Flujo_Caja_Neto_Total
## 1 -21969770
## 2 -23957376
## 3 -19357021
## 4 -15033320
## 5 -10530367
## 6 -8458712
## 7 -6683583
## 8 -5487156
for (i in 1:8) {
inicio_dias <- (i - 1) * dias_por_periodo + 1
fin_dias <- i * dias_por_periodo
precios_periodo_diario <- mb_futures_diario[inicio_dias:fin_dias]
# Código para definir la posición
if (precios_periodo_diario[1] < precio_referencia) {
posicion_actual <- "larga"
} else {
posicion_actual <- "corta"
}
df_flujo_caja[i, "Posicion"] <- posicion_actual
tabla_margen <- generar_tabla_futuros(
tiempo = 1:dias_por_periodo,
precios_futuros = precios_periodo_diario,
precio_futuro_inicial = precios_periodo_diario[1],
valor_contrato = nominal_contrato * num_contratos,
margen_inicial = margen_inicial_total,
margen_mantenimiento_porcentaje = margen_mantenimiento_porcentaje,
posicion = posicion_actual
)
ganancia_futuros_total <- sum(tabla_margen$Liquidacion)
margin_calls_total <- sum(as.numeric(tabla_margen$Margin.Call[tabla_margen$Margin.Call != "0"]))
df_flujo_caja[i, "Ganancia_Futuros_Total"] <- ganancia_futuros_total
df_flujo_caja[i, "Margin_Calls_Total"] <- margin_calls_total
}
print(df_flujo_caja)
## Periodo_Cobertura Posicion Costo_Prestamo_Total Flujo_Caja_Margen
## 1 1 corta 24933236 2963466.5
## 2 2 larga 19831044 -4126332.0
## 3 3 larga 15975657 -3381363.9
## 4 4 larga 12537155 -2496165.3
## 5 5 larga 9110904 -1419463.3
## 6 6 larga 7161290 -1297421.9
## 7 7 larga 5496779 -1186803.4
## 8 8 larga 4487724 -999431.6
## Flujo_Caja_Neto_Total Ganancia_Futuros_Total Margin_Calls_Total
## 1 -21969770 2963655.5 0.0
## 2 -23957376 -2063166.0 2063166.0
## 3 -19357021 -1682550.6 1698813.3
## 4 -15033320 -1248082.7 1248082.7
## 5 -10530367 -708554.8 710908.5
## 6 -8458712 -648711.0 648711.0
## 7 -6683583 -593401.7 593401.7
## 8 -5487156 -499715.8 499715.8
library(ggplot2)
library(tidyr)
library(scales)
df_long <- pivot_longer(
df_flujo_caja,
cols = c(Costo_Prestamo_Total, Flujo_Caja_Margen),
names_to = "Tipo_Flujo",
values_to = "Monto"
)
grafico_comparativo <- ggplot(df_long, aes(x = as.factor(Periodo_Cobertura), y = Monto, fill = Tipo_Flujo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(
title = "Comparación: Costo del Préstamo vs. Flujo de Caja de Futuros",
subtitle = "Análisis de la efectividad de la cobertura por período",
x = "Período de Cobertura (semestral)",
y = "Monto (COP)",
fill = "Tipo de Flujo"
) +
scale_y_continuous(labels = dollar_format(prefix = "$", big.mark = ",", decimal.mark = ".")) +
scale_fill_manual(
values = c("Costo_Prestamo_Total" = "#E5635F", "Flujo_Caja_Margen" = "#3B7C57"),
labels = c("Costo del Préstamo", "Flujo de Caja del Margen")
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, face = "bold"),
plot.subtitle = element_text(hjust = 0.5),
legend.position = "bottom"
)
print(grafico_comparativo)
En conclusión, la expectativa de precios de la TRM para el próximo año se basa en un análisis de equilibrio de fuerzas. La política monetaria prudente del Banco de la República, sumada a las dinámicas globales favorables, apunta a una estabilización de la TRM. Sin embargo, los modelos de riesgo nos recuerdan que cualquier cambio significativo en las variables analizadas podría alterar esta trayectoria, haciendo que el monitoreo continuo sea crucial.
Para el contexto del taller, esta proyección sugiere que la estrategia de cobertura con futuros TRX no tiene una variación significativa, ya que la tendencia esperada del dólar a la baja comparada con la tendencia de la TRX es muy similar, por ende, se podría asumir que la cobertura que se genera por parte del futuro es baja.
La estrategia de cobertura conservadora con 3 contratos de futuros TRM representa un enfoque prudente que balancea la protección del riesgo cambiario del préstamo internacional con la eficiencia en el uso de recursos financieros, considerando las limitaciones identificadas en la efectividad de la cobertura bajo las condiciones proyectadas.
Banco de la República de Colombia. (2025, julio). Informe de política monetaria. https://www.banrep.gov.co/es/publicaciones-investigaciones/informe-politica-monetaria/julio-2025
Banco de la República de Colombia. (2025, agosto). Resultado de la Encuesta Mensual de Expectativas de Analistas Económicos (EME) - agosto 2025. https://www.banrep.gov.co/es/resultado-encuesta-mensual-expectativas-analistas-economicos-eme-agosto-2025
Banco de la República de Colombia. (s.f.). Tasa de cambio – TRM. Recuperado de https://www.banrep.gov.co/es/glosario/tasa-cambio-trm
Superintendencia Financiera de Colombia. (s.f.). Reportes PowerBI. https://www.superfinanciera.gov.co/powerbi/reportes/536/