Skip to content
All library documents

Building and Valuing Amortizing Loan Cash Flows in QuantLib

Article Quant Q&A · Author: egor_zhev

Summary

The document discusses representing a fixed-rate, amortizing loan in QuantLib when a built-in loan or mortgage class is not apparent. The response constructs a fixed-rate bond for coupon payments, adds an initial amortizing payment for the loan principal, and combines these cash flows into a leg. For loans with principal repayments over time, it points to the amortizing fixed-rate bond class.

It then shows how to value the resulting leg using a yield-curve handle and QuantLib’s cash-flow NPV function. The example supplies dates, a calendar, nominal amount, payment frequency, day-count convention, coupon, and a flat discount curve, along with the resulting cash-flow amounts and NPV. The discussion illustrates one fixed-rate setup; it does not explain a floating-rate implementation, resolve the original day-count concern in depth, or compare alternative loan schedules and conventions. Those details must be matched to the instrument being modeled.

Key ideas

  • A loan’s cash flows can be represented as a leg combining principal and coupon payments.
  • A fixed-rate bond can supply scheduled coupon cash flows, with an initial principal payment added for a loan structure.
  • QuantLib provides an amortizing fixed-rate bond class for loans with principal repayments over time.
  • A yield-term-structure handle and the cash-flow NPV function can discount and value the leg.
  • The example covers a fixed-rate case and does not supply a floating-rate construction.

Tags

Full text
# Quantlib: loan cash flow


# Quantlib: loan cash flow












Situation: I would like to make a small script which prices loans (fe annuities or fixed payment) for the ALM purposes. However, I am stuck in the amount of classes existing in Quantlib and would like to understand how to do it properly.

Say I have a simple loan with calendar and fixed interest, which yields monthly principal and interest payments. All of them are trivially calculated using school maths, and making such a calendar is also very easy in pandas. I wrote additional custom class for yield curve to get discounts, so my pandas output looks like this:

However, I want to use Quantlib functionality. As far as I understand, there is no built-in loan or mortgage class. The "Bond" class is not applicable for the case. I tried to use FixedRateLeg class for the stream of the principal repayments:

`leg = FixedRateLeg(schedule, dayCount, [nominal], [rate])`

but it also didn't work due to daycount issues.

So, the question is:

- What built-in class am I supposed to use for such a cashflow stream? I am fine with calculating the required values of payments by myself and providing `zip(Schedule, Payments)` , but if there is a class that calculates such payments by itself, it is also great.

- Given such class, how do I merge it with a yield curve to obtain discounts and npv? Assume I already have a `yc = ZeroCurve(*args)`.

- Is there a way to perform such calculation with a floating interest rate (apart of merging pre-calculated schedule and payments like in 1)?

## Answer by David Duarte (score 3)

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

You could build a bond and then add the first cashflow and build a leg:

```
start = ql.Date(30, 9, 2021)
maturity = ql.Date(30, 9, 2022)
calendar = ql.TARGET()
nominal = 100e3
freq = ql.Period('6M')
dayCount = ql.Actual360()
coupon = 0.07

bond = ql.FixedRateBond(2, calendar, nominal, start, maturity, freq, [coupon], dayCount)
principal = cf = ql.AmortizingPayment(-nominal, start)

leg = ql.Leg([principal, *bond.cashflows()])
for cf in leg:
    print(cf.date().ISO(), cf.amount())
```

2021-09-30 -100000.0 2022-03-30 3519.444444444453 2022-09-30 3577.7777777777687 2022-09-30 100000.0

If you need amortizations, use the ql.AmortizingFixedRateBond class (Link).

Then you could value it using the Cashflows functions:

```
yts = ql.YieldTermStructureHandle(ql.FlatForward(0, ql.TARGET(), 0.05, ql.Actual360()))
ql.CashFlows.npv(leg, yts, False)
```

1874.481604734974

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.