Skip to content
All library documents

Finding Bond Yield with QuantLib and a Root Solver

Article Quant Q&A · Author: Kirill Dolmatov

Summary

The document explains how to calculate a bond’s yield from its price and coupon cash flows using QuantLib. One approach defines a function that reprices the bond at a trial yield and returns the difference from the target price; a bisection solver then finds the yield where that difference reaches zero. The solver’s first argument is this function, which answers the question about the Python object expected by the interface.

The answer also points out that QuantLib already provides a bond-yield method, so a custom solver is usually unnecessary. It stresses an important pricing convention: the target passed to that method should be the clean price, rather than the bond’s net present value. The example is educational and notes that its illustrative function has not been tested. Correct results still depend on matching the bond’s day-count convention, compounding, frequency, and price basis.

Key ideas

  • A root solver needs a function that returns the pricing error for a trial yield.
  • Bisection finds the yield where the pricing error is zero within the chosen bracket.
  • QuantLib bond objects provide a built-in yield calculation for common use.
  • The built-in method expects a clean price as its target.

Tags

Full text
# How to calculate bond yield in QuantLib - Python


# How to calculate bond yield in QuantLib - Python












I want to calculate yield of bond having market price and coupons. I try to replicate C++ from (https://mhittesdorf.wordpress.com/2013/03/03/introducing-quantlib-internal-rate-of-return/) in Python but without success. How to use "bisection" solver in quantlib-python?

```
solver = ql.Bisection()
solver_max = 0.5
solver_min = 0.1
solver_maxEvaluations = 1000 
solution = solver.solve(?, solver_maxEvaluations, solver_min, solver_max)
```

> NotImplementedError: Wrong number or type of arguments for overloaded function 'Bisection_solve'. Possible C/C++ prototypes are: Bisection::solve(PyObject *,Real,Real,Real) Bisection::solve(PyObject *,Real,Real,Real,Real)

What is the "PyObject*" in this case?

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

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

In the call to `Bisection.solve`, the question mark must be the Python function whose zero you want to find. In your case, it should be something reproducing the logic of `IRRSolver::operator()` in Mick Hittesdorf's code, i.e., something like this (which I haven't tested):

```
cashflows = fixedRateBond.cashflows()
npv = fixedRateBond.NPV()
def price_error_given_yield(rate):
    interestRate = InterestRate(rate, ActualActual(ActualActual.Bond),
                                Compounded, Annual)
    return CashFlows.npv(cashflows, interestRate, False) - npv

irr = solver.solve(price_error_given_yield, accuracy, guess, min, max)
```

The idea is that you write a function that takes a yield and tells you how much the corresponding price differs from the target price; the solver takes the function and returns its zero, that is, the value of the input yield for which the result (i.e. the difference from the target price) is zero.

This said, Mick's approach is useful for educational purposes but it duplicates functionality that is already available from the bond object. All you need is to call

```
fixedRateBond.bondYield(targetPrice, ActualActual(ActualActual.Bond),
                        Compounded, Annual)
```

Note, though, that the `targetPrice` above should be the clean price, so in your case what's returned by `fixedRateBond.cleanPrice()` rather than `fixedRateBond.NPV()`.

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.