1 1. Resumen ejecutivo

Objetivo del ejercicio. Financiar la compra de maquinaria amarilla por $350.000.000 COP mediante un crédito en EE. UU. y evaluar una cobertura con forward de divisas sobre el 75,00% del valor a partir del año 6.

Decisión metodológica. Se modela un crédito equivalente tipo francés en USD con pagos trimestrales a 10 años. Para la cobertura, se implementan 4 forwards anuales (años 6 a 9) y se aplica su tasa a 75% de las cuatro cuotas trimestrales de cada año cubierto. Esta aproximación se explicita porque el enunciado exige “4 forwards de 1 año”.

Variables en español. Todos los objetos, funciones y tablas creadas en el código se nombran en español para que el proyecto quede consistente con tu instrucción.

2 2. Contexto, fuente del crédito y supuestos

Bank of America publica que es SBA Preferred Lender y que el programa SBA 504 puede utilizarse para compra de equipos, incluyendo maquinaria de largo plazo, con cuota inicial típica del 10% y plazo de hasta 10 años para equipo (Bank of America 2026). A su vez, un referente público del mercado SBA 504 reportó una tasa fija efectiva de 5,61% para 10 años en marzo de 2026, con financiamiento de hasta 90% y baja cuota inicial (Growth Corp 2026b, 2026a).

Por ello, el informe adopta el siguiente supuesto pedagógico: se aproxima la estructura 504 real (banco + CDC) por un crédito equivalente único en USD, totalmente amortizable, con sistema francés y tasa efectiva anual de 5,61%.

tabla_supuestos <- tibble::tibble(
  supuesto = c(
    "Valor de la maquinaria",
    "Cuota inicial",
    "Monto financiado",
    "Plazo del crédito",
    "Pagos por año",
    "Sistema de amortización",
    "Tasa anual crédito en USD",
    "Cobertura forward sobre el crédito",
    "Inicio de cobertura",
    "Número de forwards anuales",
    "Tasa comercial USD para forward",
    "Tasa comercial COP para forward"
  ),
  valor = c(
    formatear_moneda_cop(params$monto_maquinaria_cop),
    formatear_porcentaje(params$porcentaje_cuota_inicial),
    formatear_porcentaje(1 - params$porcentaje_cuota_inicial),
    paste(params$plazo_anios_credito, "años"),
    params$pagos_por_anio,
    "Francés, cuotas trimestrales",
    formatear_porcentaje(params$tasa_credito_usd_anual),
    formatear_porcentaje(params$porcentaje_cobertura_forward),
    paste("Año", params$anio_inicio_cobertura),
    params$anios_cobertura,
    formatear_porcentaje(params$tasa_comercial_usa_anual),
    formatear_porcentaje(params$tasa_comercial_colombia_anual)
  )
)

knitr::kable(tabla_supuestos, col.names = c("Supuesto", "Valor"))
Supuesto Valor
Valor de la maquinaria $350.000.000 COP
Cuota inicial 10,00%
Monto financiado 90,00%
Plazo del crédito 10 años
Pagos por año 4
Sistema de amortización Francés, cuotas trimestrales
Tasa anual crédito en USD 5,61%
Cobertura forward sobre el crédito 75,00%
Inicio de cobertura Año 6
Número de forwards anuales 4
Tasa comercial USD para forward 6,75%
Tasa comercial COP para forward 11,22%

3 3. Análisis fundamental de la TRM

BBVA Research identifica que la tasa de cambio en Colombia sigue influida por la fortaleza global del dólar, las condiciones financieras internacionales, los precios de materias primas y, a nivel interno, por el déficit fiscal, la cuenta corriente y la percepción de riesgo país. En su escenario base, proyecta un tipo de cambio promedio cercano a COP 3.750 por dólar en 2026 y alrededor de COP 3.817 en 2027, con una trayectoria de depreciación gradual y alta volatilidad (BBVA Research 2026). Por su parte, el Banco de la República reporta una tasa de política monetaria de 10,25% vigente desde el 2 de febrero de 2026 (Banco de la República 2026b). Esa combinación sugiere que el peso podría sostener episodios de volatilidad con sesgo depreciativo si se mantienen las tensiones externas e internas.

serie_spot_diaria <- obtener_serie_spot_usdcop(
  fecha_inicio = params$fecha_inicio_historica,
  precio_spot_manual_respaldo = params$precio_spot_manual_respaldo
)

serie_spot_mensual <- construir_serie_mensual(serie_spot_diaria)

precio_spot_actual <- dplyr::last(serie_spot_diaria$precio_spot)
fecha_spot_actual <- dplyr::last(serie_spot_diaria$fecha)

retornos_mensuales <- serie_spot_mensual %>%
  dplyr::mutate(retorno_log_mensual = c(NA_real_, diff(log(precio_spot)))) %>%
  dplyr::filter(!is.na(retorno_log_mensual))

media_mensual_retornos <- mean(retornos_mensuales$retorno_log_mensual)
desviacion_mensual_retornos <- sd(retornos_mensuales$retorno_log_mensual)
exceso_curtosis_retornos <- calcular_exceso_curtosis(retornos_mensuales$retorno_log_mensual)
grados_libertad_t <- estimar_grados_libertad_t(retornos_mensuales$retorno_log_mensual)

forward_teorico_anual_hoy <- precio_spot_actual * ((1 + params$tasa_comercial_colombia_anual) / (1 + params$tasa_comercial_usa_anual))
prima_forward_hoy <- forward_teorico_anual_hoy / precio_spot_actual - 1
tabla_variables_mercado <- tibble::tibble(
  variable = c(
    "Fecha del último spot descargado",
    "TRM / spot USD-COP usado en el proyecto",
    "Media mensual de retornos logarítmicos",
    "Desviación estándar mensual",
    "Exceso de curtosis muestral",
    "Grados de libertad estimados para T-Student",
    "Tasa comercial USD para forward",
    "Tasa comercial COP para forward",
    "Forward teórico anual hoy",
    "Prima forward teórica"
  ),
  valor = c(
    as.character(fecha_spot_actual),
    formatear_moneda_cop(precio_spot_actual, 2),
    formatear_porcentaje(media_mensual_retornos, 4),
    formatear_porcentaje(desviacion_mensual_retornos, 4),
    round(exceso_curtosis_retornos, 4),
    round(grados_libertad_t, 2),
    formatear_porcentaje(params$tasa_comercial_usa_anual),
    formatear_porcentaje(params$tasa_comercial_colombia_anual),
    formatear_moneda_cop(forward_teorico_anual_hoy, 2),
    formatear_porcentaje(prima_forward_hoy)
  )
)

knitr::kable(tabla_variables_mercado, col.names = c("Variable", "Valor"))
Variable Valor
Fecha del último spot descargado 2026-03-27
TRM / spot USD-COP usado en el proyecto $3.670,13 COP
Media mensual de retornos logarítmicos 0,3241%
Desviación estándar mensual 3,7116%
Exceso de curtosis muestral 0.7649
Grados de libertad estimados para T-Student 11.84
Tasa comercial USD para forward 6,75%
Tasa comercial COP para forward 11,22%
Forward teórico anual hoy $3.823,81 COP
Prima forward teórica 4,19%
ggplot(serie_spot_diaria, aes(x = fecha, y = precio_spot)) +
  geom_line(linewidth = 0.7) +
  labs(
    title = "Serie histórica del USD/COP descargada automáticamente",
    subtitle = unique(serie_spot_diaria$fuente),
    x = "Fecha",
    y = "Pesos colombianos por dólar"
  ) +
  scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

ggplot(retornos_mensuales, aes(x = retorno_log_mensual)) +
  geom_histogram(aes(y = after_stat(density)), bins = 35, alpha = 0.7) +
  stat_function(
    fun = dnorm,
    args = list(mean = media_mensual_retornos, sd = desviacion_mensual_retornos),
    linewidth = 1
  ) +
  labs(
    title = "Retornos logarítmicos mensuales del USD/COP",
    subtitle = "Se superpone una densidad normal con media y desviación muestral",
    x = "Retorno logarítmico mensual",
    y = "Densidad"
  ) +
  scale_x_continuous(labels = scales::percent_format(accuracy = 0.1, decimal.mark = ","))

Lectura económica. Si la tasa comercial en COP se mantiene por encima de la tasa comercial en USD, el forward teórico anual resulta superior al spot actual, lo que es coherente con la paridad cubierta de tasas. En otras palabras, cubrirse no significa necesariamente pagar menos en promedio, sino evitar escenarios de depreciación fuerte del peso.

4 4. Simulación del crédito de la maquinaria en USD

valor_maquinaria_cop <- params$monto_maquinaria_cop
valor_maquinaria_usd <- valor_maquinaria_cop / precio_spot_actual

cuota_inicial_usd <- valor_maquinaria_usd * params$porcentaje_cuota_inicial
monto_credito_usd <- valor_maquinaria_usd - cuota_inicial_usd

numero_cuotas <- params$plazo_anios_credito * params$pagos_por_anio
tasa_trimestral_credito_usd <- (1 + params$tasa_credito_usd_anual)^(1 / params$pagos_por_anio) - 1

tabla_credito_usd <- crear_tabla_amortizacion(
  monto = monto_credito_usd,
  tasa_periodica = tasa_trimestral_credito_usd,
  numero_periodos = numero_cuotas,
  fecha_inicio = Sys.Date(),
  frecuencia_meses = 12 / params$pagos_por_anio
) %>%
  dplyr::mutate(
    mes_pago = seq(3, by = 3, length.out = dplyr::n()),
    anio_credito = ceiling(numero_cuota / params$pagos_por_anio)
  )

cuota_trimestral_usd <- tabla_credito_usd$cuota_usd[1]

resumen_credito_usd <- tibble::tibble(
  concepto = c(
    "Valor maquinaria en USD",
    "Cuota inicial en USD",
    "Monto del crédito en USD",
    "Tasa trimestral efectiva",
    "Número de cuotas",
    "Cuota trimestral"
  ),
  valor = c(
    formatear_moneda_usd(valor_maquinaria_usd),
    formatear_moneda_usd(cuota_inicial_usd),
    formatear_moneda_usd(monto_credito_usd),
    formatear_porcentaje(tasa_trimestral_credito_usd),
    numero_cuotas,
    formatear_moneda_usd(cuota_trimestral_usd)
  )
)

knitr::kable(resumen_credito_usd, col.names = c("Concepto", "Valor"))
Concepto Valor
Valor maquinaria en USD USD 95,364.47
Cuota inicial en USD USD 9,536.45
Monto del crédito en USD USD 85,828.03
Tasa trimestral efectiva 1,37%
Número de cuotas 40
Cuota trimestral USD 2,803.39

Con el spot descargado al momento de tejer el informe, el valor de la maquinaria equivale a USD 95,364.47, de los cuales se paga una cuota inicial de USD 9,536.45 y se financian USD 85,828.03. La cuota trimestral del crédito francés resulta aproximadamente en USD 2,803.39.

DT::datatable(
  tabla_credito_usd %>%
    dplyr::mutate(
      saldo_inicial_usd = round(saldo_inicial_usd, 2),
      interes_usd = round(interes_usd, 2),
      abono_capital_usd = round(abono_capital_usd, 2),
      cuota_usd = round(cuota_usd, 2),
      saldo_final_usd = round(saldo_final_usd, 2)
    ),
  extensions = "Buttons",
  options = list(
    dom = "Bfrtip",
    buttons = c("copy", "csv", "excel"),
    pageLength = 10,
    scrollX = TRUE
  ),
  rownames = FALSE
)
tabla_componentes_credito_usd <- tabla_credito_usd %>%
  dplyr::select(numero_cuota, interes_usd, abono_capital_usd, saldo_final_usd) %>%
  tidyr::pivot_longer(
    cols = -numero_cuota,
    names_to = "concepto",
    values_to = "valor"
  )

ggplot(tabla_componentes_credito_usd, aes(x = numero_cuota, y = valor, color = concepto)) +
  geom_line(linewidth = 1) +
  labs(
    title = "Amortización del crédito en USD",
    subtitle = "Sistema francés con pagos trimestrales",
    x = "Número de cuota",
    y = "Valor en USD",
    color = "Componente"
  ) +
  scale_y_continuous(labels = scales::dollar_format(prefix = "USD ", big.mark = ",", decimal.mark = "."))

5 5. Recreación del crédito en pesos y análisis del comportamiento

tabla_credito_cop_hoy <- tabla_credito_usd %>%
  dplyr::mutate(
    saldo_inicial_cop = saldo_inicial_usd * precio_spot_actual,
    interes_cop = interes_usd * precio_spot_actual,
    abono_capital_cop = abono_capital_usd * precio_spot_actual,
    cuota_cop = cuota_usd * precio_spot_actual,
    saldo_final_cop = saldo_final_usd * precio_spot_actual
  )

cuota_trimestral_cop_hoy <- tabla_credito_cop_hoy$cuota_cop[1]

Al convertir el crédito con el spot actual, la cuota trimestral equivalente es $10.288.792 COP. En esta recreación estática el cronograma en pesos luce ordenado y predecible, pero esa apariencia es engañosa: el verdadero riesgo aparece cuando la TRM cambia en el tiempo. Por eso, en la siguiente sección se simula el USD/COP mes a mes y luego se vuelve a valorar cada pago del crédito en COP.

DT::datatable(
  tabla_credito_cop_hoy %>%
    dplyr::mutate(
      saldo_inicial_cop = round(saldo_inicial_cop, 0),
      interes_cop = round(interes_cop, 0),
      abono_capital_cop = round(abono_capital_cop, 0),
      cuota_cop = round(cuota_cop, 0),
      saldo_final_cop = round(saldo_final_cop, 0)
    ) %>%
    dplyr::select(numero_cuota, fecha_pago, anio_credito, saldo_inicial_cop, interes_cop, abono_capital_cop, cuota_cop, saldo_final_cop),
  extensions = "Buttons",
  options = list(
    dom = "Bfrtip",
    buttons = c("copy", "csv", "excel"),
    pageLength = 10,
    scrollX = TRUE
  ),
  rownames = FALSE
)

6 6. Retornos mensuales, desviación estándar y simulación MBG/BGM

El enunciado pide simular la TRM mensual con dos distribuciones:

  1. Normal, que representa un caso base más suave.
  2. T-Student, que introduce colas pesadas y captura mejor eventos extremos en la tasa de cambio.
meses_simulados <- params$plazo_anios_credito * 12

matriz_rutas_normal <- simular_mbg(
  precio_inicial = precio_spot_actual,
  media_mensual = media_mensual_retornos,
  desviacion_mensual = desviacion_mensual_retornos,
  meses = meses_simulados,
  numero_rutas = params$numero_rutas,
  distribucion = "normal",
  grados_libertad = grados_libertad_t,
  semilla = params$semilla
)

matriz_rutas_t_student <- simular_mbg(
  precio_inicial = precio_spot_actual,
  media_mensual = media_mensual_retornos,
  desviacion_mensual = desviacion_mensual_retornos,
  meses = meses_simulados,
  numero_rutas = params$numero_rutas,
  distribucion = "t_student",
  grados_libertad = grados_libertad_t,
  semilla = params$semilla + 1
)

muestra_rutas <- dplyr::bind_rows(
  crear_muestra_rutas(matriz_rutas_normal, "Normal"),
  crear_muestra_rutas(matriz_rutas_t_student, "T-Student")
)

cuantiles_rutas <- dplyr::bind_rows(
  resumir_cuantiles_rutas(matriz_rutas_normal, "Normal"),
  resumir_cuantiles_rutas(matriz_rutas_t_student, "T-Student")
)
tabla_estadistica_retornos <- tibble::tibble(
  medida = c(
    "Número de observaciones mensuales",
    "Media mensual",
    "Desviación estándar mensual",
    "Exceso de curtosis",
    "Grados de libertad T-Student"
  ),
  valor = c(
    nrow(retornos_mensuales),
    formatear_porcentaje(media_mensual_retornos, 4),
    formatear_porcentaje(desviacion_mensual_retornos, 4),
    round(exceso_curtosis_retornos, 4),
    round(grados_libertad_t, 2)
  )
)

knitr::kable(tabla_estadistica_retornos, col.names = c("Medida", "Valor"))
Medida Valor
Número de observaciones mensuales 194
Media mensual 0,3241%
Desviación estándar mensual 3,7116%
Exceso de curtosis 0.7649
Grados de libertad T-Student 11.84
ggplot(muestra_rutas, aes(x = mes, y = precio_spot, group = numero_ruta)) +
  geom_line(alpha = 0.20) +
  facet_wrap(~ distribucion, scales = "free_y") +
  labs(
    title = "Muestra de rutas simuladas del USD/COP",
    subtitle = "Se muestran 120 trayectorias en cada distribución",
    x = "Mes",
    y = "Precio spot simulado"
  ) +
  scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

ggplot(cuantiles_rutas, aes(x = mes)) +
  geom_ribbon(aes(ymin = percentil_5, ymax = percentil_95), alpha = 0.25) +
  geom_line(aes(y = mediana), linewidth = 1) +
  facet_wrap(~ distribucion, scales = "free_y") +
  labs(
    title = "Banda de incertidumbre de la TRM simulada",
    subtitle = "Rango entre percentil 5 y 95, con la mediana de cada mes",
    x = "Mes",
    y = "Precio spot simulado"
  ) +
  scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

7 7. Proceso de forward de divisas

SET-FX se presenta como la fuente oficial y en tiempo real del dólar en Colombia y su mercado Forward registra operaciones de derivados desde T+1 en adelante sobre USD/COP. Además, SET-ICAP reporta el cierre diario del mercado NDF, incluyendo puntos forward por plazo y devaluación (SET-ICAP FX 2026). Como el ejercicio pide forwards por encima de 6 meses y, además, sugiere 4 forwards de 1 año, se utiliza una estructura anual para cubrir los años 6 a 9.

La tasa forward teórica aplicada en este proyecto es:

\[ Forward_{t,1a} = Spot_t \times \frac{1 + i_{COP}}{1 + i_{USD}} \]

donde:

resultado_cobertura_normal <- aplicar_cobertura_forward(
  tabla_amortizacion = tabla_credito_usd,
  matriz_rutas_spot = matriz_rutas_normal,
  porcentaje_cobertura = params$porcentaje_cobertura_forward,
  anio_inicio_cobertura = params$anio_inicio_cobertura,
  anios_cobertura = params$anios_cobertura,
  tasa_usd_anual = params$tasa_comercial_usa_anual,
  tasa_cop_anual = params$tasa_comercial_colombia_anual
)

resultado_cobertura_t_student <- aplicar_cobertura_forward(
  tabla_amortizacion = tabla_credito_usd,
  matriz_rutas_spot = matriz_rutas_t_student,
  porcentaje_cobertura = params$porcentaje_cobertura_forward,
  anio_inicio_cobertura = params$anio_inicio_cobertura,
  anios_cobertura = params$anios_cobertura,
  tasa_usd_anual = params$tasa_comercial_usa_anual,
  tasa_cop_anual = params$tasa_comercial_colombia_anual
)

tabla_riesgo_total <- dplyr::bind_rows(
  resumir_riesgo_total(resultado_cobertura_normal$resumen_total_rutas, "Normal"),
  resumir_riesgo_total(resultado_cobertura_t_student$resumen_total_rutas, "T-Student")
)
tabla_forward <- tibble::tibble(
  concepto = c(
    "Mercado usado como referencia",
    "Cobertura aplicada",
    "Años cubiertos",
    "Convención adoptada",
    "Tasa comercial USD",
    "Tasa comercial COP",
    "Forward teórico anual hoy",
    "Prima forward hoy"
  ),
  valor = c(
    "SET-FX / NDF USD-COP",
    formatear_porcentaje(params$porcentaje_cobertura_forward),
    paste(params$anio_inicio_cobertura, "a", params$anio_inicio_cobertura + params$anios_cobertura - 1),
    "4 forwards anuales; cada forward cubre 75% de las 4 cuotas trimestrales del año correspondiente",
    formatear_porcentaje(params$tasa_comercial_usa_anual),
    formatear_porcentaje(params$tasa_comercial_colombia_anual),
    formatear_moneda_cop(forward_teorico_anual_hoy, 2),
    formatear_porcentaje(prima_forward_hoy)
  )
)

knitr::kable(tabla_forward, col.names = c("Concepto", "Valor"))
Concepto Valor
Mercado usado como referencia SET-FX / NDF USD-COP
Cobertura aplicada 75,00%
Años cubiertos 6 a 9
Convención adoptada 4 forwards anuales; cada forward cubre 75% de las 4 cuotas trimestrales del año correspondiente
Tasa comercial USD 6,75%
Tasa comercial COP 11,22%
Forward teórico anual hoy $3.823,81 COP
Prima forward hoy 4,19%

8 8. Eventos en los que la inversión se ve protegida y cuando no

Se considera que la inversión está protegida en un pago si el costo cubierto en COP es menor que el costo del mismo pago valorado al spot simulado. Análogamente, la inversión no está protegida si el costo cubierto es mayor.

tabla_proteccion_anual <- dplyr::bind_rows(
  resultado_cobertura_normal$resumen_anual %>% dplyr::mutate(distribucion = "Normal"),
  resultado_cobertura_t_student$resumen_anual %>% dplyr::mutate(distribucion = "T-Student")
) %>%
  dplyr::filter(cubierto) %>%
  dplyr::select(
    distribucion, anio_credito, probabilidad_proteccion,
    ahorro_medio_cop, costo_spot_medio_cop, costo_cubierto_medio_cop, tasa_forward_promedio
  )

DT::datatable(
  tabla_proteccion_anual %>%
    dplyr::mutate(
      probabilidad_proteccion = round(probabilidad_proteccion, 4),
      ahorro_medio_cop = round(ahorro_medio_cop, 0),
      costo_spot_medio_cop = round(costo_spot_medio_cop, 0),
      costo_cubierto_medio_cop = round(costo_cubierto_medio_cop, 0),
      tasa_forward_promedio = round(tasa_forward_promedio, 2)
    ),
  extensions = "Buttons",
  options = list(
    dom = "Bfrtip",
    buttons = c("copy", "csv", "excel"),
    pageLength = 8,
    scrollX = TRUE
  ),
  rownames = FALSE
)
ggplot(tabla_proteccion_anual, aes(x = factor(anio_credito), y = probabilidad_proteccion)) +
  geom_col(position = "dodge") +
  facet_wrap(~ distribucion) +
  labs(
    title = "Probabilidad de que el forward proteja la inversión",
    subtitle = "La protección se mide contra el costo spot de las cuotas del año cubierto",
    x = "Año del crédito",
    y = "Probabilidad de protección"
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1, decimal.mark = ","))

prob_normal <- tabla_riesgo_total$probabilidad_proteccion[tabla_riesgo_total$distribucion == "Normal"]
prob_t <- tabla_riesgo_total$probabilidad_proteccion[tabla_riesgo_total$distribucion == "T-Student"]

cat(
  paste0(
    "**Lectura rápida.** En el escenario Normal, la cobertura resulta protectora en ",
    formatear_porcentaje(prob_normal),
    " de las rutas sobre el período cubierto. En el escenario T-Student, la protección aparece en ",
    formatear_porcentaje(prob_t),
    "."
  )
)

Lectura rápida. En el escenario Normal, la cobertura resulta protectora en 35,30% de las rutas sobre el período cubierto. En el escenario T-Student, la protección aparece en 35,56%.

Interpretación. Cuando el peso se deprecia lo suficiente durante los años cubiertos, el forward tiende a ser favorable porque fija parte del costo en COP y evita que el 75% cubierto se pague al spot más alto. En cambio, cuando el peso se aprecia o la depreciación es menor que la prima forward, la cobertura puede parecer “cara” en promedio. Por eso la evaluación correcta no debe limitarse al costo esperado, sino también al riesgo extremo.

9 9. Comparación del flujo total: crédito sin cobertura vs crédito con forward

tabla_riesgo_total_formateada <- tabla_riesgo_total %>%
  dplyr::mutate(
    costo_esperado_sin_cobertura_cop = formatear_moneda_cop(costo_esperado_sin_cobertura_cop),
    costo_esperado_cubierto_cop = formatear_moneda_cop(costo_esperado_cubierto_cop),
    desviacion_sin_cobertura_cop = formatear_moneda_cop(desviacion_sin_cobertura_cop),
    desviacion_cubierto_cop = formatear_moneda_cop(desviacion_cubierto_cop),
    percentil_95_sin_cobertura_cop = formatear_moneda_cop(percentil_95_sin_cobertura_cop),
    percentil_95_cubierto_cop = formatear_moneda_cop(percentil_95_cubierto_cop),
    cvar_95_sin_cobertura_cop = formatear_moneda_cop(cvar_95_sin_cobertura_cop),
    cvar_95_cubierto_cop = formatear_moneda_cop(cvar_95_cubierto_cop),
    ahorro_promedio_total_cop = formatear_moneda_cop(ahorro_promedio_total_cop),
    probabilidad_proteccion = formatear_porcentaje(probabilidad_proteccion),
    reduccion_percentil_95 = formatear_porcentaje(reduccion_percentil_95),
    reduccion_cvar_95 = formatear_porcentaje(reduccion_cvar_95)
  )

knitr::kable(tabla_riesgo_total_formateada, col.names = c(
  "Distribución", "Costo esperado sin cobertura", "Costo esperado cubierto",
  "Desv. sin cobertura", "Desv. cubierta", "P95 sin cobertura", "P95 cubierto",
  "CVaR95 sin cobertura", "CVaR95 cubierto", "Ahorro promedio",
  "Prob. protección", "Reducción P95", "Reducción CVaR95"
))
Distribución Costo esperado sin cobertura Costo esperado cubierto Desv. sin cobertura Desv. cubierta P95 sin cobertura P95 cubierto CVaR95 sin cobertura CVaR95 cubierto Ahorro promedio Prob. protección Reducción P95 Reducción CVaR95
Normal $530.592.482 COP $532.576.890 COP $138.497.223 COP $136.297.087 COP $785.935.544 COP $781.336.135 COP $885.740.682 COP $879.716.996 COP -$1.984.408 COP 35,30% 0,59% 0,68%
T-Student $527.083.315 COP $529.008.850 COP $137.516.875 COP $135.420.138 COP $778.580.985 COP $775.444.845 COP $880.218.182 COP $875.084.317 COP -$1.925.536 COP 35,56% 0,40% 0,58%
tabla_densidad_flujo_total <- dplyr::bind_rows(
  resultado_cobertura_normal$resumen_total_rutas %>%
    dplyr::transmute(distribucion = "Normal", cobertura = "Sin cobertura", flujo_total_cop = total_sin_cobertura_cop),
  resultado_cobertura_normal$resumen_total_rutas %>%
    dplyr::transmute(distribucion = "Normal", cobertura = "Con cobertura", flujo_total_cop = total_cubierto_cop),
  resultado_cobertura_t_student$resumen_total_rutas %>%
    dplyr::transmute(distribucion = "T-Student", cobertura = "Sin cobertura", flujo_total_cop = total_sin_cobertura_cop),
  resultado_cobertura_t_student$resumen_total_rutas %>%
    dplyr::transmute(distribucion = "T-Student", cobertura = "Con cobertura", flujo_total_cop = total_cubierto_cop)
)

ggplot(tabla_densidad_flujo_total, aes(x = flujo_total_cop, fill = cobertura)) +
  geom_density(alpha = 0.30) +
  facet_wrap(~ distribucion, scales = "free") +
  labs(
    title = "Distribución del flujo total del crédito en COP",
    subtitle = "Comparación entre pagar todo al spot vs pagar con cobertura forward",
    x = "Flujo total del crédito en COP",
    y = "Densidad",
    fill = "Esquema"
  ) +
  scale_x_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

tabla_conclusiones <- tabla_riesgo_total %>%
  dplyr::mutate(
    cambia_costo_esperado = costo_esperado_cubierto_cop - costo_esperado_sin_cobertura_cop,
    cambia_p95 = percentil_95_cubierto_cop - percentil_95_sin_cobertura_cop,
    cambia_cvar95 = cvar_95_cubierto_cop - cvar_95_sin_cobertura_cop
  )

for (i in seq_len(nrow(tabla_conclusiones))) {
  fila <- tabla_conclusiones[i, ]

  texto_costo <- if (fila$cambia_costo_esperado < 0) {
    paste0("reduce el costo esperado en ", formatear_moneda_cop(abs(fila$cambia_costo_esperado)))
  } else {
    paste0("incrementa el costo esperado en ", formatear_moneda_cop(abs(fila$cambia_costo_esperado)))
  }

  texto_p95 <- if (fila$cambia_p95 < 0) {
    paste0("reduce el percentil 95 en ", formatear_moneda_cop(abs(fila$cambia_p95)))
  } else {
    paste0("incrementa el percentil 95 en ", formatear_moneda_cop(abs(fila$cambia_p95)))
  }

  texto_cvar <- if (fila$cambia_cvar95 < 0) {
    paste0("reduce el CVaR 95 en ", formatear_moneda_cop(abs(fila$cambia_cvar95)))
  } else {
    paste0("incrementa el CVaR 95 en ", formatear_moneda_cop(abs(fila$cambia_cvar95)))
  }

  cat(
    paste0(
      "- **Escenario ", fila$distribucion, "**: la cobertura ",
      texto_costo, ", ",
      texto_p95, " y ",
      texto_cvar, ".\n"
    )
  )
}
  • Escenario Normal: la cobertura incrementa el costo esperado en $1.984.408 COP, reduce el percentil 95 en $4.599.410 COP y reduce el CVaR 95 en $6.023.686 COP.
  • Escenario T-Student: la cobertura incrementa el costo esperado en $1.925.536 COP, reduce el percentil 95 en $3.136.139 COP y reduce el CVaR 95 en $5.133.865 COP.

10 10. Conclusión y recomendación

fila_normal <- tabla_riesgo_total %>% dplyr::filter(distribucion == "Normal")
fila_t <- tabla_riesgo_total %>% dplyr::filter(distribucion == "T-Student")

beneficio_por_riesgo <- (fila_normal$reduccion_cvar_95 > 0) | (fila_t$reduccion_cvar_95 > 0)
beneficio_por_costo <- (fila_normal$ahorro_promedio_total_cop > 0) | (fila_t$ahorro_promedio_total_cop > 0)

if (beneficio_por_riesgo && beneficio_por_costo) {
  cat("**Conclusión principal:** la cobertura forward fue beneficiosa tanto como seguro cambiario como en flujo esperado, por lo que la decisión de cubrir 75% del crédito desde el año 6 resulta financieramente consistente para una inversión intensiva en TRM.")
} else if (beneficio_por_riesgo && !beneficio_por_costo) {
  cat("**Conclusión principal:** la cobertura forward no necesariamente minimiza el costo promedio, pero sí mejora la protección frente a escenarios extremos de depreciación del peso. En ese sentido, fue beneficiosa como herramienta de gestión de riesgo, aunque no siempre como estrategia de minimización de costo esperado.")
} else if (!beneficio_por_riesgo && beneficio_por_costo) {
  cat("**Conclusión principal:** la cobertura forward mejora el costo promedio, pero no reduce suficientemente el riesgo extremo. Bajo este resultado, el forward ayuda más como estrategia táctica que como cobertura robusta.")
} else {
  cat("**Conclusión principal:** con los supuestos y la muestra descargada, la cobertura forward no mejora de forma clara ni el costo promedio ni la cola de pérdidas. En ese caso, la cobertura no sería la mejor decisión para este crédito particular.")
}

Conclusión principal: la cobertura forward no necesariamente minimiza el costo promedio, pero sí mejora la protección frente a escenarios extremos de depreciación del peso. En ese sentido, fue beneficiosa como herramienta de gestión de riesgo, aunque no siempre como estrategia de minimización de costo esperado.

10.1 Juicio financiero final

  1. Sobre el crédito. Financiar en USD puede ser atractivo por la tasa extranjera, pero convierte una obligación relativamente estable en dólares en un flujo incierto en COP.
  2. Sobre la cobertura. El forward no se evalúa solo por si “sale más barato” en promedio, sino por cuánto reduce la exposición a depreciaciones severas.
  3. Sobre la decisión de inversión. Si la empresa valora estabilidad de caja y quiere proteger su capacidad de pago en pesos, una cobertura parcial como la modelada puede justificarse, sobre todo bajo escenarios con colas pesadas.
  4. Sobre las limitaciones. Este informe usa:
    • una aproximación de crédito único para representar una estructura SBA 504 real;
    • una cobertura anual sobre cuotas trimestrales por exigencia del enunciado;
    • una tasa forward teórica basada en tasas comerciales públicas, dada la disponibilidad abierta de información de mercado.

11 11. Exportación de tablas para anexos

Referencias

Banco de la República. 2026a. “IBR: Indicador Bancario de Referencia.” 2026. https://suameca.banrep.gov.co/estadisticas-economicas/informacionSerie/241/tasas_interes_indicador_bancario_referencia_ibr/.
———. 2026b. “Informe de Política Monetaria – Enero de 2026.” 2026. https://www.banrep.gov.co/es/informe-de-politica-monetaria.
Bank of America. 2026. “What Is an SBA Loan and How Do i Qualify?” 2026. https://business.bankofamerica.com/en/resources/what-is-an-sba-loan.
BBVA Research. 2026. “Situación Colombia – Marzo 2026.” 2026. https://www.bbvaresearch.com/wp-content/uploads/2026/03/20260311_TextoSC_Marzo2026.pdf.
Federal Reserve Bank of St. Louis. 2026. “Bank Prime Loan Rate (WPRIME).” 2026. https://fred.stlouisfed.org/series/WPRIME.
Growth Corp. 2026a. “Machinery & Equipment Financing.” 2026. https://www.growthcorp.com/equipment/.
———. 2026b. “SBA 504 Rate Pricing.” 2026. https://www.growthcorp.com/sba-504-rate-pricing/.
SET-ICAP FX. 2026. “Productos y Servicios: Fuente de Información de Divisas En Colombia.” 2026. https://set-icap.com/set-icap-fx/todos-los-productos-y-servicios-de-set-icap-fx-de-negociacon-registro-y-post-trade-para-el-analisis-de-informacion-sobre-divisas-somos-la-principal-fuente-de-informacion-de-divisas-en-colombia/.