Skip to content
All library documents

Diagnosing QuantLib Swap Curve Bootstrap Failures from Rate Units

Article Quant Q&A · Author: euri10

Summary

This exchange explains why adding a five-year euro swap quote causes a QuantLib yield curve bootstrap to fail. The key issue is quote units: rates expressed as percentages must be converted to decimal form before being supplied to the helpers. The example’s swap quotes were entered as values such as 0.2331 for 23.31%, although the intended rate was 0.2331%. The resulting implausibly high long-dated rates prevent the solver from finding a bracketed root.

The accepted answer recommends correcting the units for both deposits and swaps, after which the curve should bootstrap as expected. This is a focused debugging lesson rather than a general treatment of curve construction. It does not examine other possible causes of bootstrap failures or provide independent validation across market data sets.

Key ideas

  • Interest rates supplied as percentages must be represented as decimal fractions when the library expects decimals.
  • The sample quotes mistakenly interpret percentage values as whole rates, making long-term rates extreme.
  • A failed root search can result from inconsistent or incorrectly scaled market quotes.
  • The same unit check should be applied to deposit quotes as well as swap quotes.

Tags

Full text
# Quantlib bootstraping fails on 5y swap


# Quantlib bootstraping fails on 5y swap












I'm trying to build a euro swap curve with real up to date data. I should say that examples provided in github work fine. as soon as I add the 5y swap, I got the following error :

```
RuntimeError: 1st iteration: failed at 14th alive instrument, maturity September 28th, 2020, reference date September 28th, 2015: root not bracketed: f[-1,1] -> [3.260558e-001,5.904525e-002]
```

edit (error with error lines) :

```
RuntimeError: void __thiscall QuantLib::IterativeBootstrap<class QuantLib::PiecewiseYieldCurve<struct QuantLib::ForwardRate,class QuantLib::BackwardFlat,class QuantLib::IterativeBootstrap> >::calculate(void) const: 
  d:\PycharmProjects\quantlib\QuantLib\ql/termstructures/iterativebootstrap.hpp(217): 
1st iteration: failed at 14th alive instrument, maturity September 28th, 2020, reference date September 28th, 2015: double __thiscall QuantLib::Solver1D<class QuantLib::Brent>::solve<class QuantLib::BootstrapError<class QuantLib::PiecewiseYieldCurve<struct QuantLib::ForwardRate,class QuantLib::BackwardFlat,class QuantLib::IterativeBootstrap> >>(const class QuantLib::BootstrapError<class QuantLib::PiecewiseYieldCurve<struct QuantLib::ForwardRate,class QuantLib::BackwardFlat,class QuantLib::IterativeBootstrap> > &,double,double,double,double) const: 
  d:\PycharmProjects\quantlib\QuantLib\ql/math/solver1d.hpp(202): 
root not bracketed: f[-1,1] -> [3.260558e-001,5.904525e-002]
```

I have to say that I get no error if I remove the 5y swap. I have QL_NEGATIVE_RATES in userconfig.hpp that isn't commented.

the piece of code I'm using is here.

thanks

```
import QuantLib as ql
import datetime

calendar = ql.TARGET()
settlementDays = 2
now = datetime.datetime.now()
today = calendar.adjust(ql.Date(now.day, now.month, now.year))
ql.Settings.instance().evaluationDate = today
settlementDate = calendar.advance(today, settlementDays, ql.Days)

# market quotes
deposits = {(1, ql.Weeks): -0.141,
            (1, ql.Months): -0.107,
            (2, ql.Months): -0.066,
            (3, ql.Months): -0.039,
            (6, ql.Months): 0.033,
            (9, ql.Months): 0.083,
            (12, ql.Months): 0.147}

futures = {ql.Date(16, 3, 2016): 100.045,
           ql.Date(15, 6, 2016): 100.055,
           ql.Date(21, 9, 2016): 100.06,
           ql.Date(21, 12, 2016): 100.055,
           ql.Date(15, 3, 2017): 100.04}

swaps = {(2, ql.Years): 0.0557,
         (3, ql.Years): 0.1275,
         (4, ql.Years): 0.2331,
         #(5, ql.Years): 0.3523
         }

# convert them to Quote objects
for n, unit in deposits.keys():
    deposits[(n, unit)] = ql.SimpleQuote(deposits[(n, unit)])
for d in futures.keys():
    futures[d] = ql.SimpleQuote(futures[d])
for n, unit in swaps.keys():
    swaps[(n, unit)] = ql.SimpleQuote(swaps[(n, unit)])

dayCounter = ql.Actual360()

depositHelpers = [
    ql.DepositRateHelper(ql.QuoteHandle(deposits[(n, unit)]), ql.Period(n, unit), settlementDays, calendar,
                         ql.ModifiedFollowing, False, dayCounter) for n, unit in sorted(deposits.iterkeys())]

dayCounter = ql.Actual360()

futuresHelpers = [
    ql.FuturesRateHelper(ql.QuoteHandle(futures[d]), d, 3, calendar, ql.ModifiedFollowing, True, dayCounter,
                         ql.QuoteHandle(ql.SimpleQuote(0.0))) for d in sorted(futures.keys())]

settlementDays = 2
fixedLegFrequency = ql.Annual
fixedLegTenor = ql.Period(1, ql.Years)
fixedLegAdjustment = ql.Unadjusted
fixedLegDayCounter = ql.Thirty360()
floatingLegFrequency = ql.Semiannual
floatingLegTenor = ql.Period(6, ql.Months)
floatingLegAdjustment = ql.ModifiedFollowing

swapHelpers = [ql.SwapRateHelper(ql.QuoteHandle(swaps[(n, unit)]), ql.Period(n, unit), calendar, fixedLegFrequency,
                                 fixedLegAdjustment, fixedLegDayCounter, ql.Euribor6M()) for n, unit in
               swaps.keys()]

# term structure handles

discountTermStructure = ql.RelinkableYieldTermStructureHandle()
forecastTermStructure = ql.RelinkableYieldTermStructureHandle()

def printHelper(x):
    print('{} | {}'.format(x.latestDate(), x.quote().value()))

def printH(t):
    print('\n======')
    print t
    for i in list(t):
        printHelper(i)

printH(depositHelpers)
printH(futuresHelpers)
printH(swapHelpers)

helpers = depositHelpers[:-2] + futuresHelpers + swapHelpers
printH(helpers)

depoFuturesSwapCurve = ql.PiecewiseFlatForward(settlementDate, helpers, ql.Actual360())

print depoFuturesSwapCurve.dates()

for c in depoFuturesSwapCurve.dates():
    print depoFuturesSwapCurve.discount(c)
```

## Answer by Luigi Ballabio (score 7, accepted)

https://quant.stackexchange.com/a/20893

You're not the first to trip on this, and unfortunately the fact that the provided example is from a different era doesn't help.

Quite simply, you're not writing rates correctly. The 5-years swap rate, 0.3523%, must be written in decimal form as 0.003523. The same goes for the deposit rates.

As your code is now, you're writing that the 4-years rate is 23.31% and the 5-years rate is 35.23%, and the bootstrap code fails to find a solution that accounts for the extreme variation.

Writing the rates correctly should allow you to bootstrap the curve as expected.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.