# Paquetes
library(readxl)
## Warning: package 'readxl' 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
library(ggplot2)
library(knitr)
library(scales)
options(scipen = 999) # evitar notacion cientifica en tablas/graficos
# 0. PARÁMETROS GLOBALES
set.seed(123) # reproducibilidad
# Parámetros del crédito en USD (AJUSTAR tasa con banco real)
tasa_ea_usd <- 0.065 # Tasa EA del crédito en dólares
# Tasas para forwards (AJUSTAR con tasas de referencia reales)
i_usa <- 0.05 # EA USA
i_col <- 0.12 # EA Colombia
# Parámetros de simulación
n_sim <- 1000 # nº simulaciones
df_t <- 3 # grados de libertad t-Student (colas pesadas)
# Datos de la inversión
monto_cop <- 350000000 # 350 millones COP
plazo_anos <- 10
n_trimestres <- plazo_anos * 4
########################################
# 1. TRM HISTÓRICA, RETORNOS Y ANÁLISIS BÁSICO
########################################
# Cargar TRM histórica (AJUSTAR RUTA)
trm_raw <- read_excel("C:/Analisis/trm.xlsx.xlsx")
trm <- trm_raw %>%
mutate(
Fecha = as.Date(Fecha),
TRM = as.numeric(TRM)
) %>%
arrange(Fecha)
# Chequeo básico de la TRM
summary(trm$TRM)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1748 2361 3151 3137 3888 5061 3
# Gráfico de TRM histórica
ggplot(trm, aes(x = Fecha, y = TRM)) +
geom_line(color = "steelblue") +
theme_minimal() +
labs(title = "TRM historica",
x = "Fecha",
y = "COP/USD")
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_line()`).

# Cálculo de retornos diarios logarítmicos
trm <- trm %>%
mutate(Retorno_d = log(TRM / lag(TRM))) %>%
filter(!is.na(Retorno_d))
mu_d <- mean(trm$Retorno_d)
sd_d <- sd(trm$Retorno_d)
vol_anual <- sd_d * sqrt(252)
kable(data.frame(
Metrica = c("Retorno diario medio", "Volatilidad diaria", "Volatilidad anual"),
Valor = c(mu_d, sd_d, vol_anual)
), digits = 6, caption = "Estadísticas básicas de la TRM (diarias)")
Estadísticas básicas de la TRM (diarias)
| Retorno diario medio |
0.000123 |
| Volatilidad diaria |
0.006220 |
| Volatilidad anual |
0.098739 |
# Histograma de retornos diarios
ggplot(trm, aes(x = Retorno_d)) +
geom_histogram(bins = 50, color = "white", fill = "steelblue") +
theme_minimal() +
labs(title = "Distribucion de retornos diarios de la TRM",
x = "Retorno diario logaritmico",
y = "Frecuencia")

########################################
# 2. RETORNOS MENSUALES Y SIMULACIONES BMG
########################################
# Serie mensual: última TRM de cada mes
trm_mensual <- trm %>%
mutate(Mes = format(Fecha, "%Y-%m")) %>%
group_by(Mes) %>%
summarise(TRM = last(TRM), .groups = "drop") %>%
arrange(Mes) %>%
mutate(Retorno_m = log(TRM / lag(TRM))) %>%
filter(!is.na(Retorno_m))
mu_m <- mean(trm_mensual$Retorno_m)
sd_m <- sd(trm_mensual$Retorno_m)
kable(data.frame(
Metrica = c("Retorno mensual medio", "Desviacion estandar mensual"),
Valor = c(mu_m, sd_m)
), digits = 6, caption = "Estadisticas de la TRM (mensuales)")
Estadisticas de la TRM (mensuales)
| Retorno mensual medio |
0.003716 |
| Desviacion estandar mensual |
0.037340 |
# Histograma de retornos mensuales
ggplot(trm_mensual, aes(x = Retorno_m)) +
geom_histogram(bins = 30, color = "white", fill = "darkgreen") +
theme_minimal() +
labs(title = "Distribucion de retornos mensuales de la TRM",
x = "Retorno mensual logaritmico",
y = "Frecuencia")

# Parámetros simulación mensual
trm_hoy <- tail(trm$TRM, 1)
n_meses <- 12
# Simulación BMG con Normal
sim_normal <- matrix(NA, nrow = n_meses, ncol = n_sim)
for (j in 1:n_sim) {
Z <- rnorm(n_meses)
sim_normal[, j] <- trm_hoy * exp(cumsum((mu_m - 0.5 * sd_m^2) + sd_m * Z))
}
# Simulación BMG con t-Student (ajustada a varianza 1)
sim_t <- matrix(NA, nrow = n_meses, ncol = n_sim)
for (j in 1:n_sim) {
Z_raw <- rt(n_meses, df = df_t)
Z <- Z_raw / sqrt(df_t / (df_t - 2)) # ajuste de escala
sim_t[, j] <- trm_hoy * exp(cumsum((mu_m - 0.5 * sd_m^2) + sd_m * Z))
}
# Gráfico de algunas trayectorias (Normal)
matplot(sim_normal[, 1:20], type = "l", lty = 1,
col = alpha("blue", 0.4),
main = "Simulacion TRM - BMG Normal (12 meses)",
xlab = "Mes", ylab = "TRM (COP/USD)")

# Gráfico de algunas trayectorias (t-Student)
matplot(sim_t[, 1:20], type = "l", lty = 1,
col = alpha("red", 0.4),
main = "Simulacion TRM - BMG t-Student (12 meses)",
xlab = "Mes", ylab = "TRM (COP/USD)")

# Percentiles (VaR / escenario) de TRM a 12 meses
trm_12m_normal <- sim_normal[n_meses, ]
trm_12m_t <- sim_t[n_meses, ]
resumen_trm_12m <- data.frame(
Modelo = c("Normal", "t-Student"),
P5 = c(quantile(trm_12m_normal, 0.05),
quantile(trm_12m_t, 0.05)),
P50 = c(median(trm_12m_normal),
median(trm_12m_t)),
P95 = c(quantile(trm_12m_normal, 0.95),
quantile(trm_12m_t, 0.95))
)
kable(resumen_trm_12m, digits = 2,
caption = "TRM proyectada a 12 meses: percentiles 5%, 50% y 95%")
TRM proyectada a 12 meses: percentiles 5%, 50% y 95%
| Normal |
3066.07 |
3811.95 |
4668.40 |
| t-Student |
3100.89 |
3794.59 |
4663.29 |
########################################
# 3. CRÉDITO EN USD (SISTEMA FRANCÉS, TRIMESTRAL, 10 AÑOS)
########################################
# Valor maquinaria en USD
monto_usd <- monto_cop / trm_hoy
# 10% de pago inicial
pago_inicial_usd <- 0.10 * monto_usd
# 90% financiado
credito_usd <- 0.90 * monto_usd
# Tasa trimestral equivalente
i_trimestral_usd <- (1 + tasa_ea_usd)^(1/4) - 1
# Cuota trimestral (sistema francés)
cuota_usd <- credito_usd * (i_trimestral_usd / (1 - (1 + i_trimestral_usd)^(-n_trimestres)))
resumen_credito <- data.frame(
Concepto = c("Monto equivalente en USD (350M COP)",
"Pago inicial 10% (USD)",
"Monto financiado 90% (USD)",
"Cuota trimestral (USD)",
"Numero de cuotas (trimestres)",
"Tasa EA USD",
"Tasa trimestral USD"),
Valor = c(monto_usd,
pago_inicial_usd,
credito_usd,
cuota_usd,
n_trimestres,
tasa_ea_usd,
i_trimestral_usd)
)
kable(resumen_credito, digits = 4, caption = "Resumen del credito en USD")
Resumen del credito en USD
| Monto equivalente en USD (350M COP) |
95396.7004 |
| Pago inicial 10% (USD) |
9539.6700 |
| Monto financiado 90% (USD) |
85857.0303 |
| Cuota trimestral (USD) |
2915.6425 |
| Numero de cuotas (trimestres) |
40.0000 |
| Tasa EA USD |
0.0650 |
| Tasa trimestral USD |
0.0159 |
# Tabla de amortización en USD
periodo <- 1:n_trimestres
saldo_ini <- numeric(n_trimestres)
interes <- numeric(n_trimestres)
abono_capital <- numeric(n_trimestres)
saldo_fin <- numeric(n_trimestres)
for (t in 1:n_trimestres) {
if (t == 1) {
saldo_ini[t] <- credito_usd
} else {
saldo_ini[t] <- saldo_fin[t - 1]
}
interes[t] <- saldo_ini[t] * i_trimestral_usd
abono_capital[t] <- cuota_usd - interes[t]
saldo_fin[t] <- saldo_ini[t] - abono_capital[t]
}
tabla_usd <- data.frame(
Periodo = periodo,
Saldo_Inicio = saldo_ini,
Interes = interes,
Abono = abono_capital,
Cuota = rep(cuota_usd, n_trimestres),
Saldo_Final = saldo_fin
)
kable(rbind(head(tabla_usd, 5), tail(tabla_usd, 5)),
digits = 2,
caption = "Tabla de amortización del crédito en USD (primeros y últimos periodos)")
Tabla de amortización del crédito en USD (primeros y últimos
periodos)
| 1 |
1 |
85857.03 |
1362.40 |
1553.24 |
2915.64 |
84303.79 |
| 2 |
2 |
84303.79 |
1337.76 |
1577.89 |
2915.64 |
82725.91 |
| 3 |
3 |
82725.91 |
1312.72 |
1602.92 |
2915.64 |
81122.98 |
| 4 |
4 |
81122.98 |
1287.28 |
1628.36 |
2915.64 |
79494.62 |
| 5 |
5 |
79494.62 |
1261.44 |
1654.20 |
2915.64 |
77840.42 |
| 36 |
36 |
13909.12 |
220.71 |
2694.93 |
2915.64 |
11214.19 |
| 37 |
37 |
11214.19 |
177.95 |
2737.69 |
2915.64 |
8476.50 |
| 38 |
38 |
8476.50 |
134.51 |
2781.13 |
2915.64 |
5695.37 |
| 39 |
39 |
5695.37 |
90.38 |
2825.27 |
2915.64 |
2870.10 |
| 40 |
40 |
2870.10 |
45.54 |
2870.10 |
2915.64 |
0.00 |
########################################
# 4. CRÉDITO RECREADO EN COP (SIN COBERTURA)
########################################
# A partir de retornos mensuales, pasamos a trimestrales
mu_t <- 3 * mu_m # retorno esperado trimestral
sd_t <- sd_m * sqrt(3) # desviación estándar trimestral
n_sim_tri <- n_sim
sim_trm_tri <- matrix(NA, nrow = n_trimestres, ncol = n_sim_tri)
for (j in 1:n_sim_tri) {
Z <- rnorm(n_trimestres)
sim_trm_tri[, j] <- trm_hoy * exp(cumsum((mu_t - 0.5 * sd_t^2) + sd_t * Z))
}
# TRM esperada por trimestre (promedio de las simulaciones)
trm_proj_mean <- rowMeans(sim_trm_tri)
# Flujo en COP sin cobertura (cuota USD * TRM esperada)
flujo_cop_sin <- cuota_usd * trm_proj_mean
tabla_cop <- data.frame(
Periodo = 1:n_trimestres,
TRM_Esperada = trm_proj_mean,
Cuota_USD = cuota_usd,
Cuota_COP_sin_cob = flujo_cop_sin
)
kable(rbind(head(tabla_cop, 5), tail(tabla_cop, 5)),
digits = 2,
caption = "Cuotas del credito en COP sin cobertura (primeros y ultimos periodos)")
Cuotas del credito en COP sin cobertura (primeros y ultimos
periodos)
| 1 |
1 |
3718.32 |
2915.64 |
10841279 |
| 2 |
2 |
3754.51 |
2915.64 |
10946810 |
| 3 |
3 |
3790.93 |
2915.64 |
11052987 |
| 4 |
4 |
3836.65 |
2915.64 |
11186289 |
| 5 |
5 |
3882.72 |
2915.64 |
11320636 |
| 36 |
36 |
5573.17 |
2915.64 |
16249358 |
| 37 |
37 |
5647.22 |
2915.64 |
16465275 |
| 38 |
38 |
5712.11 |
2915.64 |
16654467 |
| 39 |
39 |
5793.87 |
2915.64 |
16892852 |
| 40 |
40 |
5857.24 |
2915.64 |
17077623 |
########################################
# 5. FORWARD DE DIVISAS (75% DESDE AÑO 6, 4 FORWARDS DE 1 AÑO)
########################################
# Forwards de 1 año para años 6, 7, 8 y 9
anos_fwd <- 6:9
S0 <- trm_hoy
F_anos <- S0 * ((1 + i_col) / (1 + i_usa))^anos_fwd
tabla_forward <- data.frame(
Anio = anos_fwd,
Forward = F_anos
)
kable(tabla_forward, digits = 2,
caption = "Forwards anuales implicitos (a partir de hoy)")
Forwards anuales implicitos (a partir de hoy)
| 6 |
5403.90 |
| 7 |
5764.16 |
| 8 |
6148.43 |
| 9 |
6558.33 |
# Función: trimestre -> año
anio_desde_trimestre <- function(t) {
ceiling(t / 4) # cada 4 trimestres = 1 año
}
# Cobertura 75% de la cuota desde año 6 a 9
pct_cobertura <- 0.75
cuota_cubierta_usd <- pct_cobertura * cuota_usd
cuota_descubierta_usd <- (1 - pct_cobertura) * cuota_usd
flujo_cop_con <- numeric(n_trimestres)
for (t in 1:n_trimestres) {
anio_t <- anio_desde_trimestre(t)
if (anio_t < 6 || anio_t > 9) {
# Sin cobertura
flujo_cop_con[t] <- cuota_usd * trm_proj_mean[t]
} else {
# Cobertura 75% con forward
F_t <- F_anos[which(anos_fwd == anio_t)]
flujo_cop_con[t] <-
cuota_cubierta_usd * F_t +
cuota_descubierta_usd * trm_proj_mean[t]
}
}
tabla_cop$Cuota_COP_con_cob <- flujo_cop_con
tabla_cop$Impacto_cobertura <- tabla_cop$Cuota_COP_sin_cob - tabla_cop$Cuota_COP_con_cob
kable(rbind(head(tabla_cop, 5), tail(tabla_cop, 5)),
digits = 2,
caption = "Flujos en COP con y sin cobertura (primeros y ultimos periodos)")
Flujos en COP con y sin cobertura (primeros y ultimos
periodos)
| 1 |
1 |
3718.32 |
2915.64 |
10841279 |
10841279 |
0 |
| 2 |
2 |
3754.51 |
2915.64 |
10946810 |
10946810 |
0 |
| 3 |
3 |
3790.93 |
2915.64 |
11052987 |
11052987 |
0 |
| 4 |
4 |
3836.65 |
2915.64 |
11186289 |
11186289 |
0 |
| 5 |
5 |
3882.72 |
2915.64 |
11320636 |
11320636 |
0 |
| 36 |
36 |
5573.17 |
2915.64 |
16249358 |
18403646 |
-2154288 |
| 37 |
37 |
5647.22 |
2915.64 |
16465275 |
16465275 |
0 |
| 38 |
38 |
5712.11 |
2915.64 |
16654467 |
16654467 |
0 |
| 39 |
39 |
5793.87 |
2915.64 |
16892852 |
16892852 |
0 |
| 40 |
40 |
5857.24 |
2915.64 |
17077623 |
17077623 |
0 |
########################################
# 6. COMPARACIÓN, RIESGO Y MÉTRICAS ADICIONALES
########################################
# Comparación gráfica
plot(tabla_cop$Periodo, tabla_cop$Cuota_COP_sin_cob, type = "l", lwd = 2,
col = "blue", xlab = "Periodo (trimestre)", ylab = "Cuota en COP",
main = "Credito en COP: con y sin cobertura cambiaria")
lines(tabla_cop$Periodo, tabla_cop$Cuota_COP_con_cob,
lwd = 2, col = "red", lty = 2)
abline(v = 5*4 + 0.5, lty = 3, col = "darkgray") # inicio aprox. año 6
legend("topright",
legend = c("Sin cobertura", "Con cobertura (75% desde ano 6)"),
col = c("blue", "red"),
lty = c(1, 2), lwd = 2, bty = "n")

# Volatilidad de las cuotas en COP
sd_sin <- sd(tabla_cop$Cuota_COP_sin_cob)
sd_con <- sd(tabla_cop$Cuota_COP_con_cob)
sd_sin_rel <- sd_sin / mean(tabla_cop$Cuota_COP_sin_cob)
sd_con_rel <- sd_con / mean(tabla_cop$Cuota_COP_con_cob)
kable(data.frame(
Escenario = c("Sin cobertura", "Con cobertura"),
Vol_abs = c(sd_sin, sd_con),
Vol_rel_porcent = c(sd_sin_rel, sd_con_rel) * 100
), digits = 2,
caption = "Volatilidad absoluta y relativa de las cuotas en COP")
Volatilidad absoluta y relativa de las cuotas en COP
| Sin cobertura |
1882199 |
13.64 |
| Con cobertura |
2530855 |
17.46 |
# Costo total nominal y VPN en COP
total_sin <- sum(tabla_cop$Cuota_COP_sin_cob)
total_con <- sum(tabla_cop$Cuota_COP_con_cob)
i_tri_col <- (1 + i_col)^(1/4) - 1 # tasa trimestral en COP para descuento
vpn_sin <- sum(tabla_cop$Cuota_COP_sin_cob / (1 + i_tri_col)^(tabla_cop$Periodo))
vpn_con <- sum(tabla_cop$Cuota_COP_con_cob / (1 + i_tri_col)^(tabla_cop$Periodo))
kable(data.frame(
Escenario = c("Sin cobertura", "Con cobertura"),
Total_COP = c(total_sin, total_con),
VPN_COP = c(vpn_sin, vpn_con)
), digits = 2,
caption = "Costo total y VPN del credito en COP (con y sin cobertura)")
Costo total y VPN del credito en COP (con y sin
cobertura)
| Sin cobertura |
552042539 |
311635936 |
| Con cobertura |
579928564 |
323851278 |
# (OPCIONAL) Simulación completa de ahorro por cobertura
total_sin_sim <- numeric(n_sim_tri)
total_con_sim <- numeric(n_sim_tri)
for (j in 1:n_sim_tri) {
trm_path <- sim_trm_tri[, j]
# Sin cobertura
sin_j <- cuota_usd * trm_path
# Con cobertura
con_j <- numeric(n_trimestres)
for (t in 1:n_trimestres) {
anio_t <- anio_desde_trimestre(t)
if (anio_t < 6 || anio_t > 9) {
con_j[t] <- cuota_usd * trm_path[t]
} else {
F_t <- F_anos[which(anos_fwd == anio_t)]
con_j[t] <-
cuota_cubierta_usd * F_t +
cuota_descubierta_usd * trm_path[t]
}
}
total_sin_sim[j] <- sum(sin_j)
total_con_sim[j] <- sum(con_j)
}
ahorro_sim <- total_sin_sim - total_con_sim
prob_ahorro <- mean(ahorro_sim > 0)
ahorro_medio <- mean(ahorro_sim)
ahorro_p5 <- quantile(ahorro_sim, 0.05)
ahorro_p95 <- quantile(ahorro_sim, 0.95)
kable(data.frame(
Prob_ahorro = prob_ahorro,
Ahorro_medio = ahorro_medio,
Ahorro_P5 = ahorro_p5,
Ahorro_P95 = ahorro_p95
), digits = 2,
caption = "Distribucion del ahorro por cobertura (simulaciones)")
Distribucion del ahorro por cobertura (simulaciones)
| 5% |
0.28 |
-27886025 |
-105987845 |
78552244 |