QuantLib: Bonds

Bonds are a special type of instrument in which the issuer receives money from an investor. The issuer promises to pay back the principal at the maturity date and/or interest in the form of coupons at certain times during the life time of the bond. QuntLib defines three main types of Bonds. In fixed rate bonds the coupons are fixed throughout the life time of the bond. In floating rate bonds the coupon rate is calculated from some IBOR index. Zero coupon bonds don’t pay out any interest. In this post I will be talking about the general API of the Bond class. The description of the individual bonds will follow in a future post.

The Bond Class

The Bond class has two constructors.

Bond(Natural settlementDays,
     const Calendar& calendar,
     const Date& issueDate = Date(),
     const Leg& coupons = Leg());

Bond(Natural settlementDays,
     const Calendar& calendar,
     Real faceAmount,
     const Date& maturityDate,
     const Date& issueDate = Date(),
     const Leg& cashflows = Leg());

The first of these constructors is the preferred method of creating a Bond object. settlementDays specifies the number of days, counted from the evaluation date, until the settlement of the bond. The calendar prescribes which calendar should be used in date calculations. An optional parameter, the issueDate, allows the setting of the date at which the bond is issued. Finally the coupon payments can be specified in the fourth parameter. Note that Leg is simply a std::vector of shared pointers to CashFlow objects.

typedef std::vector<boost::shared_ptr<CashFlow> > Leg;

The second constructor allows the creation of non-amortizing bonds only. In addition to the parameters of the first constructor, one needs to specify the face value of the bond and the maturity date.

The Bond class implements the abstract isExpired() method from the Instrument class.

bool isExpired() const;

This method returns true if the cash flows are expired. The method simply calls the static CashFlows::isExpired() method, passing the cashflows as argument.

Two inspectors are provided that simply return the values supplied in the constructor.

Natural settlementDays() const;
const Calendar& calendar() const;

Cash Flows and Notionals

A Bond will contain different types of cash flows. The coupons are paid according to the cashflows passed to the bond in the constructor. In addition Bond will calculate and add redemption cash flows. Two methods will return a reference to a cash flow vector.

const Leg& cashflows() const;

const Leg& redemptions() const;

The cashflows() method returns a Leg contining all the cash flows, including the any amortizing payments and redemption cash flows. In contrast, redemptions() will only return the amortizing payments and redemption cash flows.

Redemptions are calculated automatically if the first constructor has been used to create the Bond. In this case, the notional values of all the Coupons passed to the constructor are inspected. On dates where the notional changes, there will be an amortizing cash flow, encoded by the class AmortizingPayment. On the date of the last cash flow a redemption cash flow is added, encoded by the class Redemption. By default, all amortizing payments and redemption cash flows will assume a redemption rate of 100%. Specific bond types, derived from the Bond class can override this behaviour and set specific redemption rates.

The last cash flow in the redemptions cash flow vector can be obtained by calling redemption().

const boost::shared_ptr<CashFlow>& redemption() const;

A vector of the distinct notional values of the coupons is returned by the notionals() method. This is simply a vector of Real numbers, not associated with any dates. The notionals vector will not contain an entry for each cash flow but only entries for distinct notional values.

const std::vector<Real>& notionals() const;
virtual Real notional(Date d = Date()) const;
bool isTradable(Date d = Date()) const;

The notional() method takes a date and returns the corresponding notional value for that date. If the date is during the life time of the bond then the function returns the notional of the last coupon that came before or on that date. If the date falls after the last cash flow a value of 0.0 is returned. For dates before the first cash flow this function returns the notional of the first cash flow. If no date is specified then Settings.evaluationDate() will be used. Note that notional is declared virtual. Specific bond types may override the behaviour.

Finally isTradable() will return true if the notional value for the bond on the given date is non-zero.

Date Functions

Some important dates are evaluated by the following methods.

Date issueDate() const;
Date startDate() const;
Date maturityDate() const;
Date settlementDate(Date d = Date()) const;

The method issueDate() simply returns the value of the issue date passed to the Bond in the constructor. The other two methods evaluate the cash flows vector to find the start date and the maturity date of the bond. In fact they don’t really do anything themselves. They simply pass the cashflows vector to the static methods CashFlows::startDate() and CashFlows::maturityDate(). These methods return the dates of the first cash flow and the last cash flow respectively. For further information read the information on the CashFlows utility class.

The settlementDate() is calculated from the given date by adding the number of settlement days to the date. If an issue date has been specified and it lies after the settlement date calculated in this way, then the issue date is returned instead.

The following methods return cash flows dates and the coupon rates that immediatly precede or follow a given date.

Date Bond::previousCashFlowDate(Date settlement) const;
Date Bond::nextCashFlowDate(Date settlement) const;
Rate Bond::previousCouponRate(Date settlement) const;
Rate Bond::nextCouponRate(Date settlement) const;

The method previousCashFlowDate will return the date of the last cash flow on or before the given date while nextCashFlowDate will return the date of the next cash flow after the given date. The functions previousCouponRate and nextCouponRate will return the coupon rate of the previous or the next coupon in the leg, with respect to the settlement date. As above, all four methods simply forward the call to the corresponding static methods in the CashFlows utility class.

Bond Valuation

The Bond class provides a number of methods useful for the valuation of the bond.

virtual Real accruedAmount(Date d = Date()) const;

This method will return the accrued amount for a given date. This will call the accruedAmount static method in the CashFlows utility class, passing the cashflows array as argument. This class will find the next Coupon cash flow on or after the given date. Then the accrued amounts for all the cash flows on the date of that cash flow are added up. The result is then divided by the notional of the date given.

$$I_A \equiv I_{A,\mathrm{Bond}} = \frac{100}{N} I_{A,\mathrm{Cash Flows}}$$

Here \(N\) is the notional specified in percent and \(I_{A,\mathrm{Bond}}\) is the accrued amount of the bond and \(I_{A,\mathrm{Cash Flows}}\) is the accrued amount of the cash flows.

The following method returns the settlement value of the bond.

  Real settlementValue() const;
  Real settlementValue(Real cleanPrice) const;

The method settlementValue() that doesn’t take arguments invokes the pricing engine of the bond which will calculate a settlement value. This value is then returned. In order to use this method, a PricingEngine has to be supplied to the bond and the result will depend on the implementation of the pricing engine.

If the clean price of the bond is known then the settlement value can simply be calculated using the formula

$$\mathrm{settlement value} = \frac{N}{100} \left(\mathrm{clean price} + I_A\right)$$

The theoretical prices of the bond are given by the following three methods.

  Real dirtyPrice() const;
  Real cleanPrice() const;
  Rate yield(const DayCounter& dc,
             Compounding comp,
             Frequency freq,
             Real accuracy = 1.0e-8,
             Size maxEvaluations = 100) const;

The theoretical dirty price is calculated from the pricing engine’s settlement value by dividing it by the notional.

$$\mathrm{dirty price} = \frac{100}{N} \mathrm{settlement value}$$

The clean price is then calculated from the dirty price by subtracting the accrued amount from it.

$$\mathrm{clean price} = \mathrm{dirty price} – I_A = \frac{100}{N} \mathrm{settlement value} – I_A$$

Finally the theoretical yield is calculated using the theoretical settlement value. The yield method passes the calculation on to the CashFlows utility class.

If a yield is given then the following two methods can be used to calculate the clean price and the dirty price.

  Real cleanPrice(Rate yield,
                  const DayCounter& dc,
                  Compounding comp,
                  Frequency freq,
                  Date settlementDate = Date()) const;
  Real dirtyPrice(Rate yield,
                  const DayCounter& dc,
                  Compounding comp,
                  Frequency freq,
                  Date settlementDate = Date()) const;

This cleanPrice method constructs an InteresRate object from the yield, day counter, compounding rule and the frequency. This interest rate is then used to calculate the NPV of the cash flows using the static npv method in the CashFlows utility class. The clean price is then calculated by dividing by the current notional of the bond.

$$\mathrm{clean price} = \frac{100}{N} \mathrm{NPV} – I_A$$

The dirtyPrice method simply calls cleanPrice and then calculates the dirty price according to

$$\mathrm{dirty price} = \mathrm{clean price} + I_A$$

If, on the other hand, the clean price of the bond is known, then we can calculate the yield.

  Rate yield(Real cleanPrice,
             const DayCounter& dc,
             Compounding comp,
             Frequency freq,
             Date settlementDate = Date(),
             Real accuracy = 1.0e-8,
             Size maxEvaluations = 100) const;

From the clean price passed to the method, an NPV is calculated according to

$$\mathrm{NPV} = \frac{N}{100} \left(\mathrm{clean price} + I_A\right)$$

This NPV is passed to the yield method in the CashFlows utility class to calculate the yield of the bond.

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>