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.