Análisis Fundamental

Análisis Macroeconómico de EE. UU. (2024 - 2025)

1. Crecimiento Económico (PIB)

PIB Real Q1 2025 (preliminar): +1,6% anual Proyección 2025 (FMI): crecimiento entre 1,9% - 2,1% Comparado con 2023 (+2,5%), se proyecta una desaceleración moderada, debido a condiciones monetarias más restrictivas.(Fondo Monetario Internacional, 2024; Bureau of Economic Analysis [BEA], 2024).

Un menor crecimiento reduce presiones inflacionarias y permitiría recortes en tasas de la FED → dólar más débil → TRM a la baja.

2. Inflación

CPI abril 2025 (interanual): +3,4% Meta de la FED: 2,0% La inflación ha bajado desde los picos de 2022 (9,1%), pero sigue por encima del objetivo, especialmente en servicios y vivienda.(Bureau of Labor Statistics [BLS], 2025a).

Inflación elevada podría forzar a la FED a mantener tasas altas más tiempo → dólar más fuerte → TRM al alza.

3. Política Monetaria (FED – Tasas de Interés)

Tasa actual (mayo 2025): 5,25% – 5,50% Expectativa de recortes: Comienzo en Q4 2025 (probable recorte de 25-50 pb) La FED ha reiterado un enfoque “data dependent”: esperará señales claras de desinflación sostenida.(Federal Reserve, 2025a).

4. Mercado Laboral

Desempleo abril 2025: 4,0% Salarios: crecen al 4,2% interanual El mercado sigue resiliente pero con señales de enfriamiento en sectores como manufactura y tecnología.(Bureau of Labor Statistics [BLS], 2025b).

Impacto sobre la TRM: Un mercado laboral más débil = menor presión inflacionaria = recortes más rápidos → TRM a la baja

5. Sector Externo: Comercio y Dólar

El déficit comercial en marzo de 2025 fue de USD 68,9 mil millones. El índice del dólar (DXY) se ubica en 103,4, mostrando una fortaleza moderada (Federal Reserve, 2025b; Bureau of Economic Analysis [BEA], 2025; Bureau of Labor Statistics [BLS], 2025c; Fondo Monetario Internacional, 2024).

## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## 
## Adjuntando el paquete: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
Tabla 1: Escenarios combinados para la Tasa de Cambio Representativa del Mercado (TRM) COP/USD a mayo de 2026
Escenario.Económico.USA Proyección.TRM.COP.USD
Desaceleración + recortes FED 3.800 – 3.900
Inflación persistente + sin recortes 4.050 – 4.200
Recesión leve + fuerte recorte tasas 3.700 – 3.850
Sorpresa inflacionaria + geopolítica 4.200 – 4.400
Nota. Los rangos de proyección reflejan análisis propios basados en tendencias macroeconómicas históricas, con información de la FED, BEA, BLS e informes del FMI (2024–2025).

A su vez, podemos tomar como referencia las proyecciones de grandes entidades sobre la TRM para diciembre de 2025, lo cual puede brindarnos indicios o un punto de partida para anticipar su comportamiento durante el año 2026:

Tabla 2: Proyecciones de la Tasa de Cambio Representativa del Mercado (TRM) a diciembre de 2025 por entidad o fuente
Entidad.Fuente Proyección.TRM.a.Dic.2025..COP.USD.
Banco de la República (marzo 2025) 3.950
BBVA Research (abril 2025) 4.000
Bancolombia Research (mayo 2025) 3.950
Corficolombiana (abril 2025) 4.000
Fondo Monetario Internacional (FMI) 3.980
Bloomberg Consensus Forecast (mayo) 3.940
Nota. Valores recopilados de informes públicos de cada entidad. Las fechas entre paréntesis indican la última actualización disponible de cada proyección.

Conclusiones

1. Estado actual de la TRM y evolución reciente

La TRM ha experimentado una tendencia moderadamente bajista desde 2023, estabilizándose en el rango de COP 3.850 a 3.950/USD durante el primer semestre de 2025. Esta trayectoria ha sido impulsada por un entorno de menor aversión al riesgo global,mejora en los términos de intercambio para Colombia (principalmente por el precio del petróleo),y una postura monetaria más flexible del Banco de la República, que ha comenzado a reducir tasas para estimular la economía interna.

2. Factores clave que influirán la TRM en el próximo año

Desde Colombia

  • Tasa de interés del Banco de la República: Si continúa la senda bajista y EE. UU. mantiene tasas altas, podría generarse presión devaluacionista.

  • Política fiscal y reformas estructurales: Riesgos relacionados con la sostenibilidad fiscal, la reforma pensional y laboral pueden afectar la confianza inversora.

  • Flujos de inversión y exportaciones: Un aumento en la IED (Inversion Extranjera Directa) o en las exportaciones (especialmente petróleo) fortalecería el COP.

Desde Estados Unidos

  • Política monetaria de la FED: Si la FED inicia recortes hacia finales de 2025, el dólar perdería fuerza global → presión a la baja sobre la TRM.

  • Inflación persistente: Mantendría tasas elevadas por más tiempo → dólar más fuerte → TRM al alza.

  • Desaceleración económica moderada: Limitaría el fortalecimiento del dólar y beneficiaría monedas emergentes como el COP.

El escenario base más probable contempla una ligera depreciación del dólar hacia 2026, lo cual llevaría la TRM a niveles cercanos a COP 3.900/USD, con un margen de error asociado a la volatilidad geopolítica o económica global.

Proyeccion TRM y Simulación Crédito

Primero extraeremos los datos historicos de la TRM desde el 01 de enero del 2015 hasta el 01 de Mayo de 2025 con el objetivo de obtener una buena cantidad de datos debido a que proyectaremos 10 años en futuro

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
import yfinance as yf

# Descargar TRM histórica desde Yahoo Finance
start_date = "2015-01-01"
end_date = "2025-05-01"
symbol = "USDCOP=X"  # Tasa COP/USD

trm_data = yf.download(symbol, start=start_date, end=end_date)
## YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
trm_data = trm_data['Close'].dropna()
trm_data.name = "TRM"
print(trm_data.head())
## Ticker         USDCOP=X
## Date                   
## 2015-01-01  2345.199951
## 2015-01-02  2375.000000
## 2015-01-05  2430.000000
## 2015-01-06  2448.000000
## 2015-01-07  2428.000000

Calculamos ahora los retornos logarítmicos mensuales y la desviacion estándar mensual

# Re-muestreo a fin de mes para obtener la TRM mensual
trm_mensual = trm_data.resample('ME').last()

# Calcular retornos logarítmicos mensuales
retornos_mensuales = np.log(trm_mensual / trm_mensual.shift(1)).dropna()

# Calcular la desviación estándar mensual
desviacion_mensual = retornos_mensuales.std()

# Mostrar resultados
print("Retornos mensuales (log):")
## Retornos mensuales (log):
print(retornos_mensuales.tail())
## Ticker      USDCOP=X
## Date                
## 2024-12-31 -0.003014
## 2025-01-31 -0.056798
## 2025-02-28 -0.007129
## 2025-03-31 -0.001131
## 2025-04-30  0.016686
print("\nDesviación estándar mensual de los retornos:")
## 
## Desviación estándar mensual de los retornos:
print(desviacion_mensual)
## Ticker
## USDCOP=X    0.04024
## dtype: float64

Grafico de los retornos Mensuales

import matplotlib.pyplot as plt

plt.figure(figsize=(14, 6))
plt.plot(retornos_mensuales, label='Retornos mensuales (log)', color='purple')
plt.axhline(0, color='gray', linestyle='--', linewidth=1)
plt.title("Retornos Mensuales Logarítmicos de la TRM (COP/USD)")
plt.xlabel("Fecha")
plt.ylabel("Retorno Logarítmico")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

  • Se observa que la volatilidad de los retornos logarítmicos mensuales no es constante.

  • Hay períodos donde la volatilidad es relativamente baja (retornos más cercanos a cero) y otros donde las oscilaciones son más amplias (picos positivos y negativos pronunciados).

  • La línea parece oscilar alrededor del valor 0 en retornos logarítmicos, lo que indica que en promedio no hay una tendencia clara de apreciación o depreciación constante en esos períodos mensuales, sino fluctuaciones.

  • Dado que existen picos extremos, estrategias de cobertura o gestión de riesgo pueden ser útiles para protegerse de movimientos inesperados.

Simulación MBG Mensual

# Parámetros para MGB
n_simulaciones = 1000
n_periodos = 10 * 12  # 10 años, 12 meses
dt = 1/12  # periodo mensual

# Calcular media y volatilidad mensual a partir de retornos históricos
mu = retornos_mensuales.mean()
sigma = retornos_mensuales.std()

# Último valor conocido de la TRM como punto de partida
S0 = trm_data.iloc[-1].item()

# Simulación MGB
np.random.seed(42)
simulaciones = np.zeros((n_periodos, n_simulaciones))

for i in range(n_simulaciones):
    shocks = np.random.normal(loc=(mu - 0.5 * sigma**2) * dt,
                              scale=sigma * np.sqrt(dt),
                              size=n_periodos)
    simulaciones[:, i] = S0 * np.exp(np.cumsum(shocks))

# Promedio de las 1000 simulaciones (valor esperado en cada punto en el tiempo)
promedio_simulado = simulaciones.mean(axis=1)

# Crear eje temporal
fechas_simuladas = pd.date_range(start=trm_data.index[-1] + pd.DateOffset(months=1), periods=n_periodos, freq='MS')

plt.figure(figsize=(14, 6))
plt.plot(fechas_simuladas, simulaciones, color='lightgray', alpha=0.2)
plt.plot(fechas_simuladas, promedio_simulado, color='blue', label='Promedio de Simulaciones', linewidth=2)
plt.title("Simulación MGB de la TRM a 10 Años (1000 Trayectorias)")
plt.xlabel("Fecha")
plt.ylabel("TRM Simulada (COP/USD)")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

Alli podemos ver las trayectorias de las 1000 simulaciones en un tono gris y a su vez una linea azul la cual evidencia el promedio de las 1000 simulaciones. Aqui la veremos un poco mas clara:

plt.figure(figsize=(14, 6))
plt.plot(fechas_simuladas, promedio_simulado, color='blue', label='Promedio de Simulaciones', linewidth=2)
plt.title("Valor Esperado de la TRM a 10 Años (Promedio de Simulaciones MGB)")
plt.xlabel("Fecha")
plt.ylabel("TRM Simulada Promedio (COP/USD)")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

De esta simulación se infiere una tendencia ligeramente creciente y sostenida en el valor del dólar frente al peso colombiano, partiendo desde un valor cercano a COP 4.350/USD en 2025 y alcanzando un promedio de aproximadamente COP 4.560/USD en 2035.

También se observa un incremento de aproximadamente 210 pesos por dólar, lo que representa un crecimiento total del orden del 4,8% (o cerca de 0,47% anual compuesto), indicando una devaluación moderada del peso colombiano a lo largo del tiempo.

Teniendo en cuenta lo anterior, es válido aclarar que para proyectos de inversión financiados en dólares, el costo en pesos aumentará progresivamente, lo cual puede implicar mayores pagos en COP y un riesgo cambiario. Para los importadores, esta devaluación representa un incremento en el servicio de la deuda o en los créditos en el extranjero, tal como ocurre en nuestro caso como prestatarios.

Por ello, lo más adecuado sería analizar la conveniencia de utilizar instrumentos derivados como forwards, futuros y opciones.

Adicionalmente, dado que se contempla una cobertura para los últimos 4 años de un crédito a 10 años, a continuación se presenta una gráfica que hace un acercamiento a la simulación durante el periodo mencionado. Esta información servirá como insumo para el análisis final del ejercicio:

import matplotlib.pyplot as plt

# Filtrar fechas entre 2030-01 y 2035-12
inicio_2030 = pd.to_datetime("2030-01-01")
fin_2035 = pd.to_datetime("2035-12-31")

# Máscara para filtrar los datos
mask_2030_2035 = (fechas_simuladas >= inicio_2030) & (fechas_simuladas <= fin_2035)
fechas_2030_2035 = fechas_simuladas[mask_2030_2035]
promedio_2030_2035 = promedio_simulado[mask_2030_2035]

# Graficar
plt.figure(figsize=(18, 6))
plt.plot(fechas_2030_2035, promedio_2030_2035, color='blue', label='Promedio Simulado TRM (2030-2035)', linewidth=2)

plt.title("Valor Esperado de la TRM (Promedio Simulaciones MGB) - 2029 a 2035", fontsize=16)
plt.xlabel("Fecha", fontsize=14)
plt.ylabel("TRM Simulada Promedio (COP/USD)", fontsize=14)

# Etiquetas del eje X con leve rotación
plt.xticks(
    fechas_2030_2035,
    [fecha.strftime('%Y-%m') for fecha in fechas_2030_2035],
    rotation=30, ha="right", fontsize=10
)
## ([<matplotlib.axis.XTick object at 0x0000026AD8DD3250>, <matplotlib.axis.XTick object at 0x0000026AD8E05810>, <matplotlib.axis.XTick object at 0x0000026AD8E05F90>, <matplotlib.axis.XTick object at 0x0000026AD8E06710>, <matplotlib.axis.XTick object at 0x0000026AD8E06E90>, <matplotlib.axis.XTick object at 0x0000026AD8E07610>, <matplotlib.axis.XTick object at 0x0000026AD8E07D90>, <matplotlib.axis.XTick object at 0x0000026AD8E40550>, <matplotlib.axis.XTick object at 0x0000026AD8E40CD0>, <matplotlib.axis.XTick object at 0x0000026AD8E41450>, <matplotlib.axis.XTick object at 0x0000026AD8E41BD0>, <matplotlib.axis.XTick object at 0x0000026AD8E42350>, <matplotlib.axis.XTick object at 0x0000026AD8E42AD0>, <matplotlib.axis.XTick object at 0x0000026AD8E43250>, <matplotlib.axis.XTick object at 0x0000026AD8E439D0>, <matplotlib.axis.XTick object at 0x0000026AD8E60190>, <matplotlib.axis.XTick object at 0x0000026AD8E60910>, <matplotlib.axis.XTick object at 0x0000026AD8E61090>, <matplotlib.axis.XTick object at 0x0000026AD8E61810>, <matplotlib.axis.XTick object at 0x0000026AD8E61F90>, <matplotlib.axis.XTick object at 0x0000026AD8E62710>, <matplotlib.axis.XTick object at 0x0000026AD8E62E90>, <matplotlib.axis.XTick object at 0x0000026AD8E63610>, <matplotlib.axis.XTick object at 0x0000026AD8E63D90>, <matplotlib.axis.XTick object at 0x0000026AD8E7C550>, <matplotlib.axis.XTick object at 0x0000026AD8E7CCD0>, <matplotlib.axis.XTick object at 0x0000026AD8E7D450>, <matplotlib.axis.XTick object at 0x0000026AD8E7DBD0>, <matplotlib.axis.XTick object at 0x0000026AD8E7E350>, <matplotlib.axis.XTick object at 0x0000026AD8E7EAD0>, <matplotlib.axis.XTick object at 0x0000026AD8E7F250>, <matplotlib.axis.XTick object at 0x0000026AD8E7F9D0>, <matplotlib.axis.XTick object at 0x0000026AD8E9C190>, <matplotlib.axis.XTick object at 0x0000026AD8E9CA50>, <matplotlib.axis.XTick object at 0x0000026AD8E9D1D0>, <matplotlib.axis.XTick object at 0x0000026AD8E9D950>, <matplotlib.axis.XTick object at 0x0000026AD8E9E0D0>, <matplotlib.axis.XTick object at 0x0000026AD8E9E850>, <matplotlib.axis.XTick object at 0x0000026AD8E9EFD0>, <matplotlib.axis.XTick object at 0x0000026AD8E9F750>, <matplotlib.axis.XTick object at 0x0000026AD8E9FED0>, <matplotlib.axis.XTick object at 0x0000026AD8E9C910>, <matplotlib.axis.XTick object at 0x0000026AD8EB4CD0>, <matplotlib.axis.XTick object at 0x0000026AD8EB5450>, <matplotlib.axis.XTick object at 0x0000026AD8EB5BD0>, <matplotlib.axis.XTick object at 0x0000026AD8EB6350>, <matplotlib.axis.XTick object at 0x0000026AD8EB6AD0>, <matplotlib.axis.XTick object at 0x0000026AD8EB7250>, <matplotlib.axis.XTick object at 0x0000026AD8EB79D0>, <matplotlib.axis.XTick object at 0x0000026AD8EDC190>, <matplotlib.axis.XTick object at 0x0000026AD8EDC910>, <matplotlib.axis.XTick object at 0x0000026AD8EDD090>, <matplotlib.axis.XTick object at 0x0000026AD8EDD810>, <matplotlib.axis.XTick object at 0x0000026AD8EDDF90>, <matplotlib.axis.XTick object at 0x0000026AD8EDE710>, <matplotlib.axis.XTick object at 0x0000026AD8EDEE90>, <matplotlib.axis.XTick object at 0x0000026AD8EDF610>, <matplotlib.axis.XTick object at 0x0000026AD8EDFD90>, <matplotlib.axis.XTick object at 0x0000026AD8F00550>, <matplotlib.axis.XTick object at 0x0000026AD8F00CD0>, <matplotlib.axis.XTick object at 0x0000026AD8F01450>, <matplotlib.axis.XTick object at 0x0000026AD8F01BD0>, <matplotlib.axis.XTick object at 0x0000026AD8F02350>, <matplotlib.axis.XTick object at 0x0000026AD8F02AD0>, <matplotlib.axis.XTick object at 0x0000026AD8F03250>], [Text(21915.0, 0, '2030-01'), Text(21946.0, 0, '2030-02'), Text(21974.0, 0, '2030-03'), Text(22005.0, 0, '2030-04'), Text(22035.0, 0, '2030-05'), Text(22066.0, 0, '2030-06'), Text(22096.0, 0, '2030-07'), Text(22127.0, 0, '2030-08'), Text(22158.0, 0, '2030-09'), Text(22188.0, 0, '2030-10'), Text(22219.0, 0, '2030-11'), Text(22249.0, 0, '2030-12'), Text(22280.0, 0, '2031-01'), Text(22311.0, 0, '2031-02'), Text(22339.0, 0, '2031-03'), Text(22370.0, 0, '2031-04'), Text(22400.0, 0, '2031-05'), Text(22431.0, 0, '2031-06'), Text(22461.0, 0, '2031-07'), Text(22492.0, 0, '2031-08'), Text(22523.0, 0, '2031-09'), Text(22553.0, 0, '2031-10'), Text(22584.0, 0, '2031-11'), Text(22614.0, 0, '2031-12'), Text(22645.0, 0, '2032-01'), Text(22676.0, 0, '2032-02'), Text(22705.0, 0, '2032-03'), Text(22736.0, 0, '2032-04'), Text(22766.0, 0, '2032-05'), Text(22797.0, 0, '2032-06'), Text(22827.0, 0, '2032-07'), Text(22858.0, 0, '2032-08'), Text(22889.0, 0, '2032-09'), Text(22919.0, 0, '2032-10'), Text(22950.0, 0, '2032-11'), Text(22980.0, 0, '2032-12'), Text(23011.0, 0, '2033-01'), Text(23042.0, 0, '2033-02'), Text(23070.0, 0, '2033-03'), Text(23101.0, 0, '2033-04'), Text(23131.0, 0, '2033-05'), Text(23162.0, 0, '2033-06'), Text(23192.0, 0, '2033-07'), Text(23223.0, 0, '2033-08'), Text(23254.0, 0, '2033-09'), Text(23284.0, 0, '2033-10'), Text(23315.0, 0, '2033-11'), Text(23345.0, 0, '2033-12'), Text(23376.0, 0, '2034-01'), Text(23407.0, 0, '2034-02'), Text(23435.0, 0, '2034-03'), Text(23466.0, 0, '2034-04'), Text(23496.0, 0, '2034-05'), Text(23527.0, 0, '2034-06'), Text(23557.0, 0, '2034-07'), Text(23588.0, 0, '2034-08'), Text(23619.0, 0, '2034-09'), Text(23649.0, 0, '2034-10'), Text(23680.0, 0, '2034-11'), Text(23710.0, 0, '2034-12'), Text(23741.0, 0, '2035-01'), Text(23772.0, 0, '2035-02'), Text(23800.0, 0, '2035-03'), Text(23831.0, 0, '2035-04'), Text(23861.0, 0, '2035-05')])
plt.legend(fontsize=12)
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()

Simulacion crédito USD

  • Para esta simulacion tomaremos un valor en COP de $300.000.000 junto con una TRM de 4.239,23 la cúal corresponde a la TRM para el cierre del dia 12 de Mayo de 2025 que fue el dia de inicio del ejercicio. Ademas, se realizara el credito por el 90% debido a que como pago inicial se debio pagar el 10%.

  • A su vez se tomo el crédito con una tasa E.A del 5.59% que corresponde al Bank Of America.

Figura 1. Tasas de interés para autos nuevos de Bank of America. Nota. Captura de pantalla recuperada de https://www.bankofamerica.com/auto-loans/ en mayo de 2025.
Figura 1. Tasas de interés para autos nuevos de Bank of America. Nota. Captura de pantalla recuperada de https://www.bankofamerica.com/auto-loans/ en mayo de 2025.

¿Porque Bank Of America?

BOA es el segundo banco más grande de EE.UU. por activos, solo detrás de JPMorgan Chase.Administra más de $3.2 billones en activos (2024), lo que lo convierte en un actor clave en crédito, banca de consumo, banca de inversión y gestión patrimonial.Tiene una presencia dominante en el mercado estadounidense, con millones de clientes minoristas y empresariales.

Ahora una vez explicadas las variables para la simulacion:

# Parámetros del crédito
valor_cop = 300_000_000
trm = 4239.23 #TRM 12 de Mayo de 2025
valor_usd = valor_cop / trm

pago_inicial_usd = valor_usd * 0.10
monto_credito = valor_usd * 0.90

tasa_anual = 0.0559 
tasa_mensual = (1 + tasa_anual)**(1/12) - 1
plazo_meses = 10 * 12  # 10 años

# Cálculo de la cuota mensual con fórmula de anualidad
cuota_mensual = monto_credito * (tasa_mensual * (1 + tasa_mensual) ** plazo_meses) / \
                ((1 + tasa_mensual) ** plazo_meses - 1)

# Crear cronograma de pagos
saldo = monto_credito
tabla_amortizacion = []

for mes in range(1, plazo_meses + 1):
    interes = saldo * tasa_mensual
    abono_capital = cuota_mensual - interes
    saldo -= abono_capital
    tabla_amortizacion.append([mes, cuota_mensual, interes, abono_capital, saldo if saldo > 0 else 0])


df_credito = pd.DataFrame(tabla_amortizacion, columns=["Mes", "Cuota (USD)", "Interés (USD)", "Abono a Capital (USD)", "Saldo"])
print(df_credito)
##      Mes  Cuota (USD)  Interés (USD)  Abono a Capital (USD)         Saldo
## 0      1   689.689197     289.352386             400.336810  6.329047e+04
## 1      2   689.689197     287.533625             402.155572  6.288832e+04
## 2      3   689.689197     285.706600             403.982596  6.248434e+04
## 3      4   689.689197     283.871275             405.817921  6.207852e+04
## 4      5   689.689197     282.027613             407.661584  6.167086e+04
## ..   ...          ...            ...                    ...           ...
## 115  116   689.689197      15.455282             674.233914  2.727706e+03
## 116  117   689.689197      12.392184             677.297012  2.050409e+03
## 117  118   689.689197       9.315170             680.374026  1.370035e+03
## 118  119   689.689197       6.224178             683.465019  6.865701e+02
## 119  120   689.689197       3.119142             686.570055  1.512035e-11
## 
## [120 rows x 5 columns]

:::

Resumen del Crédito en USD

# Calcular los valores resumen
monto_solicitado = round(monto_credito, 2)
interes_total = round(df_credito["Interés (USD)"].sum(), 2)
total_pagado = round(df_credito["Cuota (USD)"].sum(), 2)
abono_total_capital = round(df_credito["Abono a Capital (USD)"].sum(), 2)
pago_inicial_total = round(pago_inicial_usd, 2)
costo_total_proyecto = round(pago_inicial_total + total_pagado, 2)

# Crear tabla resumen
resumen_credito = pd.DataFrame({
    "Concepto": [
        "Monto solicitado (USD)",
        "Pago inicial (USD)",
        "Interés total pagado (USD)",
        "Abono total a capital (USD)",
        "Total pagado en cuotas (USD)",
        "Costo total del proyecto (USD)"
    ],
    "Valor (USD)": [
        monto_solicitado,
        pago_inicial_total,
        interes_total,
        abono_total_capital,
        total_pagado,
        costo_total_proyecto
    ]
})

# Aplicar formato con separador de miles y dos decimales
resumen_credito_styled = resumen_credito.style.format({"Valor (USD)": "{:,.2f}"})
resumen_credito_styled
  Concepto Valor (USD)
0 Monto solicitado (USD) 63,690.81
1 Pago inicial (USD) 7,076.76
2 Interés total pagado (USD) 19,071.89
3 Abono total a capital (USD) 63,690.81
4 Total pagado en cuotas (USD) 82,762.70
5 Costo total del proyecto (USD) 89,839.46

:::

Conclusiones del crédito en USD:

  • El interés pagado representa aproximadamente un 30% del monto solicitado.Esta proporcion es moderadamente alta, lo cual puede depender del plazo o la tasa de interés.El costo final del proyecto de USD 89.839,46, lo que implica que por cada dólar financiado, se terminaron pagando 1.41 USD aproximadamente.

  • Si el retorno o beneficio del proyecto no supera el costo total (USD 89,839.46), puede que financieramente no sea viable. Se recomienda comparar esta opción con otras fuentes de financiamiento o estudiar el impacto de amortizaciones anticipadas para reducir intereses.

Recreación del crédito en pesos.

# Asegurar que df_flujo tenga el mismo número de periodos que promedio_simulado (180 meses)
df_flujo_cop = df_credito.copy()
df_flujo_cop["TRM Esperada"] = promedio_simulado[:len(df_credito)]

# Convertir a COP
df_flujo_cop["Cuota (COP)"] = (df_flujo_cop["Cuota (USD)"] * df_flujo_cop["TRM Esperada"]).round(2)
df_flujo_cop["Interés (COP)"] = (df_flujo_cop["Interés (USD)"] * df_flujo_cop["TRM Esperada"]).round(2)
df_flujo_cop["Abono a Capital (COP)"] = (df_flujo_cop["Abono a Capital (USD)"] * df_flujo_cop["TRM Esperada"]).round(2)
# Opcional: agregar las fechas simuladas al DataFrame
df_flujo_cop["Fecha"] = fechas_simuladas[:len(df_credito)]

# Reordenar columnas para que sea más clara
df_flujo_cop = df_flujo_cop[[
    "Fecha",
    "TRM Esperada",
    "Cuota (USD)", "Interés (USD)", "Abono a Capital (USD)",
    "Cuota (COP)", "Interés (COP)", "Abono a Capital (COP)"
]]

# Mostrar las primeras filas del nuevo DataFrame
df_flujo_cop.head()
##        Fecha  TRM Esperada  ...  Interés (COP)  Abono a Capital (COP)
## 0 2025-06-01   4196.358263  ...     1214226.28             1679956.68
## 1 2025-07-01   4197.012197  ...     1206782.13             1687851.84
## 2 2025-08-01   4200.033767  ...     1199977.37             1696740.55
## 3 2025-09-01   4202.162846  ...     1192873.33             1705312.99
## 4 2025-10-01   4205.661514  ...     1186112.68             1714486.63
## 
## [5 rows x 8 columns]

Resumen Crédito Recreado en COP

monto_cop = 300_000_000  # COP
inicial_cop = monto_cop * 0.10
monto_solicitado_cop = monto_cop - inicial_cop

resumen_cop = {
    "Monto inicial maquinaria (COP)": monto_cop,
    "Pago inicial (10%) (COP)": inicial_cop,
    "Monto solicitado (90%) (COP)": monto_solicitado_cop,
    "Total pagado en cuotas (COP)": df_flujo_cop["Cuota (COP)"].sum(),
    "Total de intereses pagados (COP)": df_flujo_cop["Interés (COP)"].sum(),
    "Total abonado a capital (COP)": df_flujo_cop["Abono a Capital (COP)"].sum()
}

resumen_cop_df = pd.DataFrame.from_dict(resumen_cop, orient='index', columns=["Valor (COP)"])
resumen_cop_df.style.format("{:,.0f}")
  Valor (COP)
Monto inicial maquinaria (COP) 300,000,000
Pago inicial (10%) (COP) 30,000,000
Monto solicitado (90%) (COP) 270,000,000
Total pagado en cuotas (COP) 355,808,449
Total de intereses pagados (COP) 81,431,180
Total abonado a capital (COP) 274,377,269

Conclusiones del crédito en COP:

  • La maquinaria terminó costando un 36,6% más al financiarla. Los intereses pagados representan el 35,2% del monto solicitado, reflejando un crédito con un costo financiero moderadamente alto, pero no excesivo. Se abonó a capital más de lo solicitado originalmente debido a los cambios en la TRM a medida que avanzaba el crédito. Este incremento en los intereses también está explicado por la simulación y la pendiente positiva que presentó el dólar frente al peso colombiano a lo largo de los 10 años.

  • Para tener una mejor perspectiva, se presentará una gráfica que muestra la evolución del valor de la cuota en COP. Cabe recordar que, bajo el método francés, los pagos en USD mantuvieron un valor constante; sin embargo, debido a la devaluación del peso (según los valores extraídos de la simulación), el valor de la cuota en COP varió progresivamente.

# Gráfica de evolución con etiquetas anuales
plt.figure(figsize=(14, 6))
plt.plot(df_flujo_cop["Fecha"], df_flujo_cop["Cuota (COP)"], label="Cuota mensual en COP", color="green", linewidth=2)

# Filtrar fechas de diciembre para etiquetar
diciembre_mask = df_flujo_cop["Fecha"].dt.month == 12
fechas_diciembre = df_flujo_cop[diciembre_mask]["Fecha"]
cuotas_diciembre = df_flujo_cop[diciembre_mask]["Cuota (COP)"]

# Agregar etiquetas
for fecha, cuota in zip(fechas_diciembre, cuotas_diciembre):
    plt.text(fecha, cuota + 5000, f"{cuota:,.0f}", ha='center', va='bottom', fontsize=9, rotation=0)

plt.title("Evolución de la Cuota del Crédito en COP (con TRM simulada)")
plt.xlabel("Fecha")
plt.ylabel("Cuota mensual (COP)")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

  • En el grafico podemos ver la evolucion en COP de la cuota fija en dolares que era de $689.69 USD, pero para el caso en COP fue aumentando constantemente. Los valores vistos en las etiquetas de datos muestran los valores alcanzados al cierre de cada año. Presentando una variacion desde el cierre del 2026 al cierre del 2035 del 4,2% que nos confirmaría que cada año se pagara mas.

Proceso de futuro

Para este punto tomaremos informacion de la Bolsa de Valores Colombiana para el futuro TRMM25F. Elegimos este futuro debido a su gran cantidad de contratos, la liquidez presentada y el volumen que representa.El futuro presenta vencimientos trimestrales.

Adjuntamos imagen que explica un poco su composición.

Figura 2. Características de futuros de la Bolsa de Valores de Colombia (BVC). Nota. Captura de pantalla recuperada de GraphAssets (https://media.graphassets.com/…) en mayo de 2025.
Figura 2. Características de futuros de la Bolsa de Valores de Colombia (BVC). Nota. Captura de pantalla recuperada de GraphAssets (https://media.graphassets.com/…) en mayo de 2025.

:::

Se resalta de la figura 2 (BVC) el tamaño del contrato; que al ser en su nemotecnico TRM equivaldra a USD 50.000. Adicional notamos que la garantia sobre la posicion que exige la BVC sera para el ejercicio de 6.3%. Investigando en la página oficial de la BVC no se logro encontrar explicitamente el valor del costo de mantenimiento por lo que para efectos del laboratorio asumiremos con una tasa igual a la de garantia que es del 6.3%.

Para la extracción de la información historica de este futuro se descargaran los datos encontrados en la pagina de la BVC, sin embargo debido a la naturaleza de estos derivados; los cuales presentan un vencimiento, es mas dificil obtener informacion de hace mas de 1 año. A su vez, la informacion no es continiua, pero al menos nos garantizo un dato por mes durante 1 año.

import pandas as pd
import numpy as np

archivo = "TRMM25F.xlsx"

# Leer el archivo Excel directamente
df = pd.read_excel(archivo)

# Asegurar que las fechas esten en formato datetime
df["Fecha"] = pd.to_datetime(df["Fecha"])

# Ordenar por fecha
df = df.sort_values("Fecha")

# Agrupar por mes y tomar el ultimo precio de cierre disponible en cada mes
df_mensual = df.resample('ME', on='Fecha').last()

# Calcular retornos logaritmicos mensuales
df_mensual["Retorno log"] = np.log(df_mensual["Precio cierre"] / df_mensual["Precio cierre"].shift(1))

# Eliminar el primer valor (NaN)
df_mensual = df_mensual.dropna()

# Calcular media y desviacion estandar
media_mensual_futuro = df_mensual["Retorno log"].mean()
desviacion_mensual_futuro = df_mensual["Retorno log"].std()

# Mostrar resultados
print("Media mensual de los retornos logaritmicos:", round(media_mensual_futuro, 4))
## Media mensual de los retornos logaritmicos: -0.0012
print("Desviacion estandar mensual de los retornos logaritmicos:", round(desviacion_mensual_futuro, 4))
## Desviacion estandar mensual de los retornos logaritmicos: 0.0271
# Mostrar tabla
df_mensual[["Precio cierre", "Retorno log"]].head()
##             Precio cierre  Retorno log
## Fecha                                 
## 2024-07-31           4161    -0.031230
## 2024-08-31           4211     0.011945
## 2024-09-30           4299     0.020682
## 2024-10-31           4530     0.052340
## 2024-11-30           4569     0.008572

Consideraciones y analísis datos obtenidos:

  • La media mensual de los retornos logarítmicos fue de -0.0012, lo que, al ser un valor negativo, sugiere que el precio se estuvo depreciando ligeramente en promedio cada mes. Nuestros datos históricos, correspondientes aproximadamente a los últimos ocho meses, coinciden con un descenso constante en la bolsa de valores de Estados Unidos y, con ello, también con una devaluación del dólar. Durante los últimos meses de 2024, se generaron expectativas de recortes en las tasas de interés por parte de la Reserva Federal (Fed); dichas expectativas estaban fundamentadas en señales de desaceleración económica y una menor inflación, lo que podría llevar a la Fed a reducir sus tasas.

  • Tasas más bajas hacen que los activos en dólares sean menos atractivos para inversionistas internacionales, lo que se traduce en una menor demanda de USD. Esto lleva a una depreciación del dólar, especialmente frente a monedas emergentes, siempre que estas mantengan políticas monetarias estables o restrictivas.

  • Adicionalmente, luego de la posesión de Donald Trump como presidente de los Estados Unidos, el 20 de enero del presente año, se ha generalizado la incertidumbre respecto a su política fiscal expansiva. Trump ha propuesto nuevos estímulos fiscales —como recortes de impuestos y subsidios a sectores como la energía o la manufactura—, lo que puede generar mayores déficits fiscales y, en consecuencia, tendería a aumentar la oferta de dólares en la economía.

  • La desviación estándar mensual fue de 0.0271, un valor moderado que indica que el activo presenta una variabilidad mensual no despreciable, pero tampoco excesiva. Esto sugiere que, aunque existen riesgos, no se observan movimientos extremos con frecuencia, lo que permite cierta previsibilidad para la toma de decisiones de cobertura cambiaria.

formula del futuro de la TRM para el primer mes:

S = 4239.23  # TRM actual (spot)
r_COP_EA = 0.2198 # Tasa E.A para negocios de Bancolombia
r_COP = (1 + r_COP_EA)**(1/12) - 1 # Tasa EM (interés en COP)
r_USD_EA = 0.0559  # Tasa E.A para prestamos de vehiculos del Bank Of America (interés en USD)
r_USD = (1 + r_USD_EA)**(1/12) - 1
t = 30  # Días a vencimiento

# Cálculo del precio futuro
F = S * ((1 + r_COP * (t / 360)) / (1 + r_USD * (t / 360)))

# Mostrar resultado
print(f"El precio futuro de la TRM a {t} días es: {F:.2f} COP/USD")
## El precio futuro de la TRM a 30 días es: 4243.52 COP/USD
  • Teniendo en cuenta lo propuesto en el laboratorio, tomaremos el valor calculado anteriormente de 4243.52 como el valor simulado para nuestro primer mes. Para obtener este valor, tomamos como tasa doméstica el 21.98% E.A. ofrecido por Bancolombia para los créditos de inversión en vehículos.
Figura 3. Tasas para créditos vehiculares de Bancolombia. Nota. Captura de pantalla recuperada de https://www.bancolombia.com/… en mayo de 2025.
Figura 3. Tasas para créditos vehiculares de Bancolombia. Nota. Captura de pantalla recuperada de https://www.bancolombia.com/… en mayo de 2025.

:::

  • Para la tasa extranjera tomaremos la tasa de la parte dos del laboratorio la cual fue de 5.59% E.A del Bank Of America.

Simulación futuro de la TRM.

import numpy as np
import matplotlib.pyplot as plt

# Parámetros de entrada
S0 = F  # Valor del futuro calculado anteriormente (reemplaza por el valor correcto si es necesario)
mu = media_mensual_futuro  # Ya calculado anteriormente
sigma = desviacion_mensual_futuro  # Ya calculado anteriormente
n_simulaciones = 1000
n_periodos = 119  # Se simulan 119 meses porque el primer mes ya se calculó con la fórmula

# Simulación MGB
np.random.seed(42)  # Reproducibilidad
dt = 1  # Mensual
simulaciones_futuro = np.zeros((n_periodos + 1, n_simulaciones))
simulaciones_futuro[0] = S0

for t in range(1, n_periodos + 1):
    Z = np.random.normal(0, 1, n_simulaciones)
    simulaciones_futuro[t] = simulaciones_futuro[t-1] * np.exp((mu - 0.5 * sigma**2) * dt + sigma * np.sqrt(dt) * Z)

# Promedio mensual de las simulaciones
promedio_futuro_simulado = simulaciones_futuro.mean(axis=1)

# Gráfica
plt.figure(figsize=(14, 6))

# Todas las simulaciones en gris claro
for i in range(n_simulaciones):
    plt.plot(simulaciones_futuro[:, i], color='lightgray', linewidth=0.5)

# Promedio en azul
plt.plot(promedio_futuro_simulado, color='blue', linewidth=2, label='Promedio de simulaciones')

plt.title("Simulación MGB del futuro TRMM25F - 10 años (mensual), 1000 trayectorias")
plt.xlabel("Meses")
plt.ylabel("TRM simulada")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

  • Vemos nuevamente las simulaciones durante los proximos 10 años en un tono gris claro y el promedio de ellas con una linea azul.

Ahora, haremos zoom a este promedio de las simulaciones, pero solo para los ultimos 4 años.

import matplotlib.pyplot as plt

# Rango desde el período 70 hasta el final
inicio = 70
promedio_periodo_70_al_final = promedio_futuro_simulado[inicio:]
x_vals = list(range(inicio + 1, len(promedio_futuro_simulado) + 1))  # Eje X desde 71 en adelante

# Crear gráfico
plt.figure(figsize=(12, 6))
plt.plot(x_vals, promedio_periodo_70_al_final, color='blue', linewidth=2, label='Promedio TRM simulada')

# Ticks cada 3 meses (ajustados al rango)
plt.xticks(ticks=range(x_vals[0], x_vals[-1] + 1, 3))
## ([<matplotlib.axis.XTick object at 0x0000026ADAC9C410>, <matplotlib.axis.XTick object at 0x0000026ADAC9E990>, <matplotlib.axis.XTick object at 0x0000026ADAC9F110>, <matplotlib.axis.XTick object at 0x0000026ADAC9F890>, <matplotlib.axis.XTick object at 0x0000026ADACF4050>, <matplotlib.axis.XTick object at 0x0000026ADACF47D0>, <matplotlib.axis.XTick object at 0x0000026ADACF4F50>, <matplotlib.axis.XTick object at 0x0000026ADACF56D0>, <matplotlib.axis.XTick object at 0x0000026ADACF5E50>, <matplotlib.axis.XTick object at 0x0000026ADACF65D0>, <matplotlib.axis.XTick object at 0x0000026ADACF6D50>, <matplotlib.axis.XTick object at 0x0000026ADACF74D0>, <matplotlib.axis.XTick object at 0x0000026ADACF7C50>, <matplotlib.axis.XTick object at 0x0000026ADAD14410>, <matplotlib.axis.XTick object at 0x0000026ADAD14B90>, <matplotlib.axis.XTick object at 0x0000026ADAD15310>, <matplotlib.axis.XTick object at 0x0000026ADAD15A90>], [Text(71, 0, '71'), Text(74, 0, '74'), Text(77, 0, '77'), Text(80, 0, '80'), Text(83, 0, '83'), Text(86, 0, '86'), Text(89, 0, '89'), Text(92, 0, '92'), Text(95, 0, '95'), Text(98, 0, '98'), Text(101, 0, '101'), Text(104, 0, '104'), Text(107, 0, '107'), Text(110, 0, '110'), Text(113, 0, '113'), Text(116, 0, '116'), Text(119, 0, '119')])
plt.title("Promedio de TRMM25F simulada - Últimos 4 años (mensual)")
plt.xlabel("Mes (desde el inicio de la simulación)")
plt.ylabel("TRM promedio")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

  • La tendencia es claramente descendente: el contrato TRMM25F en promedio disminuye constantemente desde un valor cercano a 3.905 hasta aproximadamente 3.675 al final del período.No hay picos ni saltos abruptos; la línea es relativamente suave. Esto sugiere que no se simularon choques externos extremos, como crisis financieras, reformas fiscales agresivas o eventos geopolíticos disruptivos quizas por la falta de mas datos historicos.

  • El grafico se encuetra dividio en el eje X cada 3 meses con el fin de concluir que posición es mas conveniente todas para el Rollover en cada vencimiento.

  • Analizando la grafica y dentro de nuestro ejercicio de laboratorio, asumiremos que esta prediccion sera fiel 100% durante los proximos años. Teniendo esto en cuenta desde nuestra perspectiva de inversores la mejor opción para realizar la cobertura con este derivado sera cada trimestre tomar posiciones en corto y asi sacar el maximo provecho a estos movimientos.

  • Cabe resaltar que para decisiones reales es mas conveniente tener mas datos para la simulación debido a que estamos simulando mas del triple de datos mensuales que logramos obtener de la BVC. Para simulaciones mas reales es posible enviar un correo a la BVC con la solicitud para obtener una data mas completa.

Flujo de caja de margen:

import pandas as pd
pd.set_option('display.float_format', '{:,.2f}'.format)
# Parámetros
capital_cop = 300000000
exposicion = 0.70
margen = 0.065 #mismo porcentaje para margen inicial y margen de mantenimiento
tam_contrato_usd = 50000
posicion = 'corta'
#num_contratos = (300000000*0.7)//((300000000*0.7)*0.065) #Calculo de la cantidad de contratos dependiendo del margen

# Precios futuros simulados para periodos 72 al 120
precios_futuro = promedio_futuro_simulado[71:120]  # largo 48
periodos = np.arange(72, 121)

# Inicializar tabla
tabla = pd.DataFrame({
    'Periodo': periodos,
    'Precio futuro': precios_futuro,
    'Diferencia': np.zeros_like(precios_futuro),
    'Ganancia/Pérdida mes': np.zeros_like(precios_futuro),
    'Ganancia/Pérdida acumulada': np.zeros_like(precios_futuro),
    'Balance cuenta': np.zeros(len(precios_futuro), dtype='float64'),
    #'Balance cuenta': np.zeros_like(precios_futuro),
    'Llamada margen': np.zeros_like(precios_futuro)
})

# Inicialización
exposicion_total_cop = capital_cop * exposicion
precio_ini = tabla.loc[0, 'Precio futuro']
valor_contrato_cop = tam_contrato_usd * precio_ini
margen_inicial_cop = exposicion_total_cop * margen
#num_contratos = int(exposicion_total_cop // margen_inicial_cop)
num_contratos = (300000000*0.7)//((300000000*0.7)*0.065) #Calculo de la cantidad de contratos dependiendo del margen
tabla.loc[0, 'Balance cuenta'] = round(margen_inicial_cop * num_contratos,2)

# Loop para cada mes
for i in range(1, len(tabla)):
    precio_ant = tabla.loc[i - 1, 'Precio futuro']
    precio_act = tabla.loc[i, 'Precio futuro']

    # Rollover trimestral
    if i % 3 == 0:
        valor_contrato_cop = tam_contrato_usd * precio_act
        margen_inicial_cop = exposicion_total_cop * margen
        num_contratos = int(exposicion_total_cop // margen_inicial_cop)

    # Payoff mensual
    diff = precio_ant - precio_act if posicion == 'corta' else precio_act - precio_ant
    ganancia_mes_cop = num_contratos * tam_contrato_usd * diff
    tabla.loc[i, 'Diferencia'] = diff
    tabla.loc[i, 'Ganancia/Pérdida mes'] = ganancia_mes_cop
    tabla.loc[i, 'Ganancia/Pérdida acumulada'] = (
        tabla.loc[i - 1, 'Ganancia/Pérdida acumulada'] + ganancia_mes_cop
    )

    # Margen mínimo requerido
    margen_requerido = (exposicion_total_cop*margen) * num_contratos 
    balance_anterior = tabla.loc[i - 1, 'Balance cuenta']
    llamada_margen = 0
    if balance_anterior < margen_requerido:
        llamada_margen = margen_requerido - balance_anterior

    tabla.loc[i, 'Llamada margen'] = llamada_margen
    tabla.loc[i, 'Balance cuenta'] = round(balance_anterior + ganancia_mes_cop + llamada_margen,2)
    


tabla = tabla.round(2)
#tabla['Balance cuenta formateado'] = tabla['Balance cuenta'].apply(lambda x: format(x, ',.2f'))
#tabla['Balance cuenta'] = tabla['Balance cuenta'].apply(lambda x: format(x, ',.2f'))
tabla.head(10)
##    Periodo  Precio futuro  ...  Balance cuenta  Llamada margen
## 0       72       3,894.56  ...  204,750,000.00            0.00
## 1       73       3,884.29  ...  212,457,406.58            0.00
## 2       74       3,888.54  ...  209,266,707.40            0.00
## 3       75       3,881.99  ...  214,182,591.12            0.00
## 4       76       3,876.94  ...  217,964,403.97            0.00
## 5       77       3,870.89  ...  222,503,467.71            0.00
## 6       78       3,868.37  ...  224,392,947.03            0.00
## 7       79       3,862.61  ...  228,712,643.08            0.00
## 8       80       3,858.02  ...  232,156,569.00            0.00
## 9       81       3,856.27  ...  233,466,529.87            0.00
## 
## [10 rows x 7 columns]
  • En el cuadro anterior veremos en el momento tan solo los primeros 10 registros de nuestro flujo de caja, sin embargo veremos un resumen a continuación:
tabla['Ganancia/Pérdida mes'] = pd.to_numeric(tabla['Ganancia/Pérdida mes'], errors='coerce')
tabla['Balance cuenta'] = pd.to_numeric(tabla['Balance cuenta'], errors='coerce')
tabla['Llamada margen'] = pd.to_numeric(tabla['Llamada margen'], errors='coerce')

# Garantía inicial 
garantia_inicial = float(tabla.loc[0, 'Balance cuenta'])

# PyG total
pyg_total = float(tabla['Ganancia/Pérdida mes'].sum())

# Rentabilidad sobre garantía inicial
rentabilidad_pyg = pyg_total / garantia_inicial

# Margen final
margen_final = float(tabla['Balance cuenta'].iloc[-1])

# Suma de llamadas de margen
suma_llamadas = float(tabla['Llamada margen'].sum())

# Garantía final (descontando llamadas de margen)
garantia_final = margen_final - suma_llamadas

# Rentabilidad final
rentabilidad_final = (garantia_final - garantia_inicial) / garantia_inicial

# Promedio trimestral de contratos (simulamos que se mantuvo constante)
contratos_trimestrales = []
num_contratos_actual = (capital_cop * exposicion) // ((capital_cop * exposicion) * margen)
for i in range(len(tabla)):
    if i % 3 == 0:
        contratos_trimestrales.append(num_contratos_actual)

cantidad_prom_contratos = float(np.mean(contratos_trimestrales))

# Crear tabla resumen
resumen = pd.DataFrame({
    'Cantidad promedio contratos (trimestre)': [round(cantidad_prom_contratos, 2)],
    'Garantía inicial': [round(garantia_inicial, 2)],
    'PyG liquidaciones': [round(pyg_total, 2)],
    'Rentabilidad PyG / Garantía': [round(rentabilidad_pyg, 4)],
    'Margen final': [round(margen_final, 2)],
    'Suma llamadas de margen': [round(suma_llamadas, 2)],
    'Garantía final': [round(garantia_final, 2)],
    'Rentabilidad final': [round(rentabilidad_final, 4)]
})

resumen
##    Cantidad promedio contratos (trimestre)  ...  Rentabilidad final
## 0                                    15.00  ...                0.77
## 
## [1 rows x 8 columns]
  • Ahora bien, teniendo estos datos nos damos cuenta que nuestra estrategia tanto de cobertura como de Rollover fue exitosa debido a que logramos una rentabilidad del 77% sobre el futuro. No obtuvimos llamadas de margen debido a que cada trimestre logramos acertar con la dirección del futuro (yendonos en corto) y sacar ganancia de ello. En promedio se logro negociar 15 contratos cada trimestre; esto debido a nuestro capital disponible y el margen de garantía dado por la BVC.

Conclusiones finales del credito y su cobertura:

# Crear diccionario con los indicadores como índices
resumen_futuro = {
    "Credito Maquinaria (COP)": monto_solicitado_cop,
    "Total Intereses Pagados (COP)": df_flujo_cop["Interés (COP)"].sum(),
    "Total Pagado Crédito (COP)": df_flujo_cop["Cuota (COP)"].sum(),
    "Garantía Inicial Futuro (COP)": garantia_inicial,
    "Ganancia/Pérdida Futuro (COP)": pyg_total,
    "Resultado Inversión Maquinaria (COP)": df_flujo_cop["Cuota (COP)"].sum() - pyg_total
}

# Convertir a DataFrame
resumen_futuro_df = pd.DataFrame.from_dict(resumen_futuro, orient='index', columns=["Valor (COP)"])

# Formatear con separador de miles sin decimales
resumen_futuro_df.style.format("{:,.0f}")
  Valor (COP)
Credito Maquinaria (COP) 270,000,000
Total Intereses Pagados (COP) 81,431,180
Total Pagado Crédito (COP) 355,808,449
Garantía Inicial Futuro (COP) 204,750,000
Ganancia/Pérdida Futuro (COP) 157,839,653
Resultado Inversión Maquinaria (COP) 197,968,796

:::

  • La cobertura funciono de forma efectiva, a pesar de tener un costo financiero elevado (más de 100M COP sobre el capital prestado), la ganancia del futuro compensó el 89% de ese sobrecosto.

  • Sin cobertura: costo final habría sido 375.8M COP.

  • Con cobertura: el costo neto fue solo 217.99M COP, es decir, una reducción del 42% del costo total del crédito.

La inversión de 204.75M como garantía generó una ganancia de 157.8M → retorno de 77% sobre garantía.Esto muestra un uso inteligente del apalancamiento del derivado para proteger una deuda en moneda extranjera.El resultado demuestra que el portafolio está bien alineado con las condiciones simuladas de mercado, lo cual es señal de una estrategia financiera robusta.

Recomendaciones:

  • Es favorable obtener más datos historicos sobre los contratos de futuro para establecer estrategias con mas certezas y a su vez lograr Rollovers eficiente que vayan a favor de los altibajos que puede presentar el mercado real.

  • Esto fue un ejercicio controlado en el cual se nota el beneficio de los contratos futuros aplicados a la vida real, que con buena data y analísis financieros coherentes se pueden disminuir considerablemente los costos financieros de las compañias.

Referencias: