Fixing QuantLib Bond Curve Fitting by Matching Quotes to Bonds
Summary
The document describes a bond discount-curve fitting error in QuantLib. The questioner supplies bond maturities and coupon rates alongside market prices, then constructs fixed-rate bond helpers for a Nelson–Siegel fitted discount curve. The reported root-bracketing error arises because the code loops over every quote inside each bond-data iteration, pairing each maturity and coupon with all available prices instead of its corresponding price.
The answer fixes the pairing by iterating over the bond records and quotes together, so each helper represents one bond and its matching market quote. It reports that the corrected construction returns a discount factor for a specified date. The example illustrates a data-alignment problem that can make curve fitting fail; the error message alone could otherwise suggest a numerical solver issue. The response does not discuss whether the input bond data, calendar, day-count convention, or fitting method are appropriate for a particular market, so the correction addresses the nested-loop mismatch rather than validating the full curve methodology.
Key ideas
- Each bond’s maturity and coupon should be paired with its corresponding market quote.
- Nesting the quote loop inside the bond-data loop creates many mismatched bond helpers.
- Pairwise iteration over the two input lists fixes the data alignment problem.
- The example reports a discount factor after correcting the helper construction.
- The correction does not validate the selected conventions or curve-fitting method.
Tags
Full text
# Bond Discounting Error With QuantLib
# Bond Discounting Error With QuantLib
I have a list of bond coupons, their maturities and their current price. I want to find their corresponding discount factors. The code I have used is from the QuantLib cookbook, attached below:
```
from QuantLib import *
data = [(13,0.0509),(44,0.0835),(72,0.0815),(124,0.0808),
(150,0.0587),(174,0.0813),(223,0.0396),(263,0.0684),
(374,0.063),(381,0.0737),(412,0.0426),(415,0.0716),
(438,0.0617),(581,0.0448),(604,0.0883),(608,0.0456),
(624,0.0768),(668,0.0732),(814,0.0735),(850,0.084),(
949,0.0618),(959,0.0915)]
today = Date(31,March,2022)
Settings.instance().evaluationDate = today
calendar = India()
settlement = calendar.advance(today, 2, Days)
quotes = [100.02, 100.44 ,100.71 ,101.23 ,100.64 ,101.78 ,99.85,
101.73 ,101.72 ,102.78 ,99.62 ,102.70 ,101.67 ,99.90,
105.95, 99.52 ,104.29 ,104.02 ,104.20 ,106.5,101.90,108.61]
helpers = []
for length, coupon in data:
for quote in quotes:
maturity = calendar.advance(settlement, length, Days)
schedule= Schedule(settlement,maturity,Period(6,Months),
calendar, ModifiedFollowing, ModifiedFollowing,
DateGeneration.Backward, False)
quote = SimpleQuote(quote)
helpers.append(FixedRateBondHelper(QuoteHandle(quote),2, 100,
schedule, [coupon], SimpleDayCounter(), ModifiedFollowing))
curve = FittedBondDiscountCurve(2, calendar, helpers, SimpleDayCounter(), NelsonSiegelFitting())
```
print(curve.discount(Date(30,May,2022)))
I am receiving the following error:
RuntimeError: unable to bracket root in 100 function evaluations (last bracket attempt: f[-2.29538e+25,5.968e+25] -> [-nan(ind),102.804])
Unable to understand what the issue is. Hope someone can help me out.
Thanks, Goutham
## Answer by lampishthing (score 3)
https://quant.stackexchange.com/a/70602
Your quotes loop is nested inside your data loop, instead of doing both at the same time. You need to zip them together like so:
```
from QuantLib import *
data = [(13,0.0509),(44,0.0835),(72,0.0815),(124,0.0808),
(150,0.0587),(174,0.0813),(223,0.0396),(263,0.0684),
(374,0.063),(381,0.0737),(412,0.0426),(415,0.0716),
(438,0.0617),(581,0.0448),(604,0.0883),(608,0.0456),
(624,0.0768),(668,0.0732),(814,0.0735),(850,0.084),(
949,0.0618),(959,0.0915)]
today = Date(31,March,2022)
Settings.instance().evaluationDate = today
calendar = India()
settlement = calendar.advance(today, 2, Days)
quotes = [100.02, 100.44 ,100.71 ,101.23 ,100.64 ,101.78 ,99.85,
101.73 ,101.72 ,102.78 ,99.62 ,102.70 ,101.67 ,99.90,
105.95, 99.52 ,104.29 ,104.02 ,104.20 ,106.5,101.90,108.61]
helpers = []
for (length, coupon), quote in zip(data, quotes):
maturity = calendar.advance(settlement, length, Days)
schedule= Schedule(settlement,maturity,Period(6,Months),
calendar, ModifiedFollowing, ModifiedFollowing,
DateGeneration.Backward, False)
quote = SimpleQuote(quote)
helpers.append(FixedRateBondHelper(QuoteHandle(quote),2, 100,
schedule, [coupon], SimpleDayCounter(), ModifiedFollowing))
curve = FittedBondDiscountCurve(2, calendar, helpers, SimpleDayCounter(), NelsonSiegelFitting())
print(curve.discount(Date(30,May,2022)))
```
giving: 0.9919014655606289Shown 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.