Hello everybody. This is the third in a series of four posts covering chapter 2 of the book; part 1, 2 and 4 can be found here, here and here. Feedback is welcome.

Registration for the next Introduction to QuantLib Development course is still open; 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.

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

Pricing engines

We now turn to the second of the requirements I stated in the previous posts. For any given instrument, it is not always the case that a unique pricing method exists; moreover, one might want to use multiple methods for different reasons. Let’s take the classic textbook example—the European equity option. One might want to price it by means of the analytic Black-Scholes formula in order to retrieve implied volatilities from market prices; by means of a stochastic volatility model in order to calibrate the latter and use it for more exotic options; by means of a finite-difference scheme in order to compare the results with the analytic ones and validate one’s finite-difference implementation; or by means of a Monte Carlo model in order to use the European option as a control variate for a more exotic one.

Therefore, we want it to be possible for a single instrument to be priced in different ways. Of course, it is not desirable to give different implementations of the performCalculations method, as this would force one to use different classes for a single instrument type. In our example, we would end up with a base EuropeanOption class from which AnalyticEuropeanOption, McEuropeanOption and others would be derived. This is wrong in at least two ways. On a conceptual level, it would introduce different entities when a single one is needed: a European option is a European option is a European option, as Gertrude Stein said. On a usability level, it would make it impossible to switch pricing methods at run-time.

The solution is to use the Strategy pattern, i.e., to let the instrument take an object encapsulating the computation to be performed. We called such an object a pricing engine. A given instrument would be able to take any one of a number of available engines (of course corresponding to the instrument type), pass the chosen engine the needed arguments, have it calculate the value of the instrument and any other desired quantities, and fetch the results. Therefore, the performCalculations method would be implemented roughly as follows:

    void SomeInstrument::performCalculations() const {
        NPV_ = engine_->calculate(arg1, arg2, ... , argN);
    }

where we assumed that a virtual calculate method is defined in the engine interface and implemented in the concrete engines.

Unfortunately, the above approach won’t work as such. The problem is, we want to implement the dispatching code just once, namely, in the Instrument class. However, that class doesn’t know the number and type of arguments; different derived classes are likely to have data members differing wildly in both number and type. The same goes for the returned results; for instance, an interest-rate swap might return fair values for its fixed rate and floating spread, while the ubiquitous European option might return any number of Greeks.

An interface passing explicit arguments to the engine through a method, as the one outlined above, would thus lead to undesirable consequences. Pricing engines for different instruments would have different interfaces, which would prevent us from defining a single base class; therefore, the code for calling the engine would have to be replicated in each instrument class. This way madness lies.

The solution we chose was that arguments and results be passed and received from the engines by means of opaque structures aptly called arguments and results. Two structures derived from those and augmenting them with instrument-specific data will be stored in any pricing engine; an instrument will write and read such data in order to exchange information with the engine.

Listing 2.5 shows the interface of the resulting PricingEngine class, as well as its inner argument and results classes and a helper GenericEngine class template. The latter implements most of the PricingEngine interface, leaving only the implementation of the calculate method to developers of specific engines. The arguments and results classes were given methods which ease their use as drop boxes for data: arguments::validate is to be called after input data are written to ensure that their values lie in valid ranges, while results::reset is to be called before the engine starts calculating in order to clean previous results.

Listing 2.5: Interface of PricingEngine and of related classes.

    class PricingEngine : public Observable {
      public:
        class arguments;
        class results;
        virtual ~PricingEngine() {}
        virtual arguments* getArguments() const = 0;
        virtual const results* getResults() const = 0;
        virtual void reset() const = 0;
        virtual void calculate() const = 0;
    };

    class PricingEngine::arguments {
      public:
        virtual ~arguments() {}
        virtual void validate() const = 0;
    };

    class PricingEngine::results {
      public:
        virtual ~results() {}
        virtual void reset() = 0;
    };

    // ArgumentsType must inherit from arguments;
    // ResultType from results.
    template <class ArgumentsType, class ResultsType>
    class GenericEngine : public PricingEngine {
      public:
        PricingEngine::arguments* getArguments() const {
            return &arguments_;
        }
        const PricingEngine::results* getResults() const {
            return &results_;
        }
        void reset() const { results_.reset(); }
      protected:
        mutable ArgumentsType arguments_;
        mutable ResultsType results_;
    };

Armed with our new classes, we can now write a generic performCalculation method. Besides the already mentioned Strategy pattern, we will use the Template Method pattern to allow any given instrument to fill the missing bits. The resulting implementation is shown in listing 2.6. Note that an inner class Instrument::result was defined; it inherits from PricingEngine::results and contains the results that have to be provided for any instrument. (The Instrument::results class also contains a std::map where pricing engines can store additional results. The relevant code is here omitted for clarity.)

Listing 2.6: Excerpt of the Instrument class.

    class Instrument : public LazyObject {
      public:
       class results;
       virtual void performCalculations() const {
          QL_REQUIRE(engine_, "null pricing engine");
          engine_->reset();
          setupArguments(engine_->getArguments());
          engine_->getArguments()->validate();
          engine_->calculate();
          fetchResults(engine_->getResults());
       }
       virtual void setupArguments(
                         PricingEngine::arguments*) const {
          QL_FAIL("setupArguments() not implemented");
       }
       virtual void fetchResults(
                   const PricingEngine::results* r) const {
          const Instrument::results* results =
              dynamic_cast<const Value*>(r);
          QL_ENSURE(results != 0, "no results returned");
          NPV_ = results->value;
          errorEstimate_ = results->errorEstimate;
       }
       template <class T> T result(const string& tag) const;
      protected:
       boost::shared_ptr<PricingEngine> engine_;
    };

    class Instrument::results
        : public virtual PricingEngine::results {
      public:
       Value() { reset(); }
       void reset() {
           value = errorEstimate = Null<Real>();
       }
       Real value;
       Real errorEstimate;
    };

As for performCalculation, the actual work is split between a number of collaborating classes—the instrument, the pricing engine, and the arguments and results classes. The dynamics of such a collaboration (described in the following paragraphs) might be best understood with the help of the UML sequence diagram shown in figure 2.2, at the bottom of this post; the static relationship between the classes (and a possible concrete instrument) is shown in figure 2.3.

A call to the NPV method of the instrument eventually triggers (if the instrument is not expired and the relevant quantities need to be calculated) a call to its performCalculations method. Here is where the interplay between instrument and pricing engine begins. First of all, the instrument verifies that an engine is available, aborting the calculation if this is not the case. If one is found, the instrument prompts it to reset itself. The message is forwarded to the instrument-specific result structure by means of its reset method; after it executes, the structure is a clean slate ready for writing the new results.

At this point, the Template Method pattern enters the scene. The instrument asks the pricing engine for its argument structure, which is returned as a pointer to arguments. The pointer is then passed to the instrument’s setupArguments method, which acts as the variable part in the pattern. Depending on the specific instrument, such method verifies that the passed argument is of the correct type and proceeds to fill its data members with the correct values. Finally, the arguments are asked to perform any needed checks on the newly-written values by calling the validate method.

The stage is now ready for the Strategy pattern. Its arguments set, the chosen engine is asked to perform its specific calculations, implemented in its calculate method. During the processing, the engine will read the inputs it needs from its argument structure and write the corresponding outputs into its results structure.

After the engine completes its work, the control returns to the Instrument instance and the Template Method pattern continues unfolding. The called method, fetchResults, must now ask the engine for the results, downcast them to gain access to the contained data, and copy such values into its own data members. The Instrument class defines a default implementation which fetches the results common to all instruments; derived classes might extend it to read specific results.

Aside: impure virtual methods

Upon looking at listing 2.6, you might wonder why the setupArguments method is defined as throwing an exception rather than declared as a pure virtual method. The reason is not to force developers of new instruments to implement a meaningless method, were they to decide that some of their classes should simply override the performCalculation method.

Next post: an example.

Figure 2.2: Sequence diagram of the interplay between instruments and pricing engines

PricingEngine sequence diagram

Figure 2.3: Class diagram of Instrument, PricingEngine, and related classes

PricingEngine class diagram