Esta es solo una extensión de la respuesta de @Dimitri pero con números para elucidar el concepto.
cuando se fija el precio de un FX-Forward GBPUSD construimos la curva USD SOFR a través de la cual obtenemos la tasa de interés libre de riesgo en USD. Para la tasa libre de riesgo en GBP, usamos la suma de la base GBPUSD y SONIA.
Sí, eso es correcto. Supongamos que la tasa USD a 1 año es del 5% y la tasa GBP es del 3% y la base es de -25bps, con GBPUSD en 1.25, entonces el forward de 1 año que esperas aproximadamente es:
$$ 1.25 * \frac{1 + 5\%}{1 + 3\% -25bps} = 1.2773 $$
En la práctica construirás una curva USD, una curva GBP y una curva de base. Las curvas USD y GBP se pueden construir por separado, en sus mercados de tasas locales.
## Python: from rateslib import *
usdusd = Curve({dt(2023, 11, 24): 1.0, dt(2024, 11, 30): 1.0}, convention="act360")
gbpgbp = Curve({dt(2023, 11, 24): 1.0, dt(2024, 11, 30): 1.0}, convention="act365f")
solver = Solver(
curves=[usdusd, gbpgbp], # calibrar estas curvas
instruments=[
IRS(dt(2023, 11, 24), "1Y", spec="usd_irs", curves=usdusd),
IRS(dt(2023, 11, 24), "1Y", spec="gbp_irs", curves=gbpgbp)
],
s=[5.0, 3.0], # estas son las tasas
id="rates 1",
instrument_labels=["US1Y", "GB1Y"]
)
El mercado de divisas cruzadas necesita conocer los tipos de cambio de divisas
gbpusd = Curve({dt(2023, 11, 24): 1.0, dt(2024, 11, 30): 1.0}, convention="act365f")
fxf = FXForwards(
fx_rates=FXRates({"gbpusd": 1.25}, settlement=dt(2023, 11, 24)),
fx_curves={"usdusd": usdusd, "gbpgbp": gbpgbp, "gbpusd": gbpusd},
)
solver2 = Solver(
curves=[gbpusd], # calibrar esta curva
pre_solvers=[solver], # con conocimiento de curvas preexistentes
instruments=[
XCS(dt(2023, 11, 24), "1Y", spec="gbpusd_xcs", curves=[gbpgbp, gbpusd, usdusd, usdusd]),
],
s=[-25.0],
id="gbpusd",
fx=fxf,
)
Entonces, al configurar estas Curvas y calibrarlas al mercado se ha creado un marco preciso y libre de arbitraje de FX Forward. Podemos usarlo para fijar el precio del forward de 1 año de GBPUSD, cerca del cálculo aproximado anterior.
fxf.rate("gbpusd", dt(2024, 11, 24))
# 1.278262
Sin embargo, si estamos valorando un Forward para algo como GBPEUR, ¿cómo usamos una base GBPUSD y la base USDEUR para lograr nuestro objetivo? Básicamente, ¿cómo incorporamos el riesgo de divisas cruzadas en la valoración de FX-Forwards para este tipo de divisas?
Bueno, ahora podemos extender y repetir esto para USDEUR. Supongamos que la tasa EUR a 1 año es del 4% y la base es +25bps, entonces esperamos.
$$ 1.10 * \frac{1+5\%}{1+4\%+25bps} = 1.1079 $$
eureur = Curve({dt(2023, 11, 24): 1.0, dt(2024, 11, 30): 1.0}, convention="act360")
eurusd = Curve({dt(2023, 11, 24): 1.0, dt(2024, 11, 30): 1.0}, convention="act360")
fxf = FXForwards(
fx_rates=FXRates({"gbpusd": 1.25, "eurusd": 1.10}, settlement=dt(2023, 11, 24)),
fx_curves={"usdusd": usdusd,"gbpgbp": gbpgbp,"gbpusd": gbpusd,"eureur": eureur,"eurusd": eurusd},
)
solver3 = Solver(
curves=[eureur, eurusd], # calibrar estas curvas
pre_solvers=[solver2], # con conocimiento de curvas preexistentes
instruments=[
IRS(dt(2023, 11, 24), "1y", spec="eur_irs", curves=eureur),
XCS(dt(2023, 11, 24), "1Y", spec="eurusd_xcs", curves=[eureur, eurusd, usdusd, usdusd]),
],
s=[4.0, 25.0],
id="eur",
instrument_labels=["EU1Y", "eurusd"],
fx=fxf,
)
fxf.rate("eurusd", dt(2024, 11, 24))
# 1.107949
Esto ha creado ahora un marco de FX Forwards que contiene conocimiento de mercado para cualquiera de las tres monedas y puede producir curvas de descuento versus cualquier moneda de garantía debido a los principios de no arbitraje. En tu caso, luego descontarías los flujos de tus transacciones forward usando la curva de descuento apropiada y podrías convertir el VPN de cada pierna a tu moneda contable preferida.
En particular, estás interesado en el forward de GBPEUR.
$$ GBPEUR = GBPUSD * USDEUR = \frac{GBPUSD}{EURUSD} \\ GBPEUR = \frac{1.25}{1.10} \frac{1 + 4\% +25bps}{1+3\% -25bps} = 1.1529 $$
fxf.rate("gbpeur", dt(2024, 11, 24))
# 1.153790 # la diferencia se debe a ACT360 v ACT365F en caso de que te lo estés preguntando