QuantLib: Net Present Value Calculation

When you have a series of cash flows you will normally want to know the net present value of those cash flows. The net present value (NPV) of a series of cash flows is calculated as the sum of all the cash flows, discounted back to the evaluation date. It provides an indication of the worth of an instrument, whether it adds or subtracts value to the business. The NPV depends, of course, on the interest rate over the period of the cash flows. The interest rate might not be known precisely and, therefore, different assumptions of the future interest rates can lead to different NPVs.

QuantLib provides a number of functions that calculate the NPV of a series of cash flows. These are defined as static methods inside the CashFlows class. The simplest calculation of the NPV will take a constant interest rate over the period of the cash flows.

static Real npv(const Leg& leg,
                const InterestRate& yield,
                bool includeSettlementDateFlows,
                Date settlementDate = Date(),
                Date npvDate = Date());

static Real npv(const Leg& leg,
                Rate yield,
                const DayCounter& dayCounter,
                Compounding compounding,
                Frequency frequency,
                bool includeSettlementDateFlows,
                Date settlementDate = Date(),
                Date npvDate = Date());

The first function takes a Leg of cash flows and an interest rate that defines the yield. The interest rate is passed using the InterestRate class. In short, InterestRate contains information about interest rates such as the rate itself, the compounding rule, the frequency and a day counting convention. Note that this allows the InterestRate class to calculate a discount factor for a given time interval. The settlement date can be passed as fourth argument. Only cash flows that occur on or after the settlement date will contribute to the NPV. The inclusion of cash flows on the settlement date is governed by the flag includeSettlementDateFlows. As always the parameters are simply passed to the hasOccured method of the cash flow to determine if the cash flow has already occurred. If the settlement date is not set the global evaluation date will be used. The last parameter can be used to specify a different date to which the cash flows are discount back to. This means that the discounting factor is calculated using npvDate. If npvDate is not set, the settlement date will be taken.

Note that the interest rate is calculated by compounding the factor calculated for the cash flow intervals. What this means is that the discount rate is calculated using the compounding rules defined in the InteresRate yield object for the intervals between two cash flows. Let’s say that \(d_i\) and \(d_{i-1}\) are the dates of two successive cash flows, then the interval discount factor is calculated as a function of these two dates.

$$\mathrm{Discount Factor}_i = DInt_{i, i-1}(d_i, d_{i-1})$$

Here \(DInt\) is the discount rate calculated by the InterestRate object and might use simple, continuous compounding or use a compounding discount factor with a frequency that does not necessarily match the frequency of the cash flows. To get the discount factor of a cash flow these interval discount factors are compounded by multiplying them together.

$$D_i = \prod_{i=1}^{N} DInt_{i, i-1}(d_i, d_{i-1})$$

The final net present value is then calculated using the individual discount factors.

$$\mathrm{NPV} = \sum_{i=1}^{N} D_i \times R_i$$

Calculating NPV with Yield Curves

In many realistic cases, one won’t have a constant interest rate over the period of the cash flows. In this case the NPV of a Leg has to be calculated using a yield curve. In QuantLib yield curves are represented by YieldTermStructure.The CashFlows class provides a static method for evaluating the NPV in this case.

Real npv(const Leg& leg,
         const YieldTermStructure& discountCurve,
         bool includeSettlementDateFlows,
         Date settlementDate = Date(),
         Date npvDate = Date());

As with the two methods described above, includeSettlementDateFlows determines if cash flows on the settlement date are taken into account for the calculation. The date settlementDate is the settlement date which enters into the hasOccured method of the cash flows. Again, this means only cash flows on or after the settlement date are included in the calculation. The npvDate is a date that the NPV is discounted back to. To understand what the function calculates, assume that \(D(d_i)\) is the discount factor returned by the yield curve for a given date \(d_i\). This discount factor is simply the return value of the discount method of YieldTermStructure. The NPV is then calculated using the formula

$$\mathrm{NPV} = \frac{\sum_{i=1}^{N} D(d_i) \times R_i}{D(\mathrm{npvDate})}$$

The last function for calculating the NPV takes the zero spread of the cash flows into account.

Real npv(const Leg& leg,
         const boost::shared_ptr<YieldTermStructure>& discount,
         Spread zSpread,
         const DayCounter& dayCounter,
         Compounding compounding,
         Frequency frequency,
         bool includeSettlementDateFlows,
         Date settlementDate = Date(),
         Date npvDate = Date());

This function uses the zero spread, given by zSpread, the day counter, the compounding rule and the frequency to construct a modified yield curve. This modified yield curve is simply the original curve passed to the function with an added zero spread. The modified curve is then passed to the previous function for calculating the NPV.

Leave a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>