Instituto Tecnologico Metropolitano

Derivados Financieros

Taller: Proceso del Crédito y Cobertura Cambiaria


1. Análisis fundamental de la TRM

Durante 2024, la economía colombiana ha presentado una desaceleración y una inflación en descenso, mientras el Banco de la República (Banrep, 2024) ha iniciado un ciclo de reducción de tasas. La Reserva Federal de Estados Unidos (FED, 2024) mantiene tasas elevadas, generando presión alcista sobre la TRM al favorecer los flujos de capital hacia el dólar.

Tabla 1: Factores clave de la TRM

Tabla 2: Proyecciones de la TRM a un año

Ambas tablas resumen el contexto económico y las expectativas de mercado para la TRM, reflejando los factores determinantes y el consenso de proyecciones de los principales analistas y entidades financieras (Banrep, 2024; BBVA Research, 2024; Bloomberg, 2024).

2. Cálculo de retornos mensuales y desviación estándar de la TRM

trm_xts <- rmre_data(start_date = "2015-01-01", end_date = "2025-05-14", frequency = 12)
trm_data <- data.frame(
  fecha = as.Date(index(trm_xts)),
  trm = as.numeric(trm_xts[, 1])
) %>% arrange(fecha)

# Gráfico TRM
plot_ly(trm_data, x = ~fecha, y = ~trm, type = 'scatter', mode = 'lines',
        line = list(color = '#003366')) %>%
  layout(title = "TRM Mensual (2015-2025)",
         xaxis = list(title = "Fecha"), 
         yaxis = list(title = "COP/USD"))

Este gráfico muestra la evolución histórica de la TRM desde 2015 hasta 2025, basada en datos del Banco de la República (Banrep, 2025). Se observa una tendencia de devaluación del peso, con episodios de volatilidad, en línea con las presiones globales y locales.

trm_data <- trm_data %>%
  mutate(log_ret = log(trm / lag(trm))) %>%
  filter(!is.na(log_ret))

mu <- mean(trm_data$log_ret)
sigma <- sd(trm_data$log_ret)

cat("Retorno mensual promedio:", round(mu, 6), "\n")
## Retorno mensual promedio: 0.004531
cat("Desviación estándar mensual:", round(sigma, 6), "\n")
## Desviación estándar mensual: 0.040533
# Gráfico retornos logarítmicos
plot_ly(trm_data, x = ~fecha, y = ~log_ret, type = 'scatter', mode = 'lines',
        line = list(color = '#336699')) %>%
  layout(title = "Retornos Logarítmicos Mensuales",
         xaxis = list(title = "Fecha"), 
         yaxis = list(title = "Retorno"))

Los retornos logarítmicos permiten visualizar la volatilidad mensual de la TRM, basada en datos de Banrep (2025). Si bien la media es positiva, existen periodos de alta variabilidad, reflejando el riesgo de cambiario relevante para un crédito en dólares.

DT::datatable(
  trm_data,
  options = list(pageLength = 10),
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: center; color: #003366; font-weight: bold;',
    'Serie histórica y retornos logarítmicos de la TRM'
  )
)

3. Simulación MBG mensual de la TRM

n_sim <- 1000
n_meses <- 120
dt <- 1/12
ultimo_valor <- tail(trm_data$trm, 1)
trayectorias <- matrix(NA, nrow = n_meses + 1, ncol = n_sim)
trayectorias[1, ] <- ultimo_valor

for (t in 1:n_meses) {
  z <- rnorm(n_sim)
  trayectorias[t + 1, ] <- trayectorias[t, ] * exp((mu - 0.5 * sigma^2) * dt + sigma * sqrt(dt) * z)
}

fechas_sim <- seq(from = max(trm_data$fecha), by = "month", length.out = n_meses + 1)

fig_sim <- plot_ly() %>%
  layout(title = "Simulación MBG de la TRM (120 meses)",
         xaxis = list(title = "Fecha"), yaxis = list(title = "TRM (COP/USD)"))
for (i in 1:50) {
  fig_sim <- fig_sim %>%
    add_trace(x = fechas_sim, y = trayectorias[, i], type = 'scatter', mode = 'lines',
              line = list(color = 'rgba(0,51,102,0.2)'), showlegend = FALSE)
}
fig_sim

La simulación de 1,000 trayectorias bajo Movimiento Browniano Geométrico (MBG) muestra los posibles escenarios futuros de la TRM en los próximos 10 años, basada en datos históricos de Banrep (2025). Se observa una tendencia general creciente y dispersión, resaltando la incertidumbre en la proyección.

4. Simulación de crédito de la maquinaria (USD y COP)

4.1 Simulación crédito en USD

Para este ejercicio se toma como referencia JP Morgan Chase (5.5%), por ser uno de los bancos más reconocidos internacionalmente en la emisión de créditos corporativos internacionales. En mayo de 2024, la tasa promedio para líneas internacionales de crédito a 10 años para empresas ronda el 5.5% anual, de acuerdo a informes de Bankrate (2024) y JP Morgan Private Bank (2024).

Instituciones como JP Morgan sí manejan líneas corporativas de crédito internacional, accesibles para financiamiento de maquinaria y proyectos empresariales en Colombia. Esto permite reflejar un escenario realista y alineado con las mejores prácticas internacionales de financiación.

monto_cop <- 300000000
tasa_anual_usd <- 0.055
plazo_anios <- 10
plazo_meses <- plazo_anios * 12
inicial_porcentaje <- 0.1
tasa_mensual_usd <- tasa_anual_usd / 12

monto_usd <- monto_cop / ultimo_valor
monto_inicial_usd <- monto_usd * inicial_porcentaje
monto_financiado_usd <- monto_usd - monto_inicial_usd
cuota_usd <- monto_financiado_usd * (tasa_mensual_usd / (1 - (1 + tasa_mensual_usd)^(-plazo_meses)))

amort_usd <- data.frame(
  mes = 1:plazo_meses,
  fecha = fechas_sim[2:(plazo_meses + 1)],
  saldo_usd = NA,
  cuota_usd = cuota_usd,
  interes_usd = NA,
  capital_usd = NA,
  trm = trayectorias[2:(plazo_meses + 1), 1],
  cuota_cop = NA
)
amort_usd$saldo_usd[1] <- monto_financiado_usd
for (i in 2:plazo_meses) {
  amort_usd$interes_usd[i] <- amort_usd$saldo_usd[i - 1] * tasa_mensual_usd
  amort_usd$capital_usd[i] <- cuota_usd - amort_usd$interes_usd[i]
  amort_usd$saldo_usd[i] <- amort_usd$saldo_usd[i - 1] - amort_usd$capital_usd[i]
}
amort_usd$interes_usd[1] <- amort_usd$saldo_usd[1] * tasa_mensual_usd
amort_usd$capital_usd[1] <- cuota_usd - amort_usd$interes_usd[1]
amort_usd$cuota_cop <- amort_usd$cuota_usd * amort_usd$trm

amort_usd_formateada <- amort_usd %>%
  mutate(across(where(is.numeric), round, 2),
         fecha = as.character(fecha))

Esta tabla muestra el detalle del crédito en dólares con su conversión mensual a pesos colombianos bajo el escenario simulado de la TRM, permitiendo observar el impacto del tipo de cambio en cada cuota.

4.2 Simulación crédito en COP

monto_financiado_cop <- monto_cop * 0.9
cuota_cop_fija <- monto_financiado_cop * (tasa_mensual_usd / (1 - (1 + tasa_mensual_usd)^(-plazo_meses)))
amort_pesos <- data.frame(
  mes = 1:plazo_meses,
  fecha = fechas_sim[2:(plazo_meses + 1)],
  saldo_cop = NA,
  cuota_cop = cuota_cop_fija,
  interes_cop = NA,
  capital_cop = NA
)

amort_pesos$saldo_cop[1] <- monto_financiado_cop
for (i in 2:plazo_meses) {
  amort_pesos$interes_cop[i] <- amort_pesos$saldo_cop[i - 1] * tasa_mensual_usd
  amort_pesos$capital_cop[i] <- cuota_cop_fija - amort_pesos$interes_cop[i]
  amort_pesos$saldo_cop[i] <- amort_pesos$saldo_cop[i - 1] - amort_pesos$capital_cop[i]
}
amort_pesos$interes_cop[1] <- amort_pesos$saldo_cop[1] * tasa_mensual_usd
amort_pesos$capital_cop[1] <- cuota_cop_fija - amort_pesos$interes_cop[1]

amort_pesos_formateada <- amort_pesos %>%
  mutate(across(where(is.numeric), round, 2),
         fecha = as.character(fecha))

promediar_tabla <- function(df) {
  df %>%
    summarise(across(where(is.numeric), mean, na.rm = TRUE),
              fecha = first(fecha)) # Conserva la primera fecha (deberían ser iguales)
}

# Aplica la función a cada data frame de la lista y luego combina los resultados
trayectoria_promedio <- amort_pesos %>%
  bind_rows() %>%
  group_by(mes, fecha) %>%
  summarise(across(where(is.numeric), mean, na.rm = TRUE ), .groups="drop")

# Formatear la tabla promedio (opcional)
trayectoria_promedio_formateada <- trayectoria_promedio %>%
  mutate(across(where(is.numeric), round, 2))

# Mostrar la tabla promedio
DT::datatable(
  trayectoria_promedio_formateada,
  filter = "top",
  options = list(
    pageLength = 10,
    dom = 'Bfrtip',
    buttons = c('copy', 'csv', 'excel', 'pdf', 'print')
  ),
  extensions = 'Buttons',
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: center; color: #336699; font-weight: bold;',
    'Tabla de Amortización Promedio - Crédito en Pesos'
  )
)

En esta tabla se visualiza el crédito en pesos con cuotas fijas, sin el efecto de la volatilidad cambiaria, lo que facilita la planeación de pagos.

4.3 Gráfico: Comparación de Cuotas en COP

El gráfico compara el comportamiento de las cuotas de ambos créditos en pesos. El crédito en USD presenta variabilidad a lo largo del tiempo, mientras que el crédito en COP permanece constante.

5. Gráficos y análisis adicionales

5.1 Saldo Pendiente del Crédito en el Tiempo

Se observa el saldo pendiente del crédito tanto en dólares como en pesos colombianos, mostrando el efecto acumulado de la TRM en el valor a pagar en moneda local.

5.2 Distribución de la TRM al Mes 120

La distribución simulada de la TRM al finalizar el crédito muestra los diferentes escenarios posibles y la dispersión de los riesgos asociados.

5.3 Costo acumulado del crédito

El gráfico muestra cómo el costo total del crédito en dólares y en pesos se va acumulando con el tiempo. El impacto del tipo de cambio genera mayor incertidumbre sobre el costo final en pesos.

## 
## 
## --- CONCLUSIONES EJECUTIVAS DEL APARTADO 1 ---
## 
## 1. Análisis fundamental de la TRM:
## La TRM muestra una tendencia de crecimiento moderado, con una proyección conservadora de incremento del 5% anual, soportada por la inflación diferencial y la política monetaria de EE.UU., según las fuentes y análisis del mercado.
## 
## 2. Retornos y volatilidad mensual:
## El retorno mensual promedio de la TRM fue de 0.004531 , con una desviación estándar de 0.040533 . Esto indica que la TRM presenta una volatilidad contenida, aunque significativa en el largo plazo, lo que exige una gestión activa del riesgo cambiario.
## 
## 3. Simulación MBG de la TRM:
## La simulación de 1.000 trayectorias durante 10 años permite visualizar distintos escenarios para la TRM, destacando la incertidumbre y la importancia de mecanismos de cobertura para créditos en dólares.
## 
## 4. Crédito en USD:
## El crédito estructurado en dólares, aunque tiene cuotas fijas en esa moneda, implica una alta exposición al riesgo cambiario, lo que se traduce en volatilidad en los pagos en pesos colombianos durante toda la vida del crédito.
## 
## 5. Crédito en COP:
## El crédito en pesos, usando la misma tasa como referencia, permite estabilizar los pagos mensuales en moneda local, facilitando la planeación financiera y eliminando el riesgo de tipo de cambio, aunque usualmente conlleva una tasa efectiva mayor en el mercado colombiano.
## 
## 6. Comparación general:
## El crédito en dólares puede ser atractivo por su menor tasa de interés nominal, pero puede volverse oneroso ante escenarios adversos de devaluación. En cambio, el crédito en COP reduce la incertidumbre sobre los pagos futuros, aunque suele implicar un costo financiero mayor. Por ello, la cobertura cambiaria se vuelve relevante si se opta por endeudamiento en moneda extranjera.

Parte 2: Proceso de Futuros

2.1 Datos históricos del futuro CL (Petroleo)

# Elegir el archivo manualmente
archivo_seleccionado <- file.choose()
data <- read_excel(archivo_seleccionado)

# Limpiar y preparar precios de cierre
data$`Precio cierre` <- as.numeric(gsub(",", "", data$`Precio cierre`))

# Crear nuevo data.frame con solo Fecha y Precio cierre
datos_TRX <- data %>%
  select(Fecha, `Precio cierre`) %>%
  rename(precio_cierre = `Precio cierre`) %>%
  arrange(Fecha)

# Calcular rendimientos logarítmicos
TRX_f <- datos_TRX %>%
  mutate(log_ret = log(precio_cierre / lag(precio_cierre))) %>%
  filter(!is.na(log_ret))

# Agrupar por mes y tomar el último precio de cada mes
mensual_TRX <- datos_TRX %>%
  mutate(Fecha = as.Date(Fecha),
         year_month = floor_date(Fecha, "month")) %>%
  group_by(year_month) %>%
  summarise(precio_cierre = last(precio_cierre), .groups = "drop") %>%
  arrange(year_month)

# Calcular rendimientos logarítmicos mensuales
TRX_f <- mensual_TRX %>%
  mutate(log_ret = log(precio_cierre / lag(precio_cierre))) %>%
  filter(!is.na(log_ret))

# Verificar los datos resultantes

datatable(TRX_f,
          options = list(pageLength = 10, autoWidth = TRUE),
          rownames = FALSE) %>%
  formatRound(columns = c("precio_cierre", "log_ret"), digits = 3)
p1 <- plot_ly(TRX_f, x = ~year_month, y = ~precio_cierre, type = 'scatter', mode = 'lines+markers',
              line = list(width = 2), marker = list(size = 5)) %>%
  layout(
    title = list(text = '<b>Precio de cierre mensual del Futuro TRM</b>', x = 0.5),
    xaxis = list(title = "Fecha"),
    yaxis = list(title = "Precio de Cierre (COP)"),
    hovermode = "x unified"
  )

p1
p2 <- plot_ly(TRX_f, x = ~year_month, y = ~log_ret, type = 'scatter', mode = 'lines',
              line = list(color = 'steelblue', width = 2)) %>%
  layout(
    title = list(text = '<b>Rendimientos logarítmicos mensuales del Futuro TRM</b>', x = 0.5),
    xaxis = list(title = "Fecha"),
    yaxis = list(title = "Log-retorno"),
    hovermode = "x unified"
  )

p2

Los datos históricos del futuro del petróleo ( CL ) utilizados aquí son un proxy debido a la falta de acceso directo a datos históricos del futuro de la TRM de la Bolsa de Valores de Colombia (BVC, 2025). Los gráficos muestran la evolución de los precios y rendimientos mensuales.

2.1 Datos históricos simulados del futuro TRM

Parámetros

Aquí simulamos el flujo de caja asociado a la gestión del margen durante los años 6 a 10 de nuestra simulación. Asumimos 50 contratos de futuros.

Para cada mes calcula las ganancias o pérdidas basadas en el movimiento del precio del futuro. Actualiza el saldo del margen. Verifica si el saldo cae por debajo del margen de mantenimiento, lo que desencadenaría un “margin call” (una llamada para depositar fondos adicionales). También se considera un costo de “rollover” cada 3 meses, que es el costo de renovar los contratos de futuros a medida que vencen.

# Estadísticas mensuales basadas en la TRM agrupada por mes
mu_futuro <- mean(TRX_f$log_ret, na.rm = TRUE)
sigma_futuro <- sd(TRX_f$log_ret, na.rm = TRUE)

# Mostrar resultados
cat("Retorno mensual promedio:", round(mu_futuro, 6), "\n")
## Retorno mensual promedio: -0.002248
cat("Desviación estándar mensual:", round(sigma_futuro, 6), "\n")
## Desviación estándar mensual: 0.027356

Grafica Simulación BMG COMPLETA A 10 AÑOS (mensual)

# EXTRAER SOLO AÑOS 6 a 10 PARA EL RESTO DEL TALLER
futuro_anios_6_10 <- futuro_valores[61:121, ]
fechas_anios_6_10 <- fechas_sim[61:121]

criterios de exposición total

# Parámetros reales
valor_inversion <- 300000000             # Valor maquinaria COP
porcentaje_cubierto <- 0.70              # Cobertura
valor_cubierto <- valor_inversion * porcentaje_cubierto

# TRM estimada del último mes de la serie mensual
precio_trm <- tail(mensual_TRX$precio_cierre, 1)
nominal_contrato_usd <- 1000
tamano_contrato_cop <- nominal_contrato_usd * precio_trm

# Cálculo de contratos y márgenes con tasas reales BVC
n_contratos <- valor_cubierto / tamano_contrato_cop
margen_inicial_pct <- 0.063
margen_mantenimiento_pct <- 0.50
margen_inicial_cop <- tamano_contrato_cop * margen_inicial_pct
margen_mantenimiento_cop <- tamano_contrato_cop * margen_mantenimiento_pct

# Tabla final
df_margenes <- tibble::tibble(
  `Valor cubierto (COP)` = valor_cubierto,
  `TRM estimada (última)` = precio_trm,
  `Tamaño contrato (COP)` = tamano_contrato_cop,
  `N° contratos necesarios` = round(n_contratos),
  `Margen inicial (6.3%)` = margen_inicial_cop,
  `Margen mantenimiento (50%)` = margen_mantenimiento_cop
)

# Tabla interactiva con scroll
datatable(df_margenes,
          options = list(scrollX = TRUE, dom = 't'),
          rownames = FALSE) %>%
  formatRound(columns = 1:6, digits = 0)

Esta tabla es una proyección vital de cómo se comportaría nuestro margen. Pueden ver mes a mes: el precio del futuro simulado, la posición (larga o corta), las ganancias o pérdidas generadas, el saldo del margen, y el monto de cualquier “margin call” necesario. Esto nos ayuda a entender los requisitos de liquidez de nuestra estrategia de cobertura.

# Parámetros
n_contratos <- 50  # Para cubrir ~210M COP (70% de 300M)
tamano_contrato_cop <- 1000 * 4188.15  # Valor nocional (1,000 USD * TRM)
margen_inicial <- tamano_contrato_cop * 0.063  # 6.3%
margen_mantenimiento <- margen_inicial * 0.50  # 50% del inicial
coste_rollover <- tamano_contrato_cop * 0.001  # 0.1% por rollover
n_meses <- 48  # Meses 61 a 108 (años 6 a 10)
dias_por_mes <- 21  # Días hábiles por mes

# Verificar dimensiones
if (length(fechas_anios_6_10) < 48 || nrow(futuro_anios_6_10) < 48) {
  stop("Error: fechas_anios_6_10 o futuro_anios_6_10 tienen menos de 48 elementos/filas")
}

# Identificar meses de vencimiento trimestral
meses_vencimiento <- which(month(fechas_anios_6_10[1:48]) %in% c(3, 6, 9, 12))

# Inicializar flujo de caja
flujo_caja <- data.frame(
  mes = 61:108,
  fecha = fechas_anios_6_10[1:48],
  precio_futuro = futuro_anios_6_10[1:48, 1],  # Trayectoria individual
  posicion = NA_character_,  # "larga" o "corta"
  ganancia_perdida = 0,
  saldo_margen = margen_inicial * n_contratos,
  margin_call = 0
)

# Determinar posiciones iniciales
flujo_caja$posicion[1] <- ifelse(flujo_caja$precio_futuro[2] > flujo_caja$precio_futuro[1], "larga", "corta")

# Simular flujo de caja
for (i in 2:n_meses) {
  # Determinar posición
  flujo_caja$posicion[i] <- ifelse(flujo_caja$precio_futuro[i] > flujo_caja$precio_futuro[i-1], "larga", "corta")
  
  # Calcular ganancia/pérdida diaria (mensual/21)
  delta_precio_diario <- (flujo_caja$precio_futuro[i] - flujo_caja$precio_futuro[i-1]) / dias_por_mes
  if (flujo_caja$posicion[i-1] == "larga") {
    flujo_caja$ganancia_perdida[i] <- delta_precio_diario * 1000 * n_contratos * dias_por_mes
  } else {
    flujo_caja$ganancia_perdida[i] <- -delta_precio_diario * 1000 * n_contratos * dias_por_mes
  }
  
  # Actualizar saldo de margen
  flujo_caja$saldo_margen[i] <- flujo_caja$saldo_margen[i-1] + flujo_caja$ganancia_perdida[i]
  
  # Verificar margin call
  if (flujo_caja$saldo_margen[i] < margen_mantenimiento * n_contratos) {
    flujo_caja$margin_call[i] <- (margen_inicial * n_contratos) - flujo_caja$saldo_margen[i]
    flujo_caja$saldo_margen[i] <- margen_inicial * n_contratos
  }
  
  # Rollover en meses de vencimiento trimestral
  if (i %in% meses_vencimiento) {
    flujo_caja$saldo_margen[i] <- flujo_caja$saldo_margen[i] - (coste_rollover * n_contratos)
  }
}

# Formatear tabla
flujo_caja_formateada <- flujo_caja %>%
  mutate(across(where(is.numeric), round, 2),
         fecha = as.character(fecha))

# Mostrar tabla
DT::datatable(
  flujo_caja_formateada,
  options = list(pageLength = 10, scrollX = TRUE),
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: center; color: #003366; font-weight: bold;',
    'Flujo de Caja de Margen (Años 6 a 10, 50 Contratos)'
  )
)
# Gráfico del saldo de margen
plot_ly() %>%
  add_trace(x = flujo_caja$fecha, y = flujo_caja$saldo_margen, type = 'scatter', mode = 'lines',
            name = "Saldo de Margen", line = list(color = '#003366')) %>%
  add_trace(x = flujo_caja$fecha, y = rep(margen_mantenimiento * n_contratos, n_meses),
            type = 'scatter', mode = 'lines', name = "Margen de Mantenimiento",
            line = list(color = '#FF3333', dash = 'dash')) %>%
  layout(title = "Saldo de Margen vs. Margen de Mantenimiento (50 Contratos)",
         xaxis = list(title = "Fecha"),
         yaxis = list(title = "Saldo (COP)"))

Referencias

Banco de la República. (2024). Informe de política monetaria . Recuperado el 17 de mayo de 2025 de https://www.banrep.gov.co/es/informe-politica-monetaria Banco de la República. (2025). Serie histórica de la Tasa Representativa del Mercado (TRM) . Recuperado el 17 de mayo de 2025 de https://www.banrep.gov.co/es/trm BBVA Investigación. (2024). Proyecciones económicas para Colombia 2024-2025 . Recuperado el 17 de mayo de 2025 de https://www.bbvaresearch.com Bloomberg. (2024). Panel de pronóstico de divisas de Bloomberg . Recuperado el 17 de mayo de 2025 de https://www.bloomberg.com/forex Tasa bancaria. (2024). Tasas de interés para créditos corporativos internacionales . Recuperado el 17 de mayo de 2025 de https://www.bankrate.com Bolsa de Valores de Colombia. (2025). Mercado de derivados - Futuros TRM . Recuperado el 17 de mayo de 2025 de https://www.bvc.com.co/mercados/derivados Banco Privado JP Morgan. (2024). Informes de tasas de crédito internacional . Recuperado el 17 de mayo de 2025 de https://privatebank.jpmorgan.com texto