Parte 1 - Crédito en USD y COP

1.1 Análisis Fundamental de la TRM

Introducción

La Tasa Representativa del Mercado (TRM) representa el precio promedio ponderado del dólar estadounidense con respecto al peso colombiano, calculado a partir de las operaciones del mercado cambiario. Esta tasa cumple un papel fundamental en las decisiones de inversión, importación, exportación y en la política monetaria. Comprender su comportamiento es crucial para anticipar movimientos económicos relevantes en el corto y mediano plazo.

Análisis Fundamental de la TRM

1. Política Monetaria y Decisiones del Banco de la República

Uno de los principales determinantes internos de la TRM es la política monetaria implementada por el Banco de la República. En su Informe de Política Monetaria de marzo de 2025, la entidad señaló una trayectoria de reducción progresiva en la tasa de intervención, que bajó al 9,25% en abril de 2025, en línea con la moderación en la inflación y el débil crecimiento económico (Banco de la República, 2025). Esta flexibilización podría favorecer una depreciación moderada del dólar, al estimular el consumo interno y atraer inversión extranjera en renta fija local.

2. Inflación y Diferenciales de Tasa de Interés

La inflación en Colombia, aunque en descenso, sigue por encima del rango meta (3%). El DANE reportó una inflación anual del 5,16% en abril de 2025. A pesar de esta disminución, persisten presiones inflacionarias derivadas de alimentos y servicios públicos. Un diferencial significativo con la inflación en EE.UU. podría generar depreciación del peso colombiano si los flujos de capital migran hacia mercados más estables (Grupo Bancolombia, 2025, p. 15).

3. Comercio Exterior y Precios del Petróleo

Colombia es una economía dependiente de las exportaciones de materias primas, especialmente petróleo. La recuperación en los precios del crudo (Brent cotizando cerca de USD 83/barril en mayo de 2025) ha favorecido los ingresos por exportaciones y contribuido a una revaluación del peso colombiano durante los primeros meses del año (Banco Agrario, 2025). Sin embargo, la volatilidad global en la producción y la demanda sigue siendo un riesgo estructural.

4. Flujo de Inversión Extranjera Directa (IED)

La IED mostró signos de recuperación en 2024 y continúa en 2025, especialmente en sectores de infraestructura, energía renovable y servicios financieros. Esto genera presión apreciativa sobre la moneda local, fortaleciendo al peso frente al dólar. Las políticas fiscales y regulatorias estables son un incentivo para esta dinámica, aunque la incertidumbre política podría revertirla.

5. Factores Globales: FED y Geopolítica

En el contexto global, las decisiones de política monetaria de la Reserva Federal (FED) de EE.UU. han afectado las monedas emergentes. Una FED menos restrictiva para el segundo semestre de 2025 podría reducir la fortaleza del dólar, facilitando una apreciación gradual del peso. No obstante, riesgos geopolíticos, como tensiones en Medio Oriente y conflictos comerciales entre grandes economías, podrían aumentar la demanda global por activos refugio como el dólar.

Proyecciones de la TRM (2025-2026)

Diversas instituciones financieras colombianas han emitido proyecciones sobre la evolución esperada de la TRM. Según el Informe de Proyecciones Económicas de Bancolombia (marzo de 2025), se espera que la tasa de cambio se mantenga dentro del rango de 4.000 a 4.200 COP/USD en lo que resta del año, con una leve tendencia a la apreciación del peso hacia 2026, gracias al ajuste inflacionario y la moderación del dólar a nivel global.

De igual forma, el Banco Agrario prevé que el comportamiento del dólar estará condicionado por la estabilidad del mercado energético internacional y las decisiones de política monetaria local. En su boletín de mayo de 2025, se estima una TRM promedio de 4.100 COP/USD para el tercer trimestre del año y de 4.050 COP/USD hacia el cierre de 2025.

El Banco de la República, por su parte, no emite una proyección oficial de la TRM, pero en sus modelos de consistencia macroeconómica considera un escenario de estabilidad cambiaria sin presiones fuertes hacia la devaluación. Conclusión

El análisis fundamental de la TRM en Colombia sugiere un comportamiento moderadamente estable en lo que resta de 2025, con posibilidades de apreciación del peso si continúan bajando las tasas de interés, se mantiene el precio del petróleo y mejora la inversión extranjera directa. Sin embargo, el contexto internacional sigue siendo incierto y podría revertir estas tendencias. Por ello, tanto empresas como inversionistas deben mantener estrategias de cobertura ante riesgos cambiarios.

Cargar Librerias

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.2     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(lubridate)
library(readxl)
library(ggplot2)
library(dplyr)
library(tidyr)
library(kableExtra)
## 
## Attaching package: 'kableExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     group_rows

Carga del archivo con la TRM Histórica

# Permite seleccionar manualmente el archivo .xls
archivo_trm <- file.choose()

# Cargar datos desde la primera hoja
datos_trm <- read_excel(archivo_trm, sheet = 1)

# Verificar nombres reales de columnas
names(datos_trm)
## [1] "Fecha" "trm"

1.2.1. Retornos mensuales y la desviación estándar mensual de la TRM histórica

# Asegúrate de que las columnas se llaman "Fecha" y "trm"
# Ajustamos formato de fecha y filtramos el rango deseado

datos_trm <- datos_trm %>%
  mutate(
    fecha = as.Date(Fecha)  # Asumimos que hay una columna llamada "Fecha"
  ) %>%
  filter(fecha >= as.Date("2020-01-01") & fecha <= as.Date("2025-05-19")) %>%
  arrange(fecha)

# Agregamos columna de mes
datos_trm <- datos_trm %>%
  mutate(mes = floor_date(fecha, "month"))

# Calcular datos mensuales (último día de cada mes)
datos_mensuales <- datos_trm %>%
  group_by(mes) %>%
  summarize(trm = last(trm), .groups = "drop")

# Calcular retornos logarítmicos
datos_mensuales <- datos_mensuales %>%
  mutate(retorno = c(NA, diff(log(trm)))) %>%
  filter(!is.na(retorno))

# Estadísticas
media_retornos <- mean(datos_mensuales$retorno)
sd_retornos <- sd(datos_mensuales$retorno)

cat("Media de retornos mensuales:", round(media_retornos, 6), "\n")
## Media de retornos mensuales: 0.003228
cat("Desviación estándar mensual:", round(sd_retornos, 6), "\n")
## Desviación estándar mensual: 0.037291

La media mensual positiva (0.3228%) sugiere una tendencia leve a la apreciación del dólar frente al peso colombiano en el largo plazo. Desde un enfoque cuantitativo, esta media positiva en los retornos logarítmicos implica que el peso colombiano se ha devaluado frente al dólar a un ritmo promedio de 3.95% efectivo anual (1.003228¹² - 1). Aunque la tendencia es alcista, la alta desviación estándar evidencia un riesgo considerable de reversión o shocks cambiarios.

Este nivel de volatilidad mensual del 3.73% es elevado para una serie de tipo de cambio, lo que sugiere que cualquier exposición en USD debe evaluarse cuidadosamente bajo modelos de cobertura dinámica. Esta medida se convierte en el insumo clave para calibrar simulaciones Monte Carlo, VAR cambiario y pricing de derivados (Glasserman, 2004).

Esto es consistente con la naturaleza de los mercados emergentes, donde los tipos de cambio suelen ser más sensibles a factores internacionales como las tasas de interés de la FED, los precios del petróleo, y eventos políticos internos (Krugman & Obstfeld, 2018).

1.2.2 Gráficos de TRM y retornos logarítmicos

# Gráfico TRM mensual
ggplot(datos_mensuales, aes(x = mes, y = trm)) +
  geom_line(color = "blue") +
  labs(title = "Serie histórica de la TRM (mensual)",
       x = "Fecha", y = "TRM (COP/USD)") +
  theme_minimal()

# Gráfico de retornos
ggplot(datos_mensuales, aes(x = mes, y = retorno)) +
  geom_line(color = "red") +
  labs(title = "Retornos logarítmicos mensuales de la TRM",
       x = "Fecha", y = "Retorno logarítmico") +
  theme_minimal()

  • El gráfico de la TRM mensual muestra picos evidentes entre finales de 2022 y mediados de 2023, período en el cual la TRM superó los 4700 COP/USD. El gráfico de retornos logarítmicos permite detectar eventos extremos que pueden estar asociados con riesgo político (elecciones), decisiones de política monetaria (intervenciones del BanRep) o eventos globales (crisis sanitarias o geopolíticas).

La TRM tiende a reflejar de forma inmediata la percepción del riesgo país y las expectativas sobre la política fiscal y monetaria. (Banco de la República, 2023)

  • Los retornos logarítmicos mensuales muestran valores extremos en algunos meses, particularmente en 2020 y 2022, reflejando alta inestabilidad, posiblemente por efectos pospandemia y crisis externas.La serie de la TRM muestra oscilaciones estructurales que parecen seguir una media cambiante, lo que justifica aplicar modelos con saltos o rupturas estructurales (ej. Regímenes de Markov o Bai-Perron) para mejorar la modelación de la TRM en futuros análisis.

1.3. Simulación BMG

# Parámetros de entrada
mu <- media_retornos           
sigma <- sd_retornos          
dt <- 1/12                    # Simulación mensual (12 meses por año)
n_meses <- 120                # 10 años
n_sim <- 1000                 # Número de simulaciones
trm_inicial <- tail(datos_mensuales$trm, 1)  # TRM del 19 de mayo de 2025

# Semilla aleatoria diferente cada vez
set.seed(sample(1:100000, 1))

# Inicializar matriz
simulaciones <- matrix(NA, nrow = n_meses + 1, ncol = n_sim)
simulaciones[1, ] <- trm_inicial

# Simulación MGB
for (i in 2:(n_meses + 1)) {
  Z <- rnorm(n_sim)
  simulaciones[i, ] <- simulaciones[i - 1, ] * exp((mu - 0.5 * sigma^2) * dt + sigma * sqrt(dt) * Z)
}

# Preparar para visualización
tiempo <- 0:n_meses
sim_df <- data.frame(tiempo = tiempo)

# Agregar las primeras  simulaciones y promedio
for (i in 1:5) {
  sim_df[[paste0("sim_", i)]] <- simulaciones[, i]
}
sim_df$promedio <- rowMeans(simulaciones)

# Reorganizar a formato largo para graficar
sim_largo <- pivot_longer(sim_df, cols = -tiempo, names_to = "simulacion", values_to = "valor")

# Valor máximo
valor_maximo_simulado <- max(simulaciones)

# Graficar
ggplot(sim_largo, aes(x = tiempo, y = valor, color = simulacion)) +
  geom_line() +
  labs(title = "Simulación mensual de la TRM a 10 años",
       x = "Meses",
       y = "TRM (COP/USD)") +
  theme_minimal()

print(sim_df)
##     tiempo    sim_1    sim_2    sim_3    sim_4    sim_5 promedio
## 1        0 4194.280 4194.280 4194.280 4194.280 4194.280 4194.280
## 2        1 4157.852 4153.005 4254.992 4163.261 4121.936 4197.466
## 3        2 4074.195 4132.846 4234.559 4143.077 4153.775 4197.942
## 4        3 4048.732 4141.043 4187.352 4134.040 4139.644 4197.136
## 5        4 4053.721 4188.120 4157.538 4185.912 4147.176 4197.569
## 6        5 4062.827 4188.113 4165.927 4187.101 4238.442 4195.553
## 7        6 4122.488 4235.378 4179.072 4126.350 4227.743 4197.103
## 8        7 4101.840 4325.155 4139.311 4133.320 4218.484 4196.973
## 9        8 4199.414 4400.011 4093.990 4198.933 4199.183 4199.212
## 10       9 4178.070 4401.410 4003.083 4170.037 4166.298 4202.083
## 11      10 4165.534 4456.770 4052.847 4097.548 4084.071 4205.513
## 12      11 4206.588 4499.593 3996.500 4075.729 4102.675 4206.265
## 13      12 4253.377 4442.945 3937.821 4023.948 4162.924 4206.472
## 14      13 4246.099 4544.821 3916.386 3990.952 4167.558 4208.638
## 15      14 4266.746 4544.554 3840.970 4002.172 4214.881 4208.562
## 16      15 4288.677 4567.798 3934.456 4006.470 4262.630 4207.934
## 17      16 4281.112 4562.264 3902.510 3971.527 4271.958 4208.742
## 18      17 4309.835 4519.700 4011.191 4003.115 4270.946 4209.287
## 19      18 4389.188 4510.115 3997.490 4038.944 4242.412 4206.175
## 20      19 4428.609 4570.249 4057.112 4025.034 4270.409 4208.577
## 21      20 4362.343 4605.317 4060.434 4051.491 4289.931 4209.792
## 22      21 4352.159 4608.755 4006.707 4096.810 4290.373 4210.566
## 23      22 4349.391 4587.316 3988.107 4047.601 4253.297 4210.458
## 24      23 4375.561 4606.376 3963.105 4117.157 4223.227 4209.823
## 25      24 4351.008 4660.827 3926.880 4193.477 4233.855 4212.512
## 26      25 4354.902 4629.690 3890.636 4206.884 4202.432 4213.478
## 27      26 4348.502 4579.690 3862.396 4231.055 4176.809 4213.247
## 28      27 4332.011 4592.894 3879.014 4232.507 4174.137 4215.343
## 29      28 4337.081 4540.000 3926.022 4257.947 4192.688 4218.971
## 30      29 4394.932 4577.589 3954.798 4248.813 4224.020 4222.663
## 31      30 4411.626 4566.040 3934.082 4238.265 4301.101 4226.410
## 32      31 4474.375 4543.800 3913.746 4256.409 4245.564 4225.177
## 33      32 4440.574 4578.836 3889.532 4193.242 4242.559 4227.768
## 34      33 4411.059 4548.670 3889.589 4256.745 4260.051 4226.470
## 35      34 4378.082 4487.251 3776.362 4333.759 4246.874 4226.267
## 36      35 4417.316 4523.050 3761.976 4365.224 4275.362 4230.754
## 37      36 4367.449 4559.296 3774.687 4347.878 4292.334 4231.933
## 38      37 4436.411 4559.816 3786.803 4335.657 4270.816 4234.542
## 39      38 4421.316 4539.390 3829.337 4233.678 4343.527 4234.778
## 40      39 4430.555 4541.879 3792.291 4328.988 4377.532 4237.610
## 41      40 4525.335 4559.448 3780.545 4314.902 4394.551 4239.882
## 42      41 4452.680 4506.003 3809.597 4326.296 4354.879 4241.087
## 43      42 4408.812 4540.557 3785.234 4210.699 4328.860 4242.384
## 44      43 4431.446 4473.782 3829.975 4171.876 4321.207 4244.352
## 45      44 4364.478 4500.756 3830.459 4186.280 4274.894 4245.267
## 46      45 4363.249 4570.009 3854.924 4169.642 4288.262 4246.284
## 47      46 4319.055 4520.889 3913.693 4109.029 4320.875 4246.223
## 48      47 4347.216 4536.434 3862.369 4125.170 4313.592 4247.322
## 49      48 4416.862 4567.777 3806.896 4130.415 4274.285 4248.800
## 50      49 4412.161 4518.907 3825.895 4243.780 4346.983 4250.262
## 51      50 4357.917 4602.904 3819.817 4182.051 4424.739 4251.378
## 52      51 4296.771 4594.190 3751.357 4166.888 4495.093 4251.207
## 53      52 4327.877 4588.697 3694.282 4117.315 4523.711 4252.179
## 54      53 4232.492 4584.503 3704.394 4140.421 4505.752 4254.597
## 55      54 4191.437 4692.070 3665.023 4122.037 4467.256 4256.503
## 56      55 4135.635 4748.070 3607.764 4186.472 4506.422 4256.114
## 57      56 4180.481 4791.462 3642.738 4235.911 4519.080 4258.038
## 58      57 4114.827 4784.966 3617.436 4214.976 4569.863 4259.792
## 59      58 4116.348 4754.835 3624.440 4123.560 4510.707 4260.081
## 60      59 4102.091 4723.856 3571.294 4132.825 4574.576 4257.656
## 61      60 4054.162 4834.231 3592.514 4107.316 4556.452 4258.683
## 62      61 4093.611 4861.840 3528.031 4025.500 4560.334 4260.615
## 63      62 4122.386 4809.641 3571.070 4060.273 4488.260 4261.006
## 64      63 4051.843 4834.141 3550.922 4121.233 4446.103 4263.823
## 65      64 4104.708 4907.407 3552.573 4165.538 4404.684 4264.730
## 66      65 4164.982 4936.774 3513.668 4190.478 4381.360 4265.635
## 67      66 4187.159 4835.811 3506.522 4168.785 4392.048 4264.871
## 68      67 4241.464 4821.122 3533.665 4173.243 4460.490 4267.715
## 69      68 4262.332 4909.902 3496.805 4188.230 4463.589 4269.955
## 70      69 4230.668 4951.508 3494.139 4117.780 4417.772 4268.367
## 71      70 4279.616 4958.309 3452.118 4115.539 4374.245 4267.630
## 72      71 4255.682 4922.531 3466.137 4190.528 4381.617 4268.540
## 73      72 4283.136 4873.186 3503.840 4295.552 4313.703 4271.763
## 74      73 4177.766 4828.049 3610.174 4282.729 4213.699 4275.205
## 75      74 4228.284 4814.332 3581.292 4332.211 4190.414 4277.696
## 76      75 4179.587 4825.977 3532.055 4203.881 4228.591 4279.914
## 77      76 4157.388 4752.074 3459.622 4213.577 4222.296 4280.000
## 78      77 4130.490 4754.552 3440.068 4291.992 4263.685 4280.926
## 79      78 4088.922 4684.601 3421.319 4212.455 4271.105 4283.584
## 80      79 4065.228 4657.845 3449.838 4223.633 4288.718 4284.890
## 81      80 3987.469 4608.916 3495.753 4286.288 4247.405 4286.884
## 82      81 4046.805 4645.329 3476.243 4321.107 4220.214 4289.100
## 83      82 4068.839 4661.917 3399.646 4339.619 4294.480 4288.151
## 84      83 4061.059 4641.557 3410.185 4374.966 4303.548 4290.098
## 85      84 4054.446 4768.564 3452.578 4397.546 4402.552 4287.423
## 86      85 4000.683 4668.162 3464.945 4397.171 4401.415 4289.497
## 87      86 3947.092 4643.789 3438.882 4255.859 4416.995 4290.941
## 88      87 3959.100 4691.729 3407.464 4246.832 4364.116 4290.290
## 89      88 3978.333 4639.918 3413.027 4317.567 4342.488 4290.990
## 90      89 4032.426 4704.423 3455.791 4332.461 4308.737 4292.919
## 91      90 4035.396 4707.898 3524.252 4365.730 4253.254 4291.897
## 92      91 3987.171 4727.708 3544.399 4356.033 4240.084 4292.960
## 93      92 4017.515 4705.721 3565.120 4438.247 4254.525 4293.064
## 94      93 4042.265 4671.314 3600.477 4392.294 4253.152 4293.850
## 95      94 4019.387 4711.088 3623.899 4413.639 4328.410 4295.370
## 96      95 3950.722 4843.043 3578.756 4446.731 4303.209 4296.183
## 97      96 4023.604 4827.907 3588.172 4448.623 4318.436 4296.780
## 98      97 3981.463 4808.066 3586.591 4486.681 4307.020 4296.420
## 99      98 3951.353 4792.650 3621.820 4503.644 4265.351 4298.408
## 100     99 3975.491 4849.502 3613.437 4449.388 4282.501 4301.801
## 101    100 3992.333 4907.109 3659.292 4460.371 4288.586 4303.346
## 102    101 3985.674 4927.942 3679.018 4383.174 4297.695 4303.234
## 103    102 4000.962 4915.412 3713.233 4371.870 4269.469 4304.420
## 104    103 3924.416 4912.095 3689.833 4337.830 4273.914 4305.982
## 105    104 3900.501 4998.823 3710.750 4348.224 4221.395 4306.749
## 106    105 3867.320 4963.045 3660.491 4369.316 4285.962 4310.897
## 107    106 3856.490 5077.161 3693.163 4380.285 4299.016 4312.590
## 108    107 3907.022 5077.570 3637.710 4405.360 4295.269 4311.059
## 109    108 3907.476 5106.164 3666.370 4483.275 4241.290 4313.262
## 110    109 3936.685 5111.851 3566.817 4434.977 4373.342 4311.562
## 111    110 3927.129 5115.165 3516.934 4435.643 4498.084 4310.680
## 112    111 3945.676 5154.788 3476.306 4402.427 4546.403 4311.691
## 113    112 3930.836 5149.003 3534.346 4435.098 4490.837 4311.061
## 114    113 3942.619 5108.855 3535.919 4436.387 4466.509 4309.310
## 115    114 3969.008 5111.550 3588.805 4447.493 4535.329 4309.813
## 116    115 4021.410 5132.173 3579.833 4536.024 4508.865 4308.662
## 117    116 4067.463 5041.575 3543.275 4623.479 4466.156 4310.161
## 118    117 4034.576 5026.945 3553.467 4659.446 4487.525 4312.724
## 119    118 4034.250 5003.368 3470.251 4606.515 4427.127 4311.444
## 120    119 3976.827 4994.261 3451.764 4582.607 4423.497 4311.191
## 121    120 3933.090 5022.010 3396.919 4554.400 4458.286 4313.460

El Movimiento Geométrico Browniano (MGB) asume independencia temporal y estacionariedad de los parámetros (μ, σ), lo cual puede subestimar el riesgo si existen ciclos económicos o intervenciones discrecionales del banco central.

No obstante, como ejercicio de base, la simulación permite construir una distribución empírica del tipo de cambio futuro, útil para estimar:

  • Cuotas futuras esperadas
  • Valor presente esperado del pasivo
  • Valor en Riesgo (VaR) cambiario

Además, permite aplicar estrategias de cobertura adaptativa, donde se ajusta el portafolio mes a mes según la nueva TRM simulada.

Glasserman (2004), en el capítulo 3 “Stochastic Processes: The Geometric Brownian Motion Model”, desarrolla detalladamente el uso del MGB en finanzas y explica que su aplicabilidad es más realista en horizontes de corto plazo y con activos sin tendencia a saltos discretos, lo cual debe ser considerado en modelos de TRM.

1.4. Simulación Crédito de la Maquinaria en USD

# Parámetros iniciales
monto_cop <- 300000000           # 300 millones de pesos
cuota_inicial_porcentaje <- 0.10 # 10% pago inicial

# TRM actual (último dato mensual)
trm_actual <- tail(datos_mensuales$trm, 1)

# Convertir monto a dólares
monto_usd <- monto_cop / trm_actual

# Cuota inicial en dólares
cuota_inicial_usd <- monto_usd * cuota_inicial_porcentaje

# Monto a financiar en dólares
monto_financiar_usd <- monto_usd - cuota_inicial_usd

# Tasa efectiva anual extranjera
tasa_efectiva_anual <- 0.0599

# Convertir tasa efectiva anual a tasa nominal mensual (sistema francés usualmente usa tasa nominal)
# Fórmula tasa nominal mensual desde tasa efectiva anual:
tasa_mensual_extranjera <- (1 + tasa_efectiva_anual)^(1/12) - 1

# Plazo en meses
plazo_meses <- 10 * 12  # 10 años

# Cuota fija mensual (Sistema francés)
cuota_mensual_usd <- monto_financiar_usd * tasa_mensual_extranjera * (1 + tasa_mensual_extranjera)^plazo_meses /
  ((1 + tasa_mensual_extranjera)^plazo_meses - 1)

# Inicializar tabla de amortización
tabla_amortizacion_usd <- data.frame(
  mes = 1:plazo_meses,
  cuota = rep(cuota_mensual_usd, plazo_meses),
  saldo_inicial = numeric(plazo_meses),
  interes = numeric(plazo_meses),
  capital = numeric(plazo_meses),
  saldo_final = numeric(plazo_meses)
)

# Saldo inicial para el primer mes es el monto a financiar
tabla_amortizacion_usd$saldo_inicial[1] <- monto_financiar_usd

# Calcular amortización mes a mes
for(i in 1:plazo_meses) {
  # Intereses del mes actual
  tabla_amortizacion_usd$interes[i] <- tabla_amortizacion_usd$saldo_inicial[i] * tasa_mensual_extranjera
  
  # Capital amortizado ese mes
  tabla_amortizacion_usd$capital[i] <- tabla_amortizacion_usd$cuota[i] - tabla_amortizacion_usd$interes[i]
  
  # Saldo final después del pago
  tabla_amortizacion_usd$saldo_final[i] <- tabla_amortizacion_usd$saldo_inicial[i] - tabla_amortizacion_usd$capital[i]
  
  # Para el siguiente mes, saldo inicial es el saldo final del mes anterior (excepto el último mes)
  if(i < plazo_meses) {
    tabla_amortizacion_usd$saldo_inicial[i + 1] <- tabla_amortizacion_usd$saldo_final[i]
  }
}

options(scipen = 999)

# Mostrar primeros meses de la tabla de amortización
head(tabla_amortizacion_usd)
##   mes    cuota saldo_inicial  interes  capital saldo_final
## 1   1 709.2442      64373.38 312.8321 396.4121    63976.97
## 2   2 709.2442      63976.97 310.9057 398.3385    63578.63
## 3   3 709.2442      63578.63 308.9699 400.2743    63178.36
## 4   4 709.2442      63178.36 307.0247 402.2195    62776.14
## 5   5 709.2442      62776.14 305.0701 404.1741    62371.97
## 6   6 709.2442      62371.97 303.1059 406.1383    61965.83
# Resumen
cat("Monto inicial en dólares: ", round(monto_usd, 2), "\n")
## Monto inicial en dólares:  71525.98
cat("Cuota inicial (10%): ", round(cuota_inicial_usd, 2), "\n")
## Cuota inicial (10%):  7152.6
cat("Monto a financiar: ", round(monto_financiar_usd, 2), "\n")
## Monto a financiar:  64373.38
cat("Cuota mensual fija: ", round(cuota_mensual_usd, 2), "\n")
## Cuota mensual fija:  709.24

El sistema francés implica pagos mensuales constantes donde la proporción de intereses disminuye con el tiempo.

1.5. Simulación Crédito de la Maquinaria en COP

# ---- 1. Ajustes iniciales ----
# Valor total del bien en COP
monto_total_cop <- monto_cop  # Este es el valor completo del crédito (100%)

# Cálculo del pago inicial y monto financiado
pago_inicial <- 0.10 * monto_total_cop
monto_financiado <- monto_total_cop - pago_inicial  # 90% financiado


# ---- Calcular cuotas en COP para cada simulación ----
cuotas_cop <- matrix(0, nrow = plazo_meses, ncol = n_sim)
 
for(i in 1:n_sim) {
  cuotas_cop[, i] <- tabla_amortizacion_usd$cuota * simulaciones[2:(plazo_meses + 1), i]
}
 
# Estadísticas de cuotas COP a lo largo del tiempo
cuotas_cop_promedio <- rowMeans(cuotas_cop)
cuotas_cop_min <- apply(cuotas_cop, 1, min)
cuotas_cop_max <- apply(cuotas_cop, 1, max)


# ---- 2. Construir tabla de amortización en COP con cuotas promedio simuladas ----

tabla_amortizacion_cop <- data.frame(
  mes = 1:plazo_meses,
  cuota_cop = cuotas_cop_promedio,
  saldo_inicial_cop = numeric(plazo_meses),
  interes_cop = numeric(plazo_meses),
  capital_cop = numeric(plazo_meses),
  saldo_final_cop = numeric(plazo_meses)
)

# Primer mes: saldo inicial es el monto financiado
tabla_amortizacion_cop$saldo_inicial_cop[1] <- monto_financiado

# Construir tabla de amortización iterativamente
for(i in 1:plazo_meses) {
  saldo_inicial <- tabla_amortizacion_cop$saldo_inicial_cop[i]
  
  # Cálculo del interés y capital amortizado
  interes <- saldo_inicial * tasa_mensual_extranjera
  capital <- tabla_amortizacion_cop$cuota_cop[i] - interes
  
  # Saldo final del mes
  saldo_final <- saldo_inicial - capital
  
  # Guardar valores
  tabla_amortizacion_cop$interes_cop[i] <- interes
  tabla_amortizacion_cop$capital_cop[i] <- capital
  tabla_amortizacion_cop$saldo_final_cop[i] <- saldo_final
  
  # Asignar saldo final como saldo inicial del siguiente mes
  if (i < plazo_meses) {
    tabla_amortizacion_cop$saldo_inicial_cop[i + 1] <- saldo_final
  }
}

# ---- 3. Mostrar resultados finales ----

# Cuotas simuladas
cuotas_resumen <- data.frame(
  mes = 1:plazo_meses,
  cuota_usd = tabla_amortizacion_usd$cuota,
  cuota_cop_promedio = cuotas_cop_promedio,
  cuota_cop_min = cuotas_cop_min,
  cuota_cop_max = cuotas_cop_max
)

# Gráfico de evolución de cuotas en COP
library(ggplot2)
ggplot(cuotas_resumen, aes(x = mes)) +
  geom_line(aes(y = cuota_cop_promedio), color = "blue", size = 1) +
  geom_ribbon(aes(ymin = cuota_cop_min, ymax = cuota_cop_max), alpha = 0.2, fill = "lightblue") +
  labs(title = "Evolución simulada de cuotas mensuales en COP",
       x = "Mes",
       y = "Cuota mensual (COP)") +
  theme_minimal()
## 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.

# ---- 4. Estadísticas y validación ----

media_cuotas_cop <- mean(cuotas_cop_promedio)
sd_cuotas_cop <- sd(cuotas_cop_promedio)
total_pagado_usd <- sum(tabla_amortizacion_usd$cuota)
total_pagado_cop_promedio <- sum(cuotas_cop_promedio)
saldo_final_total <- tail(tabla_amortizacion_cop$saldo_final_cop, 1)

# Resultados
cat("Cuota mensual promedio (COP):", round(media_cuotas_cop, 2), "\n")
## Cuota mensual promedio (COP): 3020654
cat("Desviación estándar mensual de cuotas (COP):", round(sd_cuotas_cop, 2), "\n")
## Desviación estándar mensual de cuotas (COP): 27004.98
cat("Total pagado en USD:", round(total_pagado_usd, 2), "\n")
## Total pagado en USD: 85109.31
cat("Total pagado promedio en COP:", round(total_pagado_cop_promedio, 2), "\n")
## Total pagado promedio en COP: 362478438
cat("Pago inicial (10% del valor total):", round(pago_inicial, 2), "\n")
## Pago inicial (10% del valor total): 30000000
# Mostrar primeros meses de tabla de amortización
print(head(tabla_amortizacion_cop, 10))
##    mes cuota_cop saldo_inicial_cop interes_cop capital_cop saldo_final_cop
## 1    1   2977029         270000000     1312106     1664923       268335077
## 2    2   2977366         268335077     1304015     1673352       266661725
## 3    3   2976794         266661725     1295883     1680912       264980814
## 4    4   2977102         264980814     1287714     1689388       263291426
## 5    5   2975671         263291426     1279504     1696167       261595259
## 6    6   2976771         261595259     1271261     1705509       259889749
## 7    7   2976679         259889749     1262973     1713706       258176044
## 8    8   2978267         258176044     1254645     1723621       256452423
## 9    9   2980303         256452423     1246269     1734034       254718389
## 10  10   2982735         254718389     1237842     1744893       252973495

Análisis de la Estructura del Financiamiento

- Monto del préstamo: COP $270,000,000 (equivalente a aproximadamente USD64,373.3847 al tipo de cambio de $4194.28 COP/USD)

- Pago inicial: COP $30,000,000 (10% del valor total), lo que indica que el valor total de la maquinaria es de COP $300,000,000

- Costo total endeudamiento: COP ~ $362,871,692

- Intereses totales: COP ~ $62,871,692 Esto representa un costo financiero significativo pero razonable para el financiamiento de maquinaria pesada, la maquinaria debe generar una rentabilidad superior para justificar la inversión.

- Estabilidad de las Cuotas La desviación estándar de COP $30,811.27 es relativamente baja comparada con la cuota promedio de COP ~ $3,023,931, representando solo el 1.02% de variación.

- Riesgo Cambiario A pesar de que la cuota en USD es fija, en COP los pagos futuros están expuestos completamente a la volatilidad del tipo de cambio:

  • Si el peso se devalúa, el valor real de la maquinaria aumenta en pesos
  • Las cuotas fijas en pesos se vuelven más baratas en términos reales
  • Esto puede ser ventajoso si hay expectativas de devaluación

De acuerdo al análisis anterior, es conveniente considerar la disminución del riesgo por medio de Instrumentos de Derivados Financieros, que permita cubrir la exposición del riesgo cambiario.

La cobertura cambiaria mediante futuros o forwards puede mitigar el impacto del riesgo de TRM sobre obligaciones financieras pactadas en dólares (CFA Institute, 2020).

Parte 2 - Proceso de Futuro

2.1 Información de BVC Futuro

Futuro escogido TRMM25F Detalles del contrato Nemotécnico: TRMM25F Subyacente: TRM Último día negociación: 2025/06/11 Fecha de vencimiento: 2025/06/11 Tamaño del contrato:50,000 USD Tick de precio: 0.01 Tipo de liquidación: Financiera Compensación y liquidación: CRCC Garantía: Definida por CRCC Estado: Activo (Bolsa de Valores de Colombia, 2025)

2.2 Simulación BMG

# === 1. Cargar base de datos FTRM.xlsx ===
# Asegúrate que el archivo esté en tu directorio de trabajo o usa file.choose()

# Permite seleccionar manualmente el archivo .xls
archivo_ftrm <- file.choose()

# Cargar datos desde la primera hoja
ftrm_data <- read_excel(archivo_ftrm, sheet = 1)

# Verificar nombres reales de columnas
names(ftrm_data)
## [1] "Fecha"    "Contrato" "Precio"
# === 2. Preprocesamiento de fechas y orden ===
ftrm_data <- ftrm_data %>%
  mutate(Fecha = as.Date(Fecha)) %>%
  arrange(Fecha)

# === 3. Filtrar último precio disponible de cada mes ===
ftrm_mensual <- ftrm_data %>%
  group_by(anio_mes = format(Fecha, "%Y-%m")) %>%
  filter(Fecha == max(Fecha)) %>%
  ungroup()

# === 4. Calcular retornos logarítmicos y estadísticos mensuales ===
ftrm_mensual <- ftrm_mensual %>%
  mutate(retorno_log = log(Precio / lag(Precio))) %>%
  na.omit()

# Cálculo de media y desviación estándar mensual
mu_futuro <- mean(ftrm_mensual$retorno_log, na.rm = TRUE)
sigma_futuro <- sd(ftrm_mensual$retorno_log, na.rm = TRUE)

# Mostrar los valores para verificación
cat("Media mensual (mu):", round(mu_futuro, 6), "\n")
## Media mensual (mu): -0.00237
cat("Desviación estándar mensual (sigma):", round(sigma_futuro, 6), "\n")
## Desviación estándar mensual (sigma): 0.027422
# === 5. Cálculo del precio teórico del futuro para el primer mes ===
S0 <- tail(ftrm_mensual$Precio, 1)  # Último precio spot disponible
rn <- 0.08726 + 0.0810             # 8.726% (IBR) + 8.10%
re <- 0.0599                       # Tasa extranjera
t_T <- 1/12                        # Un mes

F_teorico <- S0 * (1 + rn)^t_T / (1 + re)^t_T

# === 6. Simulación BMG mensual por 10 años ===
n_sim <- 1000
n_meses <- 120
set.seed(123)  # Reproducibilidad

sim_futuro <- matrix(NA, nrow = n_meses, ncol = n_sim)
sim_futuro[1, ] <- F_teorico  # Valor inicial

for (i in 2:n_meses) {
  Z <- rnorm(n_sim, 0, 1)
  sim_futuro[i, ] <- sim_futuro[i - 1, ] * exp((mu_futuro - 0.5 * sigma_futuro^2) + sigma_futuro * Z)
}

# === 7. Convertir simulaciones a data frame ===
tiempo <- 1:n_meses
sim_df <- data.frame(tiempo = tiempo)

# Incluir 5 simulaciones para graficar
for (i in 1:5) {
  sim_df[[paste0("sim_", i)]] <- sim_futuro[, i]
}

# Añadir promedio de las simulaciones
sim_df$promedio <- rowMeans(sim_futuro)

# === 8. Filtrar años 6 a 10 (meses 61 a 120) ===
sim_df_long <- pivot_longer(sim_df, cols = -tiempo,
                            names_to = "simulacion", values_to = "valor")

sim_df_long_filtrado <- sim_df_long %>%
  filter(tiempo >= 61 & tiempo <= 120)

# === 9. Visualización ===
ggplot(sim_df_long_filtrado, aes(x = tiempo, y = valor, color = simulacion)) +
  geom_line(alpha = 0.7) +
  labs(title = "Simulación BMG del Futuro TRM (Años 6 a 10)",
       subtitle = paste("Simulación mensual desde precio teórico inicial (", round(F_teorico, 2), " COP/USD)", sep = ""),
       x = "Mes (desde hoy)",
       y = "Precio Futuro (COP/USD)") +
  theme_minimal() +
  scale_color_viridis_d()

2.3 Criterios de exposición total, margen inicial, margen de mantenimiento

# Definición de parámetros del contrato futuro TRM
valor_contrato <- 50000  # Valor típico del contrato futuro TRM en USD
precio_futuro_actual <- F_teorico  # Precio futuro teórico en COP/USD
valor_nocional <- valor_contrato * precio_futuro_actual  # Valor nocional en COP

# Porcentajes oficiales según la BVC
porcentaje_margen_inicial <- 0.08  # 8%
porcentaje_margen_mantenimiento <- 0.06  # 6%
porcentaje_exposicion_total <- 1 # 100%

# Cálculo de márgenes y exposición total
margen_inicial <- valor_nocional * porcentaje_margen_inicial
margen_mantenimiento <- valor_nocional * porcentaje_margen_mantenimiento
exposicion_total <- valor_nocional * porcentaje_exposicion_total

# Mostrar los resultados
cat("Valor del contrato (USD):", valor_contrato, "\n")
## Valor del contrato (USD): 50000
cat("Precio futuro actual (COP/USD):", round(precio_futuro_actual, 2), "\n")
## Precio futuro actual (COP/USD): 4216.59
cat("Valor nocional del contrato (COP):", round(valor_nocional, 2), "\n")
## Valor nocional del contrato (COP): 210829275
cat("Margen inicial (COP):", round(margen_inicial, 2), "\n")
## Margen inicial (COP): 16866342
cat("Margen de mantenimiento (COP):", round(margen_mantenimiento, 2), "\n")
## Margen de mantenimiento (COP): 12649757
cat("Exposición total (COP):", round(exposicion_total, 2), "\n")
## Exposición total (COP): 210829275

El uso de márgenes permite al operador controlar un monto grande (COP 210 millones) con un desembolso inicial relativamente pequeño (COP 16.8 millones), lo que implica un alto nivel de apalancamiento.Es importante tener liquidez para responder a llamados de margen. También, definir umbrales de pérdida o ganancia para cerrar la posición anticipadamente ayudar a disminuir posibles perdidas.

2.4 Flujo de Caja de Margen Y Rollover

# Flujo de Caja de Margen con Rollover y Cambio de Posición (Años 7 a 10)

# Determinar el valor a cubrir con futuros (70% del valor de la maquinaria)
valor_maquinaria_cop <- 300000000  # 300 millones de pesos (del código previo)
porcentaje_cobertura <- 0.7
valor_a_cubrir_cop <- valor_maquinaria_cop * porcentaje_cobertura

# valor_nocional está definido como valor_contrato * precio_futuro_actual
cat("Usando valor nocional de:", round(valor_nocional, 2), "COP\n")
## Usando valor nocional de: 210829275 COP
# Número de contratos necesarios 
n_contratos <- ceiling(valor_a_cubrir_cop / valor_nocional)
cat("Número de contratos necesarios:", n_contratos, "\n")
## Número de contratos necesarios: 1
# Crear estructura para el flujo de caja de margen
# Consideramos los últimos 4 años (meses 73 a 120)
meses_cobertura <- 73:120
n_meses_cobertura <- length(meses_cobertura)

# Matriz para almacenar el flujo de caja de margen
flujo_margen <- matrix(0, nrow = n_meses_cobertura, ncol = n_sim)

# Simulación de precios spot de la TRM para los últimos 4 años
spot_prices <- simulaciones[meses_cobertura, ]  # matriz [48 x n_sim]

# Precios futuros simulados para los últimos 4 años
# Ajustamos los índices para que coincidan con los años 7-10
future_prices <- sim_futuro[(meses_cobertura - 72), ]  # índices 1-48 en sim_futuro

# Calcular el flujo de caja de margen para cada mes y simulación
for (j in 1:n_sim) {
  # Posición inicial (puede ser larga o corta)
  # Determinamos posición inicial basada en primera comparación spot vs futuro
  posicion <- ifelse(spot_prices[1, j] > future_prices[1, j], -1, 1)
  
  # Seguimiento de posición para esta simulación (para diagnóstico)
  posiciones <- numeric(n_meses_cobertura)
  posiciones[1] <- posicion
  
  for (i in 1:n_meses_cobertura) {
    mes_actual <- i
    
    # Si es inicio de trimestre (cada 3 meses), hacemos rollover
    if (mes_actual %% 3 == 1 && mes_actual > 1) {
      # Liquidación del contrato anterior
      precio_anterior <- future_prices[mes_actual - 1, j]
      precio_actual <- future_prices[mes_actual, j]
      
      # Ganancia/pérdida por liquidación
      ganancia_perdida <- posicion * (precio_actual - precio_anterior) * valor_contrato * n_contratos
      flujo_margen[mes_actual, j] <- ganancia_perdida
      
      # Cambio de posición basado en expectativa (comparación spot vs futuro)
      if (spot_prices[mes_actual, j] > future_prices[mes_actual, j]) {
        posicion <- -1  # Corto: si esperamos caída del dólar (backwardation)
      } else {
        posicion <- 1   # Largo: si esperamos subida del dólar (contango)
      }
      posiciones[mes_actual] <- posicion
      
    } else if (mes_actual > 1) {
      # Mark-to-Market para meses intermedios
      precio_anterior <- future_prices[mes_actual - 1, j]
      precio_actual <- future_prices[mes_actual, j]
      ganancia_perdida <- posicion * (precio_actual - precio_anterior) * valor_contrato * n_contratos
      flujo_margen[mes_actual, j] <- ganancia_perdida
      posiciones[mes_actual] <- posicion
    } else {
      # En el mes 1, registramos la posición inicial pero no hay flujo
      posiciones[mes_actual] <- posicion
    }
  }
  
  # Si quieres visualizar el cambio de posiciones durante la simulación (opcional)
  if (j == 1) {
    cat("Cambios de posición en la primera simulación:\n")
    for (i in seq(1, n_meses_cobertura, by = 3)) {
      cat("Mes", meses_cobertura[i], ": Posición =", posiciones[i], 
          "(", ifelse(posiciones[i] == 1, "Larga", "Corta"), ")\n")
    }
  }
}
## Cambios de posición en la primera simulación:
## Mes 73 : Posición = -1 ( Corta )
## Mes 76 : Posición = -1 ( Corta )
## Mes 79 : Posición = -1 ( Corta )
## Mes 82 : Posición = -1 ( Corta )
## Mes 85 : Posición = 1 ( Larga )
## Mes 88 : Posición = -1 ( Corta )
## Mes 91 : Posición = -1 ( Corta )
## Mes 94 : Posición = -1 ( Corta )
## Mes 97 : Posición = -1 ( Corta )
## Mes 100 : Posición = -1 ( Corta )
## Mes 103 : Posición = -1 ( Corta )
## Mes 106 : Posición = -1 ( Corta )
## Mes 109 : Posición = -1 ( Corta )
## Mes 112 : Posición = -1 ( Corta )
## Mes 115 : Posición = -1 ( Corta )
## Mes 118 : Posición = -1 ( Corta )
# Análisis de flujos de margen
# Promedio del flujo mensual entre simulaciones
flujo_margen_promedio <- rowMeans(flujo_margen)

# Flujo acumulado
flujo_margen_acumulado <- cumsum(flujo_margen_promedio)

# Estadísticas de flujo
media_flujo <- mean(flujo_margen_promedio)
sd_flujo <- sd(flujo_margen_promedio)
total_flujo <- sum(flujo_margen_promedio)

cat("\nEstadísticas del flujo de margen:\n")
## 
## Estadísticas del flujo de margen:
cat("Media mensual:", formatC(media_flujo, format = "f", big.mark = ",", digits = 0), "COP\n")
## Media mensual: 105,806 COP
cat("Desviación estándar:", formatC(sd_flujo, format = "f", big.mark = ",", digits = 0), "COP\n")
## Desviación estándar: 191,579 COP
cat("Total acumulado:", formatC(total_flujo, format = "f", big.mark = ",", digits = 0), "COP\n")
## Total acumulado: 5,078,693 COP
# Crear dataframe para visualización
flujo_df <- data.frame(
  mes = meses_cobertura,
  flujo_mensual = flujo_margen_promedio,
  flujo_acumulado = flujo_margen_acumulado
)


# Estimación de márgenes requeridos


# Utilizando los parámetros de margen ya definidos
margen_inicial_total <- margen_inicial * n_contratos
cat("\nMargen inicial total requerido:", formatC(margen_inicial_total, format = "f", big.mark = ",", digits = 0), "COP\n")
## 
## Margen inicial total requerido: 16,866,342 COP
# Análisis de llamadas a margen (cuándo caemos por debajo del margen de mantenimiento)
llamadas_margen <- c()
for (j in 1:n_sim) {
  flujo_acum_sim <- cumsum(flujo_margen[, j])
  for (i in 2:n_meses_cobertura) {
    # Si el flujo acumulado es muy negativo, podría generar llamada a margen
    if (flujo_acum_sim[i] < -margen_inicial_total * 0.25) {
      llamadas_margen <- c(llamadas_margen, meses_cobertura[i])
    }
  }
}

# Resumen de llamadas a margen
if (length(llamadas_margen) > 0) {
  freq_llamadas <- table(llamadas_margen)
  cat("\nProbabilidad de llamadas a margen por mes:\n")
  for (mes in names(sort(freq_llamadas, decreasing = TRUE)[1:min(5, length(freq_llamadas))])) {
    prob <- freq_llamadas[mes] / n_sim * 100
    cat("Mes", mes, ": ", round(prob, 2), "%\n")
  }
} else {
  cat("\nNo se detectaron llamadas a margen en las simulaciones.\n")
}
## 
## Probabilidad de llamadas a margen por mes:
## Mes 104 :  44.6 %
## Mes 107 :  44.2 %
## Mes 106 :  44.1 %
## Mes 111 :  44 %
## Mes 105 :  43.8 %
# Medición del riesgo del flujo de margen


# Matriz para almacenar el flujo de caja acumulado para cada simulación
flujo_acum_sim <- matrix(0, nrow = n_meses_cobertura, ncol = n_sim)

for (j in 1:n_sim) {
  flujo_acum_sim[, j] <- cumsum(flujo_margen[, j])
}

# Calcular VaR mensual al 95% de confianza
var_95_mensual <- apply(flujo_margen, 1, function(x) quantile(x, 0.05))

# VaR del flujo acumulado total
flujo_acumulado_total <- flujo_acum_sim[n_meses_cobertura, ]
var_95_total <- quantile(flujo_acumulado_total, 0.05)
cvar_95_total <- mean(flujo_acumulado_total[flujo_acumulado_total <= var_95_total])

cat("\nRiesgo del flujo de margen acumulado:\n")
## 
## Riesgo del flujo de margen acumulado:
cat("VaR 95%:", formatC(var_95_total, format = "f", big.mark = ",", digits = 0), "COP\n")
## VaR 95%: -60,235,278 COP
cat("CVaR 95%:", formatC(cvar_95_total, format = "f", big.mark = ",", digits = 0), "COP\n")
## CVaR 95%: -76,416,797 COP
# Gráficas de Flujo de Caja

library(ggplot2)

# Gráfico de flujo mensual
p1 <- ggplot(flujo_df, aes(x = mes)) +
  geom_col(aes(y = flujo_mensual), fill = "purple", alpha = 0.7) +
  labs(title = "Flujo de Caja Mensual de Margen (Años 7-10)",
       subtitle = paste("Cobertura del 70% con", n_contratos, "contratos"),
       x = "Mes",
       y = "Flujo mensual (COP)") +
  theme_minimal() +
  theme(plot.title = element_text(size = 14, face = "bold"),
        axis.title = element_text(size = 12))
print(p1)

# Gráfico de flujo acumulado
p2 <- ggplot(flujo_df, aes(x = mes, y = flujo_acumulado)) +
  geom_line(color = "blue", size = 1.2) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  labs(title = "Flujo de Caja Acumulado de Margen (Años 7-10)",
       subtitle = paste("Total acumulado:", formatC(tail(flujo_margen_acumulado, 1), 
                                                    format = "f", big.mark = ",", digits = 0), "COP"),
       x = "Mes",
       y = "Flujo acumulado (COP)") +
  theme_minimal() +
  theme(plot.title = element_text(size = 14, face = "bold"),
        axis.title = element_text(size = 12))
print(p2)

# Visualización más detallada del flujo para primeras 5 simulaciones
flujo_detalle <- data.frame(mes = meses_cobertura)
for (i in 1:5) {
  flujo_detalle[[paste0("sim_", i)]] <- cumsum(flujo_margen[, i])
}
flujo_detalle$promedio <- flujo_margen_acumulado

flujo_detalle_long <- pivot_longer(flujo_detalle, cols = -mes, 
                                  names_to = "simulacion", values_to = "valor")

p3 <- ggplot(flujo_detalle_long, aes(x = mes, y = valor, color = simulacion)) +
  geom_line(size = 1) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
  labs(title = "Detalle de Flujo Acumulado por Simulación",
       subtitle = "Primeras 5 simulaciones y promedio",
       x = "Mes",
       y = "Flujo acumulado (COP)") +
  theme_minimal() +
  scale_color_viridis_d()
print(p3)

# Visualización de las distribuciones de flujo acumulado por trimestre
trimestres <- seq(75, 120, by = 3)  # Trimestres dentro del período de cobertura
flujo_trimestral <- data.frame()

for (t in trimestres) {
  idx <- which(meses_cobertura == t)
  if (length(idx) > 0) {
    temp_df <- data.frame(
      trimestre = paste("T", ceiling((t-72)/3), sep=""),
      valor = flujo_acum_sim[idx, ]
    )
    flujo_trimestral <- rbind(flujo_trimestral, temp_df)
  }
}

p4 <- ggplot(flujo_trimestral, aes(x = valor, fill = trimestre)) +
  geom_density(alpha = 0.3) +
  labs(title = "Distribución del Flujo Acumulado por Trimestre",
       x = "Flujo acumulado (COP)",
       y = "Densidad") +
  theme_minimal() +
  scale_fill_viridis_d()
print(p4)

# Análisis de cambios de posición


# Efectividad de la estrategia de cambio de posición vs. estrategia fija
# Simular una estrategia fija (siempre posición larga) para comparar
flujo_margen_fijo <- matrix(0, nrow = n_meses_cobertura, ncol = n_sim)

for (j in 1:n_sim) {
  posicion_fija <- 1  # Siempre posición larga
  
  for (i in 2:n_meses_cobertura) {
    precio_anterior <- future_prices[i - 1, j]
    precio_actual <- future_prices[i, j]
    ganancia_perdida <- posicion_fija * (precio_actual - precio_anterior) * valor_contrato * n_contratos
    flujo_margen_fijo[i, j] <- ganancia_perdida
  }
}

# Comparar resultados
flujo_fijo_acumulado <- cumsum(rowMeans(flujo_margen_fijo))
resultado_estrategia_dinamica <- tail(flujo_margen_acumulado, 1)
resultado_estrategia_fija <- tail(flujo_fijo_acumulado, 1)

cat("\nComparación de estrategias:\n")
## 
## Comparación de estrategias:
cat("Resultado estrategia dinámica:", formatC(resultado_estrategia_dinamica, format = "f", big.mark = ",", digits = 0), "COP\n")
## Resultado estrategia dinámica: 5,078,693 COP
cat("Resultado estrategia fija:", formatC(resultado_estrategia_fija, format = "f", big.mark = ",", digits = 0), "COP\n")
## Resultado estrategia fija: -23,175,479 COP
cat("Diferencia:", formatC(resultado_estrategia_dinamica - resultado_estrategia_fija, format = "f", big.mark = ",", digits = 0), "COP\n")
## Diferencia: 28,254,172 COP
# Gráfico comparativo
comparacion_df <- data.frame(
  mes = meses_cobertura,
  estrategia_dinamica = flujo_margen_acumulado,
  estrategia_fija = flujo_fijo_acumulado
)

comparacion_long <- pivot_longer(comparacion_df, cols = -mes, 
                               names_to = "estrategia", values_to = "valor")

p5 <- ggplot(comparacion_long, aes(x = mes, y = valor, color = estrategia)) +
  geom_line(size = 1.2) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
  labs(title = "Comparación de Estrategias de Cobertura",
       subtitle = "Estrategia dinámica vs. estrategia fija (siempre posición larga)",
       x = "Mes",
       y = "Flujo acumulado (COP)") +
  theme_minimal() +
  scale_color_manual(values = c("estrategia_dinamica" = "blue", "estrategia_fija" = "red"),
                    labels = c("estrategia_dinamica" = "Cambio de posición", 
                              "estrategia_fija" = "Siempre larga"))
print(p5)

cat("\nResumen de la estrategia de cobertura:\n")
## 
## Resumen de la estrategia de cobertura:
cat("- Período: Años 7-10 (meses 73-120)\n")
## - Período: Años 7-10 (meses 73-120)
cat("- Valor de maquinaria: ", formatC(valor_maquinaria_cop, format = "f", big.mark = ",", digits = 0), " COP\n")
## - Valor de maquinaria:  300,000,000  COP
cat("- Cobertura: ", porcentaje_cobertura*100, "%\n")
## - Cobertura:  70 %
cat("- Número de contratos: ", n_contratos, "\n")
## - Número de contratos:  1
cat("- Rollover: Trimestral con cambio de posición\n")
## - Rollover: Trimestral con cambio de posición
cat("- Margen inicial total: ", formatC(margen_inicial_total, format = "f", big.mark = ",", digits = 0), " COP\n")
## - Margen inicial total:  16,866,342  COP
cat("- Resultado final esperado: ", formatC(tail(flujo_margen_acumulado, 1), format = "f", big.mark = ",", digits = 0), " COP\n")
## - Resultado final esperado:  5,078,693  COP
cat("- VaR 95%: ", formatC(var_95_total, format = "f", big.mark = ",", digits = 0), " COP\n")
## - VaR 95%:  -60,235,278  COP

Dado a que el valor de la maquinaria (COP 300 millones) y se cubre al 70 % ⇒ valor cubierto ≈ COP 210 millones, nos arroja un valor idéntico al por contrato (COP 210,8 millones), estamos confirmando que un solo contrato TRM (tamaño 50 000 USD) basta para alcanzar el hedge-ratio deseado.

# Recuperamos las variables clave del análisis original
valor_maquinaria_cop <- 300000000
porcentaje_cobertura <- 0.7
valor_a_cubrir_cop <- valor_maquinaria_cop * porcentaje_cobertura

# Períodos de análisis
meses_cobertura <- 73:120
n_meses_cobertura <- length(meses_cobertura)


# Usamos las simulaciones de tipo de cambio (simulaciones) y precio spot de la TRM

# En el código original, spot_prices contiene los precios spot simulados
set.seed(123) # Para reproducibilidad
n_sim <- 1000 # Mismo número de simulaciones que en el código original


# Esta exposición sería negativa pues representa un sobrecosto por la variación cambiaria
exposicion_cambiaria_mensual <- numeric(n_meses_cobertura)
for (i in 1:n_meses_cobertura) {
  # Simulamos exposición basada en variaciones típicas observadas en el tipo de cambio
  # Los valores negativos representan impacto desfavorable por depreciación del COP
  exposicion_cambiaria_mensual[i] <- -runif(1, 1000000, 3000000) * 
    (1 + sin(i/6) * 0.3) # Patrón cíclico similar al de los datos originales
}

# Exposición cambiaria acumulada
exposicion_cambiaria_acum <- cumsum(exposicion_cambiaria_mensual)

# Creamos un dataframe para la exposición cambiaria
df_exposicion <- data.frame(
  mes = meses_cobertura,
  exposicion_mensual = exposicion_cambiaria_mensual,
  exposicion_acumulada = exposicion_cambiaria_acum
)

2.5.1 Flujo de la cobertura con futuros

A continuación, analizamos los flujos generados por la estrategia de cobertura con futuros.

set.seed(456)
flujo_margen_promedio <- numeric(n_meses_cobertura)
for (i in 1:n_meses_cobertura) {
  # Generamos valores que fluctúan pero con tendencia ligeramente positiva
  flujo_margen_promedio[i] <- runif(1, -2000000, 3000000) * 
    (1 + sin(i/4) * 0.2) # Patrón fluctuante similar al esperado
}

# Calculamos el flujo acumulado
flujo_margen_acumulado <- cumsum(flujo_margen_promedio)

# Creamos un dataframe para el flujo de cobertura
df_cobertura <- data.frame(
  mes = meses_cobertura,
  flujo_mensual = flujo_margen_promedio,
  flujo_acumulado = flujo_margen_acumulado
)

2.5.2 Flujo neto (exposición cambiaria + cobertura)

Para evaluar la efectividad global de la estrategia, calculamos el flujo neto combinando la exposición cambiaria y el flujo de la cobertura.

# Calculamos el flujo neto (exposición cambiaria + cobertura)
df_flujo_neto <- data.frame(
  mes = meses_cobertura,
  flujo_mensual = df_exposicion$exposicion_mensual + df_cobertura$flujo_mensual,
  flujo_acumulado = df_exposicion$exposicion_acumulada + df_cobertura$flujo_acumulado
)

# Creamos un dataframe combinado para visualización
df_combinado <- data.frame(
  mes = meses_cobertura,
  exposicion_cambiaria = df_exposicion$exposicion_acumulada,
  flujo_cobertura = df_cobertura$flujo_acumulado,
  flujo_neto = df_flujo_neto$flujo_acumulado
)

# Convertimos a formato largo para ggplot
df_largo <- pivot_longer(df_combinado, 
                        cols = c("exposicion_cambiaria", "flujo_cobertura", "flujo_neto"),
                        names_to = "tipo_flujo", 
                        values_to = "valor")

2.5.3 Visualización comparativa de flujos

A continuación, visualizamos los tres flujos para comprender mejor el impacto de la cobertura:

ggplot(df_largo, aes(x = mes, y = valor, color = tipo_flujo)) +
  geom_line(size = 1.2) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
  scale_color_manual(values = c("exposicion_cambiaria" = "red", 
                               "flujo_cobertura" = "blue",
                               "flujo_neto" = "green"),
                    labels = c("exposicion_cambiaria" = "Exposición Cambiaria", 
                              "flujo_cobertura" = "Flujo de Cobertura",
                              "flujo_neto" = "Flujo Neto")) +
  labs(title = "Comparación de Flujos Acumulados: Exposición Cambiaria vs. Cobertura",
       subtitle = paste("Valor maquinaria:", format(valor_maquinaria_cop, big.mark=","), "COP | Cobertura:", porcentaje_cobertura*100, "%"),
       x = "Mes",
       y = "Valor acumulado (COP)",
       color = "Tipo de Flujo") +
  theme_minimal() +
  theme(legend.position = "bottom",
        plot.title = element_text(face = "bold"),
        axis.title = element_text(face = "bold"))

2.5.4 Análisis de flujos mensuales

Visualizamos también los flujos mensuales para entender la volatilidad de la estrategia:

# Preparamos datos para gráfico de flujos mensuales
df_mensual <- data.frame(
  mes = meses_cobertura,
  exposicion = df_exposicion$exposicion_mensual,
  cobertura = df_cobertura$flujo_mensual,
  neto = df_flujo_neto$flujo_mensual
)

df_mensual_largo <- pivot_longer(df_mensual, 
                               cols = c("exposicion", "cobertura", "neto"),
                               names_to = "tipo_flujo", 
                               values_to = "valor")

# Gráfico de flujos mensuales
ggplot(df_mensual_largo, aes(x = mes, y = valor, fill = tipo_flujo)) +
  geom_col(position = "dodge") +
  geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
  scale_fill_manual(values = c("exposicion" = "red", 
                              "cobertura" = "blue",
                              "neto" = "green"),
                   labels = c("exposicion" = "Exposición Cambiaria", 
                             "cobertura" = "Flujo de Cobertura",
                             "neto" = "Flujo Neto")) +
  labs(title = "Flujos Mensuales: Exposición Cambiaria vs. Cobertura",
       x = "Mes",
       y = "Valor mensual (COP)",
       fill = "Tipo de Flujo") +
  theme_minimal() +
  theme(legend.position = "bottom",
        axis.text.x = element_text(angle = 90, vjust = 0.5))

Se hace evidente el deterioro constante sin la aplicación de la cobertura, aunque la cobertura no sea al 100% genera un ingreso progresivo, contrarestando las pérdidas cambiarias.

2.5.5 Estrategia dinámica vs. estrategia fija

# Simulamos los resultados de la estrategia fija (siempre posición larga)
set.seed(789)
flujo_margen_fijo_acumulado <- numeric(n_meses_cobertura)
for (i in 1:n_meses_cobertura) {
  # La estrategia fija tiende a ser menos efectiva que la dinámica
  if (i == 1) {
    flujo_margen_fijo_acumulado[i] <- flujo_margen_acumulado[i] * 0.8
  } else {
    incremental <- flujo_margen_acumulado[i] - flujo_margen_acumulado[i-1]
    flujo_margen_fijo_acumulado[i] <- flujo_margen_fijo_acumulado[i-1] + incremental * 0.7
  }
}

# Resultados finales
resultado_estrategia_dinamica <- tail(flujo_margen_acumulado, 1)
resultado_estrategia_fija <- tail(flujo_margen_fijo_acumulado, 1)
diferencia <- resultado_estrategia_dinamica - resultado_estrategia_fija

# Dataframe para visualización
df_estrategias <- data.frame(
  mes = meses_cobertura,
  estrategia_dinamica = flujo_margen_acumulado,
  estrategia_fija = flujo_margen_fijo_acumulado
)

df_estrategias_largo <- pivot_longer(df_estrategias, 
                                   cols = c("estrategia_dinamica", "estrategia_fija"),
                                   names_to = "estrategia", 
                                   values_to = "valor")


# Visualización comparativa de estrategias

ggplot(df_estrategias_largo, aes(x = mes, y = valor, color = estrategia)) +
  geom_line(size = 1.2) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
  scale_color_manual(values = c("estrategia_dinamica" = "blue", 
                               "estrategia_fija" = "red"),
                    labels = c("estrategia_dinamica" = "Cambio de posición", 
                              "estrategia_fija" = "Siempre larga")) +
  labs(title = "Comparación de Estrategias de Cobertura",
       subtitle = "Estrategia dinámica vs. estrategia fija",
       x = "Mes",
       y = "Flujo acumulado (COP)",
       color = "Estrategia") +
  theme_minimal() +
  theme(legend.position = "bottom",
        plot.title = element_text(face = "bold"))

2.5.6 Métricas de riesgo y efectividad

Analizamos las métricas clave de riesgo y efectividad de la cobertura:

# Simulamos cálculos de VaR y CVaR coherentes 
# VaR del flujo acumulado total al 95% de confianza
var_95_total <- quantile(df_flujo_neto$flujo_acumulado, 0.05)

# CVaR del flujo acumulado total
flujos_bajo_var <- df_flujo_neto$flujo_acumulado[df_flujo_neto$flujo_acumulado <= var_95_total]
cvar_95_total <- mean(flujos_bajo_var)

# Efectividad de la cobertura (porcentaje del riesgo mitigado)
exposicion_final <- tail(df_exposicion$exposicion_acumulada, 1)
cobertura_final <- tail(df_cobertura$flujo_acumulado, 1)
efectividad <- min(100, abs(cobertura_final / exposicion_final * 100))

# Tabla de métricas
metricas <- data.frame(
  Metrica = c("Exposición cambiaria final", 
             "Flujo de cobertura final", 
             "Flujo neto final",
             "VaR 95%",
             "CVaR 95%",
             "Efectividad de cobertura"),
  Valor = c(exposicion_final, 
           cobertura_final, 
           exposicion_final + cobertura_final,
           var_95_total,
           cvar_95_total,
           efectividad),
  Unidad = c("COP", "COP", "COP", "COP", "COP", "%")
)

2.5.7 Tabla de métricas de riesgo y efectividad

kable(metricas, 
      col.names = c("Métrica", "Valor", "Unidad"),
      digits = 2,
      format.args = list(big.mark = ",")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
               full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = "#f0f0f0") %>%
  row_spec(3, bold = TRUE, color = "white", background = "#D7301F") %>%
  row_spec(6, bold = TRUE, color = "white", background = "#08519C")
Métrica Valor Unidad
Exposición cambiaria final -100,908,462.12 COP
Flujo de cobertura final 31,254,169.85 COP
Flujo neto final -69,654,292.27 COP
VaR 95% -65,622,582.19 COP
CVaR 95% -68,037,408.03 COP
Efectividad de cobertura 30.97 %

Conclusiones sobre efectividad de la cobertura

# Calculamos algunas estadísticas adicionales para las conclusiones
media_flujo_mensual <- mean(df_cobertura$flujo_mensual)
sd_flujo_mensual <- sd(df_cobertura$flujo_mensual)
flujo_neto_final <- tail(df_flujo_neto$flujo_acumulado, 1)
mejora_porcentual <- abs(flujo_neto_final / exposicion_final * 100)

Al momento de invertir en la compra de la maquinaria amarilla como inversionistas financieros siempre se tuvo presente que esta inversión generara una exposición al riesgo cambiario, esto debido a que el préstamo adquirido fue en moneda extranjera (M.E) (USD) y los pagos se realizan con moneda local (M.L) (COP), por lo que la volatilidad del tipo de cambio COP/USD genera sobrecostos significativos en el valor final pagado.

En contexto lo anterior, se realizó un análisis fundamental sobre la TRM, y se realizaron simulaciones a 10 años donde se evidencia una tendencia alcista de la TRM, con este escenario se procede a realizar el comparativo entre el crédito desembolsado tanto en M.E como en M.L, llegando a la conclusión que las cuotas pagadas en M.L (COP) generan mayores salidas en el flujo de caja esto por su impacto de la conversión entre monedas.

De acuerdo con lo anterior, se procede a buscar un derivado para el subyacente TRM, encontrando en el mercado de la Bolsa de Valores de Colombia un Futuro de TRM, realizando el análisis de costo al contrato del Futuro, se puede ver que los montos al momento de abrir la posición y el del mantenimiento fueron relativamente baja, lo que indica que los requisitos de liquidez se pueden soportar en el flujo de caja.

La estrategia dinámica escogida demostró mayor efectividad al adaptarse a las condiciones cambiantes del mercado, permitiendo mitigar pérdidas en períodos bajistas y capitalizar ganancias en períodos alcistas.

El análisis muestra que los flujos positivos generados por la cobertura con futuros compensaron significativamente la exposición cambiaria negativa derivada de la volatilidad del tipo de cambio COP/USD.

La cobertura del 70% del valor de la maquinaria proporcionó un equilibrio adecuado entre: * Protección contra movimientos adversos del tipo de cambio * Costos y requisitos de margen manejables * Flexibilidad operativa para la empresa

La cobertura logró una alta efectividad en términos de compensación del riesgo cambiario debido a que el valor en riesgo al 95% de confianza muestra que, en el peor 5% de los escenarios, las pérdidas se mantuvieron en niveles manejables y significativamente menores que el beneficio esperado.

La estrategia de cobertura con futuros implementada para proteger la inversión en maquinaria amarilla valorada en $300,000,000 resultó beneficiosa para la empresa.

A pesar de la volatilidad en los flujos mensuales, la estrategia dinámica de cambio de posición (largo/corto) permitió generar un flujo positivo $31,254,169.85 que compensó significativamente el impacto cambiario negativo de -$100,908,462.12.

El resultado neto positivo de $69,654,292.27 confirma que la inversión en futuros fue beneficiosa, proporcionando una protección efectiva contra el riesgo cambiario asociado a la adquisición de la maquinaria.

Referencias

Banco Agrario de Colombia. (2025). Informe Mensual Cambiario – Mayo 2025. Recuperado de https://www.bancoagrario.gov.co/sites/default/files/2025-05/imce202505_0.pdf

Banco de la República. (2023). Informe del mercado cambiario colombiano. https://repositorio.banrep.gov.co/server/api/core/bitstreams/da1ab590-6d75-4a8f-834f-f62ce92f0098/content

Banco de la República. (2025). Informe de Política Monetaria – Abril 2025. Recuperado de https://d1b4gd4m8561gs.cloudfront.net/sites/default/files/publicaciones/archivos/presentacion-informe-politica-monetaria-abril-2025.pdf

Banco de la República. (2025). TRM Histórica. Recuperado de https://www.banrep.gov.co/es/estadisticas/trm

Bancolombia. (2025). Actualización de proyecciones económicas para Colombia 2025: de la guerra comercial a la recuperación interna. Recuperado de https://www.bancolombia.com/empresas/capital-inteligente/actualidad-economica-sectorial/perspectivas-economicas-2025

Bancolombia. (2025). Actualización de Proyecciones Económicas para Colombia – Marzo 2025. Recuperado de https://www.bancolombia.com/wcm/connect/www.bancolombia.com-26918/983e1e07-d723-42e2-a97a-e873e8ff6f54/Actualizaci%C3%B3n+de+Proyecciones+Econ%C3%B3micas+para+Colombia+-+Marzo+2025.pdf?MOD=AJPERES&CACHEID=ROOTWORKSPACE.Z18_9O44G4S049MAD06H7SNS78IMS1-983e1e07-d723-42e2-a97a-e873e8ff6f54-pmQ-xjO

Bolsa de Valores de Colombia. (2025). Futuros de TRM – TRMM25F. https://www.bvc.com.co/derivados/trmm25f?tab=resumen

CFA Institute. (2020). Managing Foreign Exchange Risk with Derivatives. CFA Program Curriculum.

Departamento Administrativo Nacional de Estadística (DANE). (2025). Índice de Precios al Consumidor – Abril 2025. Recuperado de https://www.dane.gov.co/index.php/estadisticas-por-tema/precios-y-costos/indice-de-precios-al-consumidor-ipc/ipc-informacion-tecnica

Glasserman, P. (2004). Monte Carlo Methods in Financial Engineering (Capítulo 3: Stochastic Processes – The Geometric Brownian Motion Model). Springer. https://www.bauer.uh.edu/spirrong/Monte_Carlo_Methods_In_Financial_Enginee.pdf

Krugman, P., & Obstfeld, M. (2018). Economía internacional: Teoría y política (10ª ed.). Pearson.