Chapter 3, part 1 of n: Term structures
Hello again.
This post starts a new series that will cover chapter 3 of my book. Most of the content was already available (even though I’ll review it a bit before posting, so there might be some revisions) but the chapter is still missing the last section. Hopefully, I’ll write it by the end of the series. (Suspense. That’s what makes you come back here again and again.)
Follow me on Twitter if you want to be notified of new posts, or add me to your circles, or subscribe via RSS: the buttons for that are in the footer. Also, make sure to check my Training page.
Term structures
CHANGE IS the only constant, as Heraclitus said. Paradoxically, the aphorism still holds after twenty-five centuries; also in quantitative finance, where practically all quantities obviously vary—sometimes spectacularly—over time.
This leads us straight to the subject of term structures. This chapter describes the basic facilities available for their construction, as well as a few existing term structures that can be used as provided.
The TermStructure class
The current base class for term structures is a fine example of design
ex-post. After some thinking, you might come up with a specification
for such class. When we started the library, we didn’t; we just
started growing classes as we needed them. A couple of years later,
older and somewhat wiser, we looked at the existing term structures
and abstracted out their common features. The result is the
TermStructure
class as described in this section.
Interface and requirements
Once abstracted out, the base term-structure class (whose interface is shown in listing 3.1) was responsible for three basic tasks.
Listing 3.1: Interface of the TermStructure
class.
The first is to keep track of its own reference date, i.e., the date
at which—in a manner of speaking—the future begins. (This
is not strictly true of all term structures. However, we’ll leave it
at that for the time being.) For a volatility term structure, that
would most likely be today’s date. For a yield curve, it might be
today’s date, too; but depending on the conventions used at one’s desk
(for instance, an interest-rate swap desk whose deals are all settled
spot; that’s on the second business day for you equity folks) the
reference date might be the result of advancing today’s date by a few
business days. Our term-structure class must be able to perform such a
calculation if needed. Also, there might be cases in which the
reference date is specified externally (such as when a sequence of
dates, including the reference, is tabulated somewhere together with
the corresponding discount factors). Finally, the calculation of the
reference date might be altogether delegated to some other object;
we’ll see such an arrangement in a later example. In all these cases,
the reference date will be provided to client code by means of the
referenceDate
method. The related calendar
and settlementDays
methods return the calendar and the number of days used for the
calculation (“settlement” applies to instruments, but is probably not
the correct word for a term structure).
The second (and somewhat mundane) task is to convert dates to times,
i.e., points on a real-valued time axis starting with t=0 at the
reference date. Such times might be used in the mathematical model
underlying the curve, or simply to convert, say, from discount factors
to zero-yield rates. The calculation is made available by means of the
timeFromReference
method.
The third task (also a mundane one) is to check whether a given date
or time belongs to the domain covered by the term structure. The
TermStructure
class delegates to derived classes the specification
of the latest date in the domain—which must be implemented in
the maxDate
method—and provides a corresponding maxTime
method as well as an overloaded checkRange
method performing the
actual test; there is no minDate
method, as the domain is assumed to
start at the reference date.
Implementation
The first task—keeping track of the reference date—starts when the term structure is instantiated.
Listing 3.2: Implementation of the TermStructure
class.
Depending on how the reference date is to be calculated, different
constructors must be called. All such constructors set two boolean
data members. The first is called moving_
; it is set to true
if
the reference date moves when today’s date changes, or to false
if
the date is fixed. The second, updated_
, specifies whether the value
of another data member (referenceDate_
, storing the latest
calculated value of the reference date) is currently up to date or
should be recalculated.
Three constructors are available. One simply takes a day counter (used
for time calculations, as we will see later) but no arguments related
to reference-date calculation. Of course, the resulting term structure
can’t calculate such date; therefore, derived classes calling this
constructor must take care of the calculation by overriding the
virtual referenceDate
method. The implementation sets moving_
to
false
and updated_
to true
to inhibit calculations in the base
class.
Another constructor takes a date, as well as an optional calendar and
a day counter. When this one is used, the reference date is assumed to
be fixed and equal to the given date. Accordingly, the implementation
sets referenceDate_
to the passed date, moving_
to false
, and
updated_
to true
.
Finally, a third constructor takes a number of days and a
calendar. When this one is used, the reference date will be calculated
as today’s date advanced by the given number of business days
according to the given calendar. Besides copying the passed data to
the corresponding data members, the implementation sets moving_
to
true
and updated_
to false
(since no calculation is performed at
this time). However, that’s not the full story; if today’s date
changes, the term structure must be notified so that it can update its
reference date. The Settings
class (described elsewhere) provides
global access to the current evaluation date, with which the term
structure registers as an observer. When a change is notified, the
update
method is executed. If the reference date is moving, the body
of the method sets updated_
to false
before forwarding the
notification to the term structure’s own observers.
Apart from trivial inspectors such as the calendar
method, the
implementation of the first task is completed with the referenceDate
method. If the reference date needs to be calculated, it does so by
retrieving the current evaluation date, advancing it as specified, and
storing the result in the referenceDate_
data member before
returning it.
The second task is much simpler, since the conversion of dates into
times can be delegated entirely to a DayCounter
instance. Such day
counter is usually passed to the term structure as a constructor
argument and stored in the dayCounter_
data member. The conversion
is handled by the timeFromReference
method, which asks the day
counter for the number of years between the reference date and the
passed date. Note that, in the body of the method, both the day
counter and the reference date are accessed by means of the
corresponding methods rather than the data members. This is necessary,
since—as I mentioned earlier—the referenceDate
method
can be overridden entirely and thus disregard the data member; the
same applies to the dayCounter
method.
You might object that this is, to use the term coined by Kent Beck
[1], a code smell. A term-structure instance might store a day counter
or a reference date (or likely both) that don’t correspond to the
actual ones used by its methods. This disturbs me as well; and indeed,
earlier versions of the class declared the dayCounter
method as
purely virtual and did not include the data member. However, it is a
necessary evil in the case of the reference date, since we need a data
member to cache its calculated value. Due to the broken-window effect
[2], the day counter, calendar and settlement days followed (after a
period in which we developed a number of derived term structures, all
of which had to define the same data members).
What day counter should be used for a given term structure? Fortunately, it doesn’t matter much. If one is only working with dates (i.e., provides dates as an input for the construction of the term structure and uses dates as arguments to retrieve values) the effects of choosing a specific day counter will cancel out as long as the day counter is sufficiently well behaved: for instance, if it is homogeneous (by which I mean that the time T(d1,d2) between two dates d1 and d2 equals the time T(d3,d4) between d3 and d4 if the two pairs of dates differ by the same number of days) and additive (by which I mean that T(d1,d2) + T(d2,d3) equals T(d1,d3) for all choices of the three dates). Two such day counters are the actual/360 and the actual/365-fixed ones. Similarly, if one is only working with times, the day counter will not be used at all.
Onwards with the third and final task. The job of defining the valid
date range is delegated to derived classes, which must define the
maxDate
method (here declared as purely virtual). The corresponding
time range is calculated by the maxTime
method, which simply
converts the latest valid date to time by means of the
timeFromReference
method; this, too, can be overridden. Finally, the
two checkRange
methods implement the actual range checking and throw
an exception if the passed argument is not in the valid range; the one
that takes a date does so by forwarding the request to the other after
converting the given date to a time. The check can be overridden by a
request to extrapolate outside the domain of the term-structure; this
can be done either by passing an optional boolean argument to
checkRange
or by using the facilities provided by the Extrapolator
class from which TermStructure
inherits. Extrapolation is only
allowed beyond the maximum date; requests for dates before the
reference date are always rejected.
Aside: evaluation date tricks.
If no evaluation date is set, the Settings
class defaults to
returning today’s date. Unfortunately, the latter will change silently
(that is, without notifying its observers) at the strike of midnight,
causing mysterious errors. If you run overnight calculations, you’ll
have to perform the same feat as Hiro Nakamura in
Heroes—freeze time. Explicitly settings today’s date as the
evaluation date will keep it fixed, even when today becomes tomorrow.
Another trick worth knowing: if all your term structures are moving, setting the evaluation date to tomorrow and recalculating the value of your instruments while keeping everything else unchanged will give you the daily theta of your portfolio.
Bibliography
[1] M. Fowler, K. Beck, J. Brant, W. Opdyke and D. Roberts,
Refactoring: Improving the Design of Existing Code. Addison-Wesley,
1999.
[2] A. Hunt and D. Thomas, The Pragmatic Programmer: From Journeyman
to Master. Addison-Wesley, 1999.