QuantLib: Yield Curves

In a previous post I discussed the abstract class TermStructure that defines methods common to any kind of term structure. It was pointed out that many classes inherit from the TermStructure class, including a class called YieldTermStructure. This class is, again, an abstract class and it defines the base for any yield curves. A yield curve is defined by a list of quotes together with a list of jump dates. These are passed to YieldTermStructure in the constructor and are then stored internally. There are three different constructors which correspond to the three constructors defined in TermStructure.

YieldTermStructure(
    const DayCounter& dc = DayCounter(),
    const std::vector<Handle<Quote> >& jumps
        = std::vector<Handle<Quote> >(),
    const std::vector<Date>& jumpDates
        = std::vector<Date>());

YieldTermStructure(
    const Date& referenceDate,
    const Calendar& cal = Calendar(),
    const DayCounter& dc = DayCounter(),
    const std::vector<Handle<Quote> >& jumps
        = std::vector<Handle<Quote> >(),
    const std::vector<Date>& jumpDates
        = std::vector<Date>());

YieldTermStructure(Natural settlementDays,
    const Calendar& cal,
    const DayCounter& dc = DayCounter(),
    const std::vector<Handle<Quote> >& jumps
        = std::vector<Handle<Quote> >(),
    const std::vector<Date>& jumpDates
        = std::vector<Date>());

All three constructors take two additional arguments, a std::vector of Quote handles and a std::vector of jump dates. These two vectors define the data for the interest rate term structure. If the jumpDates array is left empty, the jumps are assumed to occur annually at  31 Dec every year, starting in the year of the reference date. For the meaning of the remaining arguments and the difference between the constructors, see the documentation of the TermStructure class.

Two inspector methods give access to the jump dates.

const std::vector<Date>& jumpDates() const;
const std::vector<Time>& jumpTimes() const;

The method jumpDates returns vector of Date objects while jumpTimes returns a vector of times. Recall that Time is just a Real number. Times are expressed in fractions of a year from the reference date and are evaluated using the day counter. They are calculated using the timeFromReference method of TermStructure.

YieldTermStructure also overrides the update method that it inherited from the Observer interface. Whenever the reference date changes, the jump times have to be recalculated.

Two methods return the discount factor from an arbitrary date to the reference date.

DiscountFactor discount(const Date& d,
                        bool extrapolate = false) const;

DiscountFactor discount(Time t,
                        bool extrapolate = false) const;

The two methods differ in the way that the date is passed to them. The first version takes a date, while the second version takes a time measured in fractions of a year. This time should be calculated using the same day counting convention that is used in the YieldTermStructure. In fact, the first method is just a convenience method which converts the Date into Time using TermStrucure::timeFromReference and then calls the second version of the discount method.

The discount is calculated by multiplying all the jumps that fall in the period from the reference date to the date passed to the discount() method and then multiplying this with the result of discountImpl, discussed later. The extrapolate flag indicates whether the discount factor should be extrapolated if it falls outside of the date range of the term structure.

The discount method is used internally in a number of convenience methods. zeroRate calculates the implied zero-coupon interest rate for a given time interval.

InterestRate zeroRate(const Date& d,
                      const DayCounter& resultDayCounter,
                      Compounding comp,
                      Frequency freq = Annual,
                      bool extrapolate = false) const;

InterestRate zeroRate(Time t,
                      Compounding comp,
                      Frequency freq = Annual,
                      bool extrapolate = false) const;

As before, the two methods differ in the way that the date is passed to them. The first version takes a specific date. This version allows passing a different day counter than the one used in the term structure.  The InterestRate that is returned uses the new day counter, compounding rule and frequency. The second version takes a time interval which has to be calculated using the same day counter as the one used in YieldTermStructure. Internally, both methods first calculate the compound rate as the reciprocal of the discount rate, a=1/d. Then an InterestRate is generated by calling InterestRate::impliedRate() with the correct arguments. The extrapolate flag indicates whether the discount factor should be extrapolated for dates outside of the term structure’s range.

The implied forward rates can be obtained in a similar way.

InterestRate forwardRate(const Date& d1, const Date& d2,
                         const DayCounter& resultDayCounter,
                         Compounding comp,
                         Frequency freq = Annual,
                         bool extrapolate = false) const;

InterestRate forwardRate(const Date& d,
                         const Period& p,
                         const DayCounter& resultDayCounter,
                         Compounding comp,
                         Frequency freq = Annual,
                         bool extrapolate = false) const;

InterestRate forwardRate(Time t1, Time t2,
                         Compounding comp,
                         Frequency freq = Annual,
                         bool extrapolate = false) const;

For the forward rate there are three methods available, each taking the time interval in a different form. It can be given by two dates, by a date and a time period, or by two floating point numbers representing the time intervals. The behaviour is equivalent to the zeroRate methods. For the first two methods, a separate day counter can be specified for the resulting InterestRate. For the last version, the day counter of the term structure is used.

The forward rate is evaluated by calculating a compound rate using the ratio of the two discount rates, a=d1/d2. The interest rate is then generated by calling InterestRate::impliedRate() with the compound rate.

As promised above, I have to now talk about the actual implementation of the discount factor calculation. This should be handled in the method discountImpl which is declared abstract.

virtual DiscountFactor discountImpl(Time) const = 0;

Any concrete implementation of YieldTermStructure must implement this method and return the discount factor for a specific time. When discountImpl() is called, the conversions from dates to units of time has already been done. The enabled flag that was passed to the discount method has been checked. This means that discountImpl must assume that the discount factor has to be extrapolated if the time does not fall within the time for which the term structure can return values, i.e. if it is larger than the value returned by maxTime.

Follow the author

1 Comment

  1. convexity

    Robust trajectory optimization under frictional contact …

    Reply

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>