|
From: Marcin R. <mry...@gm...> - 2025-05-19 08:00:10
|
Hi Henry,
The FX forward formula seems incorrect. Additionally, you need to calculate
the forwards on the nodes of the MXN curve, and correct for the spot date.
Something like this:
# ====== Step 6: Calculate implied forward rates ======
print("\nImplied Forward USD/MXN Rates:")
fx_spot_date = fx_calendar.advance(today, fixing_days, ql.Days, convention,
end_of_month)
for node, _ in mxn_curve.nodes()[1:]:
# Calculate implied forward rate
usd_discount = usd_curve.discount(node)
usd_discount_spot = usd_curve.discount(fx_spot_date)
mxn_discount = mxn_curve.discount(node)
mxn_discount_spot = mxn_curve.discount(fx_spot_date)
fwd_fx = spot_fx_usdmxn * (usd_discount / mxn_discount) * (
mxn_discount_spot / usd_discount_spot)
points = (fwd_fx - spot_fx_usdmxn) * 10000 # Convert to pips
print(f"{node}: {fwd_fx:.4f} (Points: {points:.1f})")
Hope this helps.
Cheers,
Marcin
On Sat, 17 May 2025 at 14:39, Henry Wu Hu <hen...@gm...> wrote:
> Hello. I am trying to get implied fx forward using the FxRateSwapHelper.
> Some how I am not able to get the same fx forward points when comparing
> with the input.
>
> Am I missing something? All help is appreciated
>
> Thanks in advanced.
>
>
> import QuantLib as ql
> import datetime as dt
> import numpy as np
> import pandas as pd
>
> # Set evaluation date
> today = ql.Date(16, 5, 2025) # May 16, 2025
> ql.Settings.instance().evaluationDate = today
>
> # ====== Step 1: Define market data ======
> # USD yield curve data (assuming we already have this)
> usd_rate_dates = [
> today + ql.Period("1D"),
> today + ql.Period("1W"),
> today + ql.Period("1M"),
> today + ql.Period("3M"),
> today + ql.Period("6M"),
> today + ql.Period("1Y"),
> today + ql.Period("2Y"),
> today + ql.Period("5Y")
> ]
>
> usd_rates = [0.0520, 0.0525, 0.0530, 0.0535, 0.0540, 0.0550, 0.0560,
> 0.0570] # Sample rates
>
> # FX Spot USDMXN rate
> spot_fx_usdmxn = 17.8500 # USD/MXN spot rate
>
> # FX Swap points for different tenors (market quotes in pips)
> fx_swap_tenors = [ql.Period("1M"), ql.Period("3M"), ql.Period("6M"),
> ql.Period("1Y")]
> fx_swap_points = [125, 375, 825, 1750] # Sample swap points in pips
>
> # ====== Step 2: Set up USD curve (base/collateral currency) ======
> usd_day_count = ql.Actual360()
> usd_calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond)
> usd_interpolation = ql.Linear()
> usd_compounding = ql.Compounded
> usd_compounding_freq = ql.Semiannual
>
> # Create USD deposit rate helpers
> usd_rate_helpers = []
> for rate, maturity in zip(usd_rates, usd_rate_dates):
> if maturity <= today + ql.Period("1Y"): # For maturities up to 1Y
> days_to_maturity = (maturity - today)
> usd_rate_helpers.append(
> ql.DepositRateHelper(
> ql.QuoteHandle(ql.SimpleQuote(rate)),
> ql.Period(days_to_maturity, ql.Days),
> 2, # fixing days
> usd_calendar,
> ql.ModifiedFollowing,
> False,
> usd_day_count
> )
> )
> else: # For longer maturities, assume we're using swap rates
> tenor_length = (maturity - today) / 365 # Approximate in years
> usd_rate_helpers.append(
> ql.SwapRateHelper(
> ql.QuoteHandle(ql.SimpleQuote(rate)),
> ql.Period(int(tenor_length), ql.Years),
> usd_calendar,
> ql.Semiannual,
> ql.ModifiedFollowing,
> usd_day_count,
> ql.Euribor6M() # Example index, in reality would use
> appropriate USD index
> )
> )
>
> # Build USD curve
> usd_curve = ql.PiecewiseLinearZero(
> today, usd_rate_helpers, usd_day_count
> )
> usd_curve_handle = ql.YieldTermStructureHandle(usd_curve)
>
> # ====== Step 3: Set up FX swap rate helpers for MXN curve ======
> mxn_calendar = ql.Mexico()
> # In FX markets, typically both calendars are considered
> fx_calendar = ql.JointCalendar(usd_calendar, mxn_calendar)
> fixing_days = 2 # Standard for FX markets
> convention = ql.Following
> end_of_month = False
> # In USD/MXN, USD is the base currency, and if using USD as collateral:
> is_fx_base_currency_collateral_currency = True
>
> # Create FX swap rate helpers
> fx_swap_helpers = []
> for tenor, points in zip(fx_swap_tenors, fx_swap_points):
> # Convert swap points from pips to decimal
> swap_point_decimal = points / 10000.0
>
> fx_swap_helpers.append(
> ql.FxSwapRateHelper(
> ql.QuoteHandle(ql.SimpleQuote(swap_point_decimal)),
> ql.QuoteHandle(ql.SimpleQuote(spot_fx_usdmxn)),
> tenor,
> fixing_days,
> fx_calendar,
> convention,
> end_of_month,
> is_fx_base_currency_collateral_currency,
> usd_curve_handle
> )
> )
>
> # ====== Step 4: Build MXN curve ======
> mxn_day_count = ql.Actual360()
> mxn_curve = ql.PiecewiseLinearZero(
> today, fx_swap_helpers, mxn_day_count
> )
>
> # ====== Step 5: Analyze the results ======
> print(f"Evaluation date: {today.ISO()}")
> print(f"USD/MXN Spot Rate: {spot_fx_usdmxn}")
> print("\nUSD Zero Rates:")
> for date, rate in zip(usd_rate_dates, usd_rates):
> days = (date - today)
> print(f"{days} days: {rate*100:.4f}%")
>
> print("\nImplied MXN Zero Rates:")
> for tenor in fx_swap_tenors:
> date = today + tenor
> mxn_zero_rate = mxn_curve.zeroRate(
> date, mxn_day_count, ql.Continuous).rate()
> print(f"{tenor}: {mxn_zero_rate*100:.4f}%")
>
> # ====== Step 6: Calculate implied forward rates ======
> print("\nImplied Forward USD/MXN Rates:")
> for tenor in fx_swap_tenors:
> date = today + tenor
> # Calculate implied forward rate
> usd_discount = usd_curve.discount(date)
> mxn_discount = mxn_curve.discount(date)
> fwd_fx = spot_fx_usdmxn * (mxn_discount / usd_discount)
>
> points = (fwd_fx - spot_fx_usdmxn) * 10000 # Convert to pips
> print(f"{tenor}: {fwd_fx:.4f} (Points: {points:.1f})")
>
> Best Regards
> Henry Wu Hu
> _______________________________________________
> QuantLib-users mailing list
> Qua...@li...
> https://lists.sourceforge.net/lists/listinfo/quantlib-users
>
|