Chapter 2, part 1 of 4: Financial instruments
Hello again.
Some book content, for a change. This is the first in a series of four posts covering chapter 2 of the book; part 2, 3 and 4 are here, here and here. I managed the book footnotes by simply including them in parentheses at the corresponding point in the text; this, too, might change once I get better at this blogging thing I hear so much about. It goes without saying that I’ll be most grateful for any feedback, corrections, and criticisms.
Important news: the good Jacob Bettany of MoneyScience (hi, Jacob) is currently busy organizing the next Introduction to QuantLib Development course, scheduled for September 2nd/4th in London. It is the course that I teach based on the contents of the Implementing QuantLib blog and book, and you can find more information, a brochure and a booking form by clicking on this link. I look forward to see you there.
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, even if you can’t make it to the next course.
Financial instruments and pricing engines
THE STATEMENT that a financial library must provide the means to price financial instruments would certainly have appealed to Monsieur de La Palisse. However, that is only a part of the whole problem; a financial library must also provide developers with the means to extend it by adding new pricing functionality.
Foreseeable extensions are of two kinds, and the library must allow either one. On the one hand, it must be possible to add new financial instruments; on the other hand, it must be feasible to add new means of pricing an existing instrument. Both kinds have a number of requirements, or in pattern jargon, forces that the solution must reconcile. This chapter details such requirements and describes the design that allows QuantLib to satisfy them.
The Instrument class
In our domain, a financial instrument is a concept in its own right. For this reason alone, any self-respecting object-oriented programmer will code it as a base class from which specific instruments will be derived.
The idea, of course, is to be able to write code such as
where we don’t have to care about the specific type of each
instrument. However, this also prevents us from knowing what arguments
to pass to the NPV
method, or even what methods to call. Therefore,
even the two seemingly harmless lines above tell us that we have to
step back and think a bit about the interface.
Interface and requirements
The broad variety of traded assets—which range from the simplest to
the most exotic—implies that any method specific to a given class of
instruments (say, equity options) is bound not to make sense for some
other kind (say, interest-rate swaps). Thus, very few methods were
singled out as generic enough to belong to the Instrument
interface. We limited ourselves to those returning its present value
(possibly with an associated error estimate) and indicating whether or
not the instrument has expired; since we can’t specify what arguments
are needed (even fancy new C++11 stuff like variadic templates won’t
help) the methods take none; any needed input will have to be stored
by the instrument. The resulting interface is shown in listing 2.1
below.
Listing 2.1: Preliminary interface of the Instrument
class.
As is good practice, the methods were first declared as pure virtual ones; but—as Sportin’ Life points out in Gershwin’s Porgy and Bess—it ain’t necessarily so. There might be some behavior that can be coded in the base class. In order to find out whether this was the case, we had to analyze what to expect from a generic financial instrument and check whether it could be implemented in a generic way. Two such requirements were found at different times, and their implementation changed during the development of the library; I present them here in their current form.
One is that a given financial instrument might be priced in different ways (e.g., with one or more analytic formulas or numerical methods) without having to resort to inheritance. At this point, you might be thinking “Strategy pattern”. It is indeed so; I devote the third post of this series to its implementation.
The second requirement came from the observation that the value of a financial instrument depends on market data. Such data are by their nature variable in time, so that the value of the instrument varies in turn; another cause of variability is that any single market datum can be provided by different sources. We wanted financial instruments to maintain links to these sources so that, upon different calls, their methods would access the latest values and recalculate the results accordingly; also, we wanted to be able to transparently switch between sources and have the instrument treat this as just another change of the data values.
We were also concerned with a potential loss of efficiency. For instance, we could monitor the value of a portfolio in time by storing its instruments in a container, periodically poll their values, and add the results. In a simple implementation, this would trigger recalculation even for those instruments whose inputs did not change. Therefore, we decided to add to the instrument methods a caching mechanism: one that would cause previous results to be stored and only recalculated when any of the inputs change.
Implementation
The code managing the caching and recalculation of the instrument value was written for a generic financial instrument by means of two design patterns.
When any of the inputs change, the instrument is notified by means of the Observer pattern [1]. The pattern itself is briefly described in appendix A (this does not excuse you from reading the Gang of Four book); I describe here the participants.
Obviously enough, the instrument plays the role of the observer while
the input data play that of the observables. In order to have access
to the new values after a change is notified, the observer needs to
maintain a reference to the object representing the input. This might
suggest some kind of smart pointer; however, the behavior of a pointer
is not sufficient to fully describe our problem. As I already
mentioned, a change might come not only from the fact that values from
a data feed vary in time; we might also want to switch to a different
data feed. Storing a (smart) pointer would give us access to the
current value of the object pointed; but our copy of the pointer,
being private to the observer, could not be made to point to a
different object. Therefore, what we need is the smart equivalent of a
pointer to pointer. This feature was implemented in QuantLib as a
class template and given the name of Handle
. Again, details are
given in appendix A; relevant to this discussion is the fact that
copies of a given Handle
share a link to an object. When the link is
made to point to another object, all copies are notified and allow
their holders to access the new pointee. Furthermore, Handle
s
forward any notifications from the pointed object to their observers.
Finally, classes were implemented which act as observable data and can
be stored into Handle
s. The most basic is the Quote
class,
representing a single varying market value. Other inputs for financial
instrument valuation can include more complex objects such as yield or
volatility term structures. (Most likely, such objects ultimately
depend on Quote
instances, e.g., a yield term structure might depend
on the quoted deposit and swap rates used for bootstrapping.)
Another problem was to abstract out the code for storing and
recalculating cached results, while still leaving it to derived
classes to implement any specific calculations. This was done by means
of the Template Method pattern [1]. In earlier versions of QuantLib,
the functionality was included in the Instrument
class itself;
later, it was extracted and coded into another class—somewhat
unsurprisingly called LazyObject
—which is now reused in other parts
of the library. An outline of the class is shown in listing 2.2.
Listing 2.2: Outline of the LazyObject
class.
The code is simple enough. A boolean data member calculated_
is
defined which keeps track of whether results were calculated and still
valid. The update
method, which implements the Observer
interface
and is called upon notification from observables, sets such boolean to
false
and thus invalidates previous results.
The calculate
method is implemented by means of the Template Method
pattern. As explained in the Gang of Four book, the constant part of
the algorithm (in this case, the management of the cached results) is
implemented in the base class; the varying parts (here, the actual
calculations) are delegated to a virtual method, namely,
performCalculations
, which is called in the body of the base-class
method. Therefore, derived classes will only implement their specific
calculations without having to care about caching: the relevant code
will be injected by the base class.
The logic of the caching is simple. If the current results are no longer valid, we let the derived class perform the needed calculations and flag the new results as up to date. If the current results are valid, we do nothing.
However, the implementation is not as simple. You might wonder why we
had to insert a try
block setting calculated_
beforehand and a
handler rolling back the change before throwing the exception
again. After all, we could have written the body of the algorithm more
simply—for instance, as in the following, seemingly equivalent code,
that doesn’t catch and rethrow exceptions:
The reason is that there are cases (e.g., when the lazy object is a
yield term structure which is bootstrapped lazily) in which
performCalculations
happens to recursively call calculate
. If
calculated_
were not set to true
, the if
condition would still
hold and performCalculations
would be called again, leading to
infinite recursion. Setting such flag to true
prevents this from
happening; however, care must now be taken to restore it to false
if
an exception is thrown. The exception is then rethrown so that it can
be caught by the installed error handlers.
A few more methods are provided in LazyObject
which enable users to
prevent or force a recalculation of the results. They are not
discussed here. If you’re interested, you can heed the advice often
given by master Obi-Wan Kenobi: “Read the source, Luke.”
The Instrument
class inherits from LazyObject
. In order to
implement the interface outlined in listing 2.1, it decorates the
calculate
method with code specific to financial instruments. The
resulting method is shown in listing 2.3, together with other bits of
supporting code.
Listing 2.3: Excerpt of the Instrument
class.
Once again, the added code follows the Template Method pattern to
delegate instrument-specific calculations to derived classes. The
class defines an NPV_
data member to store the result of the
calculation; derived classes can declare other data members to store
specific results (the Instrument
class also defines an
errorEstimate_
member, which is omitted here for clarity of
exposition. The discussion of NPV_
applies to both). The body of the
calculate
method calls the virtual isExpired
method to check
whether the instrument is an expired one. If this is the case, it
calls another virtual method, namely, setupExpired
, which has the
responsibility of giving meaningful values to the results; its default
implementation sets NPV_
to 0 and can be called by derived
classes. The calculated_
flag is then set to true
. If the
instrument is not expired, the calculate
method of LazyObject
is
called instead, which in turn will call performCalculations
as
needed. This imposes a contract on the latter method, namely, its
implementations in derived classes are required to set NPV_
(as well
as any other instrument-specific data member) to the result of the
calculations. Finally, the NPV
method ensures that calculate
is
called before returning the answer.
Aside: const or not const?
It might be of interest to explain why NPV_
is declared as mutable,
as this is an issue which often arises when implementing caches or
lazy calculations. The crux of the matter is that the NPV
method is
logically a const one: calculating the value of an instrument does not
modify it. Therefore, a user is entitled to expect that such a method
can be called on a const instance. In turn, the constness of NPV
forces us to declare calculate
and performCalculations
as const,
too. However, our choice of calculating results lazily and storing
them for later use makes it necessary to assign to one or more data
members in the body of such methods. The tension is solved by
declaring cached variables as mutable; this allows us (and the
developers of derived classes) to fulfill both requirements, namely,
the constness of the NPV
method and the lazy assignment to data
members.
Also, it should be noted that the C++11 standard now requires const methods to be thread-safe; that is, two threads calling const members at the same time should not incur in race conditions (to learn all about it, see Sutter [2]). To make the code conform to the new standard, we should protect updates to mutable members with a mutex. This will likely require some changes in design.
Bibliography
[1] E. Gamma, R. Helm, R. Johnson and J.Vlissides, Design Patterns:
Element of Reusable Object-Oriented Software. Addison-Wesley, 1995.
[2] H. Sutter, You don’t know const and
mutable.
In Sutter’s Mill, 2013.