Welcome back, and happy new year.

I hope you all had a nice holiday. I had a nice Christmas, thanks for asking; and I finally managed to find a couple of free afternoons to finish chapter 3. This post is the last in a series of seven that covered this chapter and that started with this one.

Important news: thanks to MoneyScience, and in particular to Jacob Bettany, I’ll be in London from March 24th to 26th to teach another edition of my Introduction to QuantLib Development course. It is the course that I teach based on the contents of the Implementing QuantLib book, and you can find more information, a brochure and a booking form by clicking on this link. Yes, go ahead, click: I’ll wait right here.

Done? Thanks. I look forward to see you there: I’m told London is quite nice in spring. Ok, maybe. You can probably strike that last bit.

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 attend the course this time.

Interest-rate volatility structures

Last in our tour are interest-rate volatilities. There are three different hierarchies of them, each with its quirks.

The first hierarchy models cap and floor term volatilities; the base class is the CapFloorTermVolatilityStructure, shown in listing 3.19.

Listing 3.19: Interface of the CapFloorTermVolatilityStructure class.

    class CapFloorTermVolatilityStructure
                              : public VolatilityTermStructure {
      public:
        ... // constructors, not shown
        Volatility volatility(const Period& length, Rate strike,
                              bool extrapolate = false) const;
        Volatility volatility(const Date& end, Rate strike,
                              bool extrapolate = false) const;
        Volatility volatility(Time t, Rate strike,
                              bool extrapolate = false) const;
      protected:
        virtual Volatility volatilityImpl(Time length,
                                          Rate strike) const = 0;
    };

It is a straightforward application of the patterns seen so far, with one main difference; the volatility is not dependent on the exercise time, which is fixed to today’s time, but on the maturity of the strip of caplets or floorlets of which the instrument is composed.

The difference is semantic: volatility(t,strike) has for this class a different meaning, even though the interface and the implementation are the same as for the other volatility classes. In turn, this has a couple of small consequences on the interface: on the one hand, there’s an additional overload of the volatility method that takes the length of the cap as a Period instance, as seemed natural; and on the other hand, the volatility doesn’t really measure the width of the distribution of any variable at time t, so the variance method was omitted.

The second hierarchy models the volatilities of single caplets and floorlets. (There are ways to convert from cap to caplet volatilities, of course, but I won’t cover them here. Look into QuantLib for the OptionletStripper class and its derived classes, if you’re interested in their implementation.) Its base class is the OptionletVolatilityStructure class, shown in listing 3.20.

Listing 3.20: Interface of the OptionletVolatilityStructure class.

    class OptionletVolatilityStructure
                                   : public VolatilityTermStructure {
      public:
        ... // constructors, not shown
        Volatility volatility(const Period& optionTenor,
                              Rate strike,
                              bool extrapolate = false) const;
        Volatility volatility(const Date& optionDate,
                              Rate strike,
                              bool extrapolate = false) const;
        Volatility volatility(Time optionTime,
                              Rate strike,
                              bool extrapolate = false) const;

        Real blackVariance(const Period& optionTenor,
                           Rate strike,
                           bool extrapolate = false) const;
        // same overloads as for volatility

        shared_ptr<SmileSection> smileSection(
                              const Period& optionTenor,
                              bool extrapolate = false) const;
        shared_ptr<SmileSection> smileSection(
                              const Date& optionDate,
                              bool extrapolate = false) const;
        shared_ptr<SmileSection> smileSection(
                              Time optionTime,
                              bool extrapolate = false) const;
      protected:
        virtual shared_ptr<SmileSection> smileSectionImpl(
                              const Date& optionDate) const;
        virtual shared_ptr<SmileSection> smileSectionImpl(
                              Time optionTime) const = 0;

        virtual Volatility volatilityImpl(const Date& d,
                                          Rate strike) const {
            return volatilityImpl(timeFromReference(d), strike);
        }
        virtual Volatility volatilityImpl(Time optionTime,
                                          Rate strike) const = 0;
    };

The semantics are back to normal, with the volatility being dependent on the exercise time. The structure of the class is as usual, too, but with a notable addition: besides the usual volatility method, the class declares a smileSection method that takes an exercise date (or the corresponding time or period) and returns an object that models the whole smile at that date and inherits from the base class SmileSection, shown in listing 3.21. The interface is modeled after that of the volatility class and shouldn’t need explanation, apart from noting that the time is fixed and doesn’t need to be passed as an argument to the various methods.

Listing 3.21: Partial interface of the SmileSection class.

    class SmileSection : public virtual Observable,
                         public virtual Observer {
      public:
        SmileSection(Time exerciseTime,
                     const DayCounter& dc = DayCounter());
        virtual ~SmileSection() {}

        virtual Real minStrike() const = 0;
        virtual Real maxStrike() const = 0;
        Real variance(Rate strike) const;
        Volatility volatility(Rate strike) const;
        virtual Real atmLevel() const = 0;
      protected:
        virtual Real varianceImpl(Rate strike) const;
        virtual Volatility volatilityImpl(Rate strike) const = 0;
    };

Simple as it seems, the addition of smile sections yields a new design that sees volatilities not as surfaces, but as collections of smiles at different times. This opens up the possibility to model the smile directly and to reuse the corresponding classes across different types of volatilities (say, for both cap/floors and swaptions).

However, we weren’t bold enough to switch completely to the new interface. The two representations (the surface and the series of smiles) still coexist in the base caplet-volatility class, leading to some disadvantages. Any derived class can implement volatilityImpl in terms of smileSectionImpl as

    Volatility volatilityImpl(Time t, Real strike) const {
        return smileSectionImpl(t).volatility(strike);
    }

but this is only convenient if we’re modeling the smile to begin with. If we’re modeling the volatility surface, instead, this design makes it a lot more cumbersome to implement a new class. There’s no easy way to implement smileSectionImpl in terms of volatilityImpl: we should return an object that’s able to call volatilityImpl from its own volatility method, but that would link the lifetimes of the smile section and the volatility surface, and in turn raise all kind of problems. We would probably end up writing a smile-section class that contains the same code as the volatility surface; therefore, we might as well drop volatilityImpl altogether.

Unfortunately, naive implementations of the smileSectionImpl method cause new objects to be allocated at each call, which is obviously not good for performance. Smarter implementations would need to cache objects, and with this comes more complexity. Thus, the smile section is an interesting concept, but maybe more trouble than it’s worth. It might be reduced in scope, and used as an implementation detail for classes that model the smile directly.

A final note on the OptionletVolatilityStructure class: unlike the classes we’ve seen so far, it also declares an overload of volatilityImpl that takes a date. It has a default implementation that converts the date to a time and calls the other overload, so writers of derived classes don’t need to override it; but it can increase accuracy when the derived class takes and stores dates as input.

Finally, the third hierarchy models swaption volatilities; its base class is the SwaptionVolatilityStructure, shown in listing 3.22.

Listing 3.22: Interface of the SwaptionVolatilityStructure class.

    class SwaptionVolatilityStructure
                              : public VolatilityTermStructure {
      public:
        ... // constructors, not shown
        Volatility volatility(const Period& optionTenor,
                              const Period& swapTenor,
                              Rate strike,
                              bool extrapolate = false) const;
        // various overloads, also for blackVariance and smileSection

        virtual const Period& maxSwapTenor() const = 0;
        Time maxSwapLength() const;
      protected:
        virtual Volatility volatilityImpl(Time optionTime,
                                          Time swapLength,
                                          Rate strike) const = 0;
        void checkSwapTenor(Time swapLength,
                            bool extrapolate) const;
    };

It has the same new features I just described for caplet volatilities (the use of smile sections and the overload of volatilityImpl) and a new shtick: the additional dimension given by the length of the underlying swap, which in turn brings a few more methods for specifying and checking the range of the corresponding argument.

That’s all for term structures. You’ll find plenty of examples in the library; I hope this chapter will help you make sense of them.