Welcome back.

In this post, some more content from Implementing QuantLib: a short section from the appendix, looking at the Exercise and Payoff classes. At last, it seems that I’m getting close to completing the book, or at least its first version. (And in case you’re interested, I’m available for trainings based on its contents.)

Subscribe to my Substack to receive my posts in your inbox, or follow me on Twitter or LinkedIn if you want to be notified of new posts, or subscribe via RSS if you’re the tech type: the buttons for all that are in the footer. Also, I’m available for training, both online and (when possible) on-site: visit my Training page for more information.

Exercises and payoffs

The subjects of this post are a couple of domain-related classes used in the definitions of a few instruments.

First, the Exercise class, shown in the listing below.

    class Exercise {
      public:
        enum Type {
            American, Bermudan, European
        };
        explicit Exercise(Type type);
        virtual ~Exercise();
        Type type() const;
        Date date(Size index) const;
        const std::vector<Date>& dates() const;
        Date lastDate() const;
      protected:
        std::vector<Date> dates_;
        Type type_;
    };

    class EarlyExercise : public Exercise {
      public:
        EarlyExercise(Type type,
                      bool payoffAtExpiry = false);
        bool payoffAtExpiry() const;
    };

    class AmericanExercise : public EarlyExercise {
      public:
        AmericanExercise(const Date& earliestDate,
                         const Date& latestDate,
                         bool payoffAtExpiry = false);
    };

    class BermudanExercise : public EarlyExercise {
      public:
        BermudanExercise(const std::vector<Date>& dates,
                         bool payoffAtExpiry = false);
    };

    class EuropeanExercise : public Exercise {
      public:
        EuropeanExercise(const Date& date);
    };

As you would expect, the base class declares methods to retrieve information on the date, or dates, of the exercise. Quite a few of them, actually. There’s a dates method that returns the set of exercise dates, a date method that returns the one at a particular index, and a convenience method lastDate that, as you might have guessed, returns the last one; so there’s some redundancy there. (Lovers of encapsulation will probably prefer the version taking an index to the one returning a vector, since the latter reveals more than necessary about the internal storage of the class.) Also, there’s a type method that is leaving me scratching my head as I look at the code again.

The type method returns the kind of exercise, picking its value from a set (European, Bermudan, or American) declared in an inner enumeration Exercise::Type. This is not puzzling per se, but it goes somewhat against what we did next, which is to use inheritance to declare AmericanExercise, BermudanExercise, and EuropeanExercise classes. On the one hand, the use of a virtual destructor in the base Exercise class seems to suggest that inheritance is the way to go if one wants to define new kind of exercises. On the other hand, enumerating the kind of exercises in the base class seems to go against this kind of extension, since inheriting a new exercise class would also require one to add a new case to the enumeration. For inheritance, one can also argue that the established idiom around the library is to pass around smart pointers to the Exercise class; and against inheritance, that the class doesn’t define any virtual method except the destructor, and the behavior of an instance of any derived class is only given by the value of the data members stored in the base class. In short: it seems that, when we wrote this, we were even more confused than I am now.

Were I to write it now, I’d probably keep the enumeration and make it a concrete class: the derived classes might either create objects that can be safely sliced to become Exercise instances when passed around, or they could be turned into functions returning Exercise instances directly. As much as this might irk object-oriented purists, there are a number of places in the code where the type of the exercise need to be checked, and having an enumeration is probably the pragmatic choice when compared to using casts or some kind of visitor pattern. The absence of specific behavior in derived classes seems another hint to me.

As I wrote this, it occurred to me that an exercise might also be an Event, as described in a previous post. However, this doesn’t always match what the Exercise class models. In the case of a European exercise, we could also model it as an Event instance; in the case of a Bermudan exercise, the Exercise instance would probably correspond to a set of Event instances; and in the case of an American exercise, what we’re really modeling here is an exercise range—and as a matter of fact, the meaning of the interface also changes in this case, since the dates method no longer returns the set of all possible exercise dates, but just the first and last date in the range. As often happens, the small things that seem obvious turn out to be difficult to model soundly when looked up close.

Onwards to the Payoff class, shown in the next listing together with a few of its derived classes.

    class Payoff : std::unary_function<Real,Real> {
      public:
        virtual ~Payoff() {}
        virtual std::string name() const = 0;
        virtual std::string description() const = 0;
        virtual Real operator()(Real price) const = 0;
        virtual void accept(AcyclicVisitor&);
    };

    class TypePayoff : public Payoff {
      public:
        Option::Type optionType() const;
      protected:
        TypePayoff(Option::Type type);
    };

    class FloatingTypePayoff : public TypePayoff {
      public:
        FloatingTypePayoff(Option::Type type);
        Real operator()(Real price) const;
        // more Payoff interface
    };

    class StrikedTypePayoff : public TypePayoff {
      public:
        Real strike() const;
        // more Payoff interface
      protected:
        StrikedTypePayoff(Option::Type type,
                          Real strike);
    };

    class PlainVanillaPayoff : public StrikedTypePayoff {
      public:
        PlainVanillaPayoff(Option::Type type,
                           Real strike);
        Real operator()(Real price) const;
        // more Payoff interface
    };

Its interface includes an operator(), returning the value of the payoff given the value of the underlying, an accept method to support the Visitor pattern, and a couple of inspectors (name and description) which can be used for reporting—and are probably one too many.

In hindsight, we tried to model the class before having a grasp of enough use cases. Unfortunately, the resulting interface stuck. The biggest problem is the dependency of operator() on a single underlying, which excludes payoffs based on multiple underlying values. (This also constrains how we model payoffs based on multiple fixings of an underlying; for instance, Asian options are passed the payoff for a plain option and the average of the fixings is done externally, before passing it to the payoff. One might want the whole process to be described as “the payoff”.) Another one is the over-reliance on inheritance. For instance, we have a TypePayoff class that adds a type (Call or Put, which again might be restrictive) and the corresponding inspector; a StrikedTypePayoff which adds a strike; and, finally, PlainVanillaPayoff, which models a simple call or put payoff and ends up removed from the Payoff class by three levels of inheritance: probably too many, considering that this is used to implement a textbook option and will be looked up by people just starting with the library.

Another misstep we might have made is to add a pointer to a Payoff instance to the Option class as a data member, with the intent that it should contain the information about the payoff. This led us to classes such as FloatingTypePayoff, also shown in the listing. It’s used in the implementation of floating lookback options, and stores the information about the type (as in, call or put); but since the strike is fixed at the maturity of the option, it can’t specify it and can’t implement the payoff with the interface we specified. Its operator() throws an exception if invoked. In this case, we might as well do without the payoff and just pass the type to the lookback option; that is, if its base Option class didn’t expect a payoff. Yet another thing to remember when we decide to clean up the code.