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

for (i = portfolio.begin(); i != portfolio.end(); ++i)
        totalNPV += i->NPV();

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.

    class Instrument {
      public:
        virtual ~Instrument();
        virtual Real NPV() const = 0;
        virtual Real errorEstimate() const = 0;
        virtual bool isExpired() const = 0;
    };

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, Handles forward any notifications from the pointed object to their observers.

Finally, classes were implemented which act as observable data and can be stored into Handles. 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.

    class LazyObject : public virtual Observer,
                       public virtual Observable {
      protected:
        mutable bool calculated_;
        virtual void performCalculations() const = 0;
      public:
        void update() { calculated_ = false; }
        virtual void calculate() const {
            if (!calculated_) {
                calculated_ = true;
                try {
                    performCalculations();
                } catch (...) {
                    calculated_ = false;
                    throw;
                }
            }
        }
    };

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:

    if (!calculated_) {
        performCalculations();
        calculated_ = true;
    }

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.

    class Instrument : public LazyObject {
      protected:
        mutable Real NPV_;
      public:
        Real NPV() const {
            calculate();
            return NPV_;
        }
        void calculate() const {
            if (isExpired()) {
                setupExpired();
                calculated_ = true;
            } else {
                LazyObject::calculate();
            }
        }
        virtual void setupExpired() const {
            NPV_ = 0.0;
        }
    };

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.