2
$\begingroup$

The Bloomberg USD OIS discount factors for 2024-03-01 do not match the values calculated using Quantlib beyond the 18M tenor. What do I need to do get them to match?

Sorry, I am unable to paste a screenshot from the Bloomberg terminal.

My code is as follows:

import typing
import datetime
import math
import pandas
import QuantLib


if __name__ == "__main__":
    day_counter: QuantLib.DayCounter = QuantLib.Actual360()
    calendar: QuantLib.Calendar = QuantLib.UnitedStates(QuantLib.UnitedStates.FederalReserve)
    reference_date: QuantLib.Date = QuantLib.Date(1, 3, 2024)
    settlement_date: QuantLib.Date = calendar.advance(reference_date, QuantLib.Period(2, QuantLib.Days))
    QuantLib.Settings.instance().evaluationDate = reference_date
    overnightIndex: QuantLib.FedFunds = QuantLib.FedFunds()

    # Bloomberg USD OIS Swap rates
    swaps: typing.Mapping[QuantLib.Period, float] = {
        QuantLib.Period("1W"): 5.33000,
        QuantLib.Period("2W"): 5.33260,
        QuantLib.Period("3W"): 5.33300,
        QuantLib.Period("1M"): 5.33535,
        QuantLib.Period("2M"): 5.34110,
        QuantLib.Period("3M"): 5.33440,
        QuantLib.Period("4M"): 5.30550,
        QuantLib.Period("5M"): 5.27900,
        QuantLib.Period("6M"): 5.24035,
        QuantLib.Period("9M"): 5.12030,
        QuantLib.Period("1Y"): 4.98700,
        QuantLib.Period("18M"): 4.65575,
        QuantLib.Period("2Y"): 4.43105,
        QuantLib.Period("3Y"): 4.13593,
        QuantLib.Period("4Y"): 3.97872,
        QuantLib.Period("5Y"): 3.88900,
        QuantLib.Period("6Y"): 3.83837,
        QuantLib.Period("7Y"): 3.80548,
        QuantLib.Period("8Y"): 3.78547,
        QuantLib.Period("9Y"): 3.77427,
        QuantLib.Period("10Y"): 3.76773,
        QuantLib.Period("12Y"): 3.76733,
        QuantLib.Period("15Y"): 3.77146,
        QuantLib.Period("20Y"): 3.73336,
        QuantLib.Period("25Y"): 3.64168,
        QuantLib.Period("30Y"): 3.54345,
        QuantLib.Period("40Y"): 3.33623,
        QuantLib.Period("50Y"): 3.11935
    }
    ois_helpers: typing.List[QuantLib.OISRateHelper] = [
        QuantLib.OISRateHelper(
            settlementDays=2,
            tenor=tenor,
            rate=QuantLib.QuoteHandle(QuantLib.SimpleQuote(rate / 100)),
            index=overnightIndex,
        )
        for tenor, rate in swaps.items()
    ]

    curve: QuantLib.PiecewiseLogLinearDiscount = QuantLib.PiecewiseLogLinearDiscount(0, calendar, ois_helpers, QuantLib.Actual360())
    tenors: typing.List[QuantLib.Period] = []
    rates: typing.List[float] = []
    maturity_dates: typing.List[datetime.date] = []
    zero_rates: typing.List[float] = []
    discount_factors: typing.List[float] = []
    for tenor, rate in swaps.items():
        tenors.append(tenor)
        rates.append(rate)
        maturity_date: QuantLib.Date = calendar.advance(settlement_date, tenor, QuantLib.ModifiedFollowing, True)
        maturity_dates.append(datetime.date(maturity_date.year(), maturity_date.month(), maturity_date.dayOfMonth()))
        discount_factor: float = curve.discount(maturity_date)
        discount_factors.append(discount_factor)
        zero_rate: float = -100.0 * math.log(discount_factor) * 365.0 / (maturity_date - reference_date)
        zero_rates.append(zero_rate)

    result: pandas.DataFrame = pandas.DataFrame(
        data={
            "Tenor": tenors,
            "Maturity Date": maturity_dates,
            "Market Rate": rates,
            "Zero Rate": zero_rates,
            "Discount": discount_factors,
            "Bloomberg Discount": [
                0.998374,
                0.997340,
                0.996309,
                0.994838,
                0.990299,
                0.985967,
                0.981757,
                0.977478,
                0.973338,
                0.961789,
                0.951308,
                0.932241,
                0.915541,
                0.884058,
                0.853814,
                0.824673,
                0.795974,
                0.768084,
                0.740793,
                0.714084,
                0.688356,
                0.638668,
                0.570186,
                0.477321,
                0.409793,
                0.357900,
                0.288171,
                0.250724
            ]
        }
    )
    result["Discount Difference"] = round(result["Discount"] - result["Bloomberg Discount"], 6)
    print(result.to_string(index=False))

The output is as follows:

Tenor Maturity Date  Market Rate  Zero Rate  Discount  Bloomberg Discount  Discount Difference
   1W    2024-03-12      5.33000   5.401229  0.998374            0.998374            -0.000000
   2W    2024-03-19      5.33260   5.401102  0.997340            0.997340            -0.000000
   3W    2024-03-26      5.33300   5.399085  0.996309            0.996309            -0.000000
   1M    2024-04-05      5.33535   5.397540  0.994838            0.994838            -0.000000
   2M    2024-05-06      5.34110   5.391176  0.990299            0.990299            -0.000000
   3M    2024-06-05      5.33440   5.373175  0.985967            0.985967             0.000000
   4M    2024-07-05      5.30550   5.333618  0.981757            0.981757            -0.000000
   5M    2024-08-05      5.27900   5.295914  0.977478            0.977478            -0.000000
   6M    2024-09-05      5.24035   5.246586  0.973338            0.973338             0.000000
   9M    2024-12-05      5.12030   5.096887  0.961789            0.961789             0.000000
   1Y    2025-03-05      4.98700   4.937667  0.951308            0.951308            -0.000000
  18M    2025-09-05      4.65575   4.631071  0.932241            0.932241             0.000000
   2Y    2026-03-05      4.43105   4.388100  0.915538            0.915541            -0.000003
   3Y    2027-03-05      4.13593   4.092998  0.884053            0.884058            -0.000005
   4Y    2028-03-06      3.97872   3.935097  0.853806            0.853814            -0.000008
   5Y    2029-03-05      3.88900   3.845092  0.824662            0.824673            -0.000011
   6Y    2030-03-05      3.83837   3.794754  0.795961            0.795974            -0.000013
   7Y    2031-03-05      3.80548   3.762279  0.768070            0.768084            -0.000014
   8Y    2032-03-05      3.78547   3.743008  0.740777            0.740793            -0.000016
   9Y    2033-03-07      3.77427   3.732890  0.714067            0.714084            -0.000017
  10Y    2034-03-06      3.76773   3.727594  0.688339            0.688356            -0.000017
  12Y    2036-03-05      3.76733   3.730669  0.638652            0.638668            -0.000016
  15Y    2039-03-07      3.77146   3.739299  0.570172            0.570186            -0.000014
  20Y    2044-03-07      3.73336   3.692611  0.477288            0.477321            -0.000033
  25Y    2049-03-05      3.64168   3.565595  0.409681            0.409793            -0.000112
  30Y    2054-03-05      3.54345   3.423741  0.357667            0.357900            -0.000233
  40Y    2064-03-05      3.33623   3.112584  0.287588            0.288171            -0.000583
  50Y    2074-03-05      3.11935   2.773300  0.249608            0.250724            -0.001116
$\endgroup$
3
  • $\begingroup$ Anything to do with hol calendars and US Labor day on Mon 1st Sep 2025? $\endgroup$
    – Attack68
    Apr 18 at 17:08
  • $\begingroup$ Your post seems to include an incomplete sentence or paragraph: "Sorry, I am unable to paste a screenshot from t". $\endgroup$
    – Alper
    Apr 18 at 17:49
  • $\begingroup$ The maturity dates match those reported by Bloomberg. So, I don't think this is an issue with regard to holidays. I corrected the incomplete sentence. $\endgroup$
    – scorpio
    Apr 18 at 21:13

1 Answer 1

2
$\begingroup$

I think this may be an issue with Bloomberg rounding its values and not displaying exactly what it is using as input or possibly that the Bloomberg "Step Forward (Cont)" does something that is not exactly equal to the log-linear interpolation of discount factors at the Maturity dates.

Your cross posted issue at Rateslib https://github.com/attack68/rateslib/issues/145 shows that Quantlib and Rateslib, which are both implenting log-linear interpolations on the same market data are almost equal.

So here the outlier seems to be Bloomberg, if two other independent sources converge on the same answer.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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