1
$\begingroup$

I'm attempting to calculate a GBP yield curve using a USD OIS rate curve and the FX Forward rates using Quantlib. I am trying to replicate the output of a different library, and am close but can't seem to quite get it right.

Firstly, bootstrapping the USD yield curve from the OIS swap rates:

# Set the calculation date
start_date = ql.Date(1, 2, 2024)
ql.Settings.instance().evaluationDate = start_date


# Define calendar
calendar = ql.UnitedStates(0)
convention = ql.Following
endOfMonth = False
spot_date = calendar.advance(start_date, 2, ql.Days)

# Fixed leg payment frequency and conventions
fixed_frequency = ql.Annual
fixed_day_count = ql.Actual360()  
fixed_convention = convention
fixed_payment_convention = convention

# Rule for generating the schedule
rule = ql.DateGeneration.Backward

# Define the overnight index as Fed Funds
overnight_index = ql.FedFunds()

# Market data for OIS rates and their specific maturity dates
maturity_dates = ois_data["end_date"].to_list()  # Specific maturity dates
ois_rates = ois_data["Value"].to_list()  # Corresponding OIS rates

# Create OIS Rate Helpers with specific maturity dates for the Fed Funds rate
ois_helpers = [
    ql.OISRateHelper(
        2,
        ql.Period(maturity_date - spot_date, ql.Days),
        ql.QuoteHandle(ql.SimpleQuote(rate)),
        overnight_index,
        paymentLag=0,
        paymentFrequency=fixed_frequency,
        paymentConvention=fixed_payment_convention,
        paymentCalendar=calendar,
        endOfMonth=endOfMonth,
    )
    for rate, maturity_date in zip(ois_rates, maturity_dates)
]

# Bootstrap the OIS curve
day_count = ql.Actual365Fixed()
ois_curve = ql.PiecewiseLogLinearDiscount(start_date, ois_helpers, day_count)
usd_yield_curve = ql.YieldTermStructureHandle(ois_curve)

When I compare the discount factors, I am getting the correct figures.

Next, I attempt to bootstrap the GBP yield curve:

fx_prices = fx_fwd["Value"].tolist()
settlement_dates = fx_fwd["Settlement Date"].dt.date.tolist()
joint_calendar = ql.JointCalendar(
    ql.UnitedKingdom(), calendar, ql.JoinHolidays
)
rate_helpers = [
    ql.FxSwapRateHelper(
        ql.QuoteHandle(ql.SimpleQuote(price - spot_price)),
        ql.QuoteHandle(ql.SimpleQuote(spot_price)),
        ql.Period(ql.Date.from_date(settlement_date) - start_date, ql.Days),
        0,
        joint_calendar,
        ql.ModifiedFollowing,
        True,
        False,
        usd_yield_curve,
    )
    for price, settlement_date in zip(fx_prices, settlement_dates)
]

# Bootstrap the OIS curve
day_count = ql.Actual365Fixed()
# day_count = ql.Actual360()
gbp_curve = ql.PiecewiseFlatForward(start_date, rate_helpers, day_count)
gbp_yield_curve = ql.YieldTermStructureHandle(gbp_curve)

This time when I plot the discount factors, compared with the other library, they are different. Only by between 1-50 bp, but that is enough to throw off instrument pricing further down the line when using these yield curves.

I've tried a few different iterations of the arguments to the helpers but can't seem to get it to work. Any help would be really appreciated.

$\endgroup$
1
  • $\begingroup$ Would it be possible for you to share the data points along with the corresponding resulting curve in another software? It would be even more helpful if you could also provide the configuration used in that software. This would facilitate our ability to assist you effectively. $\endgroup$
    – Xiarpedia
    Commented Feb 10 at 10:41

1 Answer 1

0
$\begingroup$

While there is not enough information in the question to answer exactly what is asked (it might be the other library giving the wrong answer, we don't have the data, etc), I suggest debugging this from the first principles.

Luckily the setup here is very simple - in the sense that if you compute forward FX values by hand (as ratio of discount factors) on FX swap maturity dates you can then immediately compare these to your FX swap quotes. This will very quickly tell you which of the two libraries is giving the wrong answer (might be both!) and also should give you some clues as to why.

$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.