Monday, December 2, 2013

Chapter 3, part 6 of n: volatility term structures

Welcome back.

Two bit of news about the QuantLib site. The first is that we finally collected the material from the QuantLib User Meeting in Düsseldorf, and the slides for most of the talks are now available on the documentation page. The second is that the QuantLib site itself was renovated; I hope that the navigation is a bit more clear now, and that it will be simpler to find stuff.

As promised, this week's post has some new book content. At last, we're nearing the end of chapter 3; all that's missing is a couple of short sections on interest-rate volatilities.

Follow me on Twitter if you want to be notified of new posts, or add me to your circles, or subscribe via RSS: the widgets for that are in the sidebar, at the top right of the page. Also, make sure to check my Training page.

Term structures

Volatility term structures

There are so many types of volatility structures that finding common behavior between them is a bit of a stretch. In fact, I'm not sure that the base class we defined for them (the VolatilityTermStructure class, shown in listing 3.16) is a useful abstraction.

Listing 3.16: Interface of the VolatilityTermStructure class.
    class VolatilityTermStructure : public TermStructure {
      public:
        VolatilityTermStructure(BusinessDayConvention bdc,
                                const DayCounter& dc = DayCounter());
        VolatilityTermStructure(const Date& referenceDate,
                                const Calendar& cal,
                                BusinessDayConvention bdc,
                                const DayCounter& dc = DayCounter());
        VolatilityTermStructure(Natural settlementDays,
                                const Calendar& cal,
                                BusinessDayConvention bdc,
                                const DayCounter& dc = DayCounter());

        virtual BusinessDayConvention businessDayConvention() const {
            return bdc_;
        }
        Date optionDateFromTenor(const Period&) const {
            return calendar().advance(referenceDate(),
                                      p,
                                      businessDayConvention());
        }

        virtual Rate minStrike() const = 0;
        virtual Rate maxStrike() const = 0;
      protected:
        void checkStrike(Rate strike, bool extrapolate) const;
      private:
        BusinessDayConvention bdc_;
    };
The class adds two things to TermStructure, from which it inherits. The first is a method, optionDateFromTenor, that calculates the exercise date of an option from its tenor; to do this, it used the calendar provided by the base-class interface as well as a business-day convention stored in this class (which is passed to the constructors, and from which the usual inspector is provided). Instead, this functionality could be encapsulated in some kind of utility class and used elsewhere. (The idea of such date calculator was suggested years ago on the mailing list by someone who will forgive me if I can no longer recall nor find out his name.)

The second addition involves two pure virtual methods that return the minimum and maximum strike over which the term structure is defined and a protected method that checks a given strike against the defined range. Unfortunately, these don't make sense for a local volatility structure; but leaving them out would require yet another level of hierarchy to hold them (namely, an implied-vol structure class) so I'm not shocked to see them here instead.

Equity volatility structures

Equity and FX-rate Black volatilities are modeled by the BlackVolTermStructure class, shown in listing 3.17. Apart from its several constructors (which, as usual, forward their arguments to the base class and would be made unnecessary by constructor inheritance, introduced in C++11 [1]) the class defines the overloaded blackVol method to retrieve the volatility for a given exercise date or time; the blackVariance method for the corresponding variance (the product of the square of the volatility by the time); and the blackForwardVol and blackForwardVariance methods for the forward volatility and variance between two future dates.

Listing 3.17: Partial interface of the BlackVolTermStructure class.
    class BlackVolTermStructure : public VolatilityTermStructure {
      public:
        Volatility blackVol(const Date& maturity,
                            Real strike,
                            bool extrapolate = false) const;
        Volatility blackVol(Time maturity,
                            Real strike,
                            bool extrapolate = false) const;
        Real blackVariance(const Date& maturity,
                           Real strike,
                           bool extrapolate = false) const;
        Real blackVariance(Time maturity,
                           Real strike,
                           bool extrapolate = false) const;
        Volatility blackForwardVol(const Date& date1,
                                   const Date& date2,
                                   Real strike,
                                   bool extrapolate = false) const;
        Real blackForwardVariance(const Date& date1,
                                  const Date& date2,
                                  Real strike,
                                  bool extrapolate = false) const;
        // same two methods as above, taking two times
      protected:
        virtual Real blackVarianceImpl(Time t,
                                       Real strike) const = 0;
        virtual Volatility blackVolImpl(Time t,
                                        Real strike) const = 0;
    };
Following the Template Method pattern (no surprise there) all these methods are implemented by calling the protected and pure virtual blackVolImpl and blackVarianceImpl methods. The public interface adds range checking and, in the case of forward volatility or variance, the bit of logic required to calculate the forward values from the spot values at the two passed dates.

At the time of this writing, the BlackVolTermStructure class also defines a private static const data member dT that is no longer used—much like we still carry around an appendix, or a vestigial tailbone. By the time you read this, I hope to have it removed. The data member, I mean. Not my appendix.

As usual, adapters are provided to write only one of the blackVolImpl or the blackVarianceImpl method; they are shown in listing 3.18. (For simple examples of either kind, you can look at the ConstantBlackVol and the misleadingly-named ImpliedVolTermStructure classes in the library.) It is unfortunate that the name of one of the adapters, the BlackVolatilityTermStructure class, is so confusingly similar to the name of the base class. I'm open to suggestions for changing either one in a future version of the library.

Listing 3.18: Adapters for the BlackVolTermStructure class.
    class BlackVolatilityTermStructure
                        : public BlackVolTermStructure {
        ... // constructors, not shown
      protected:
        Real blackVarianceImpl(Time maturity, Real strike) const {
            Volatility vol = blackVolImpl(t, strike);
            return vol*vol*t;
        }
    };

    class BlackVarianceTermStructure
                        : public BlackVolTermStructure {
        ... // constructors, not shown
      protected:
        Volatility blackVolImpl(Time t, Real strike) const {
            Time nonZeroMaturity = (t==0.0 ? 0.00001 : t);
            Real var = blackVarianceImpl(nonZeroMaturity, strike);
            return std::sqrt(var/nonZeroMaturity);
        }
    };

Aside: Interpolations and extrapolations.

One of the available volatility classes is the BlackVarianceSurface class, which interpolates a matrix of quoted Black volatilities. I won't describe it here, since you're probably sick of term-structure examples by now; but it has a couple of interesting features.

The first is that the interpolation can be changed once the structure is built; the relevant method is
    template <class Interpolator>
    void setInterpolation(const Interpolator& i = Interpolator()) {
        varianceSurface_ =
            i.interpolate(times_.begin(), times_.end(),
                          strikes_.begin(), strikes_.end(),
                          variances_);
        notifyObservers();
    }
This is not possible in other interpolated curves, in which the type of the interpolation is a template argument and is fixed at instantiation; see, for instance, the PiecewiseYieldCurve class template in this post. The difference is that BlackVarianceSurface doesn't need to store the interpolator, and thus doesn't need to know its type outside the setInterpolation method.

The second feature of BlackVarianceSurface is the possibility to customize the kind of extrapolation to use when the passed strike is outside the range of the interpolation. It is possible either to extend the underlying interpolation or to extrapolate flatly the value at the end of the range; the behavior at either end can be specified independently.

Now, it would be nice if this behavior could be extracted in some base class and reused. The choice of extrapolation can be implemented in a generic way; given any interpolation f defined up to xmax (or down to xmin), and given an x > xmax, the two choices can be realized by returning f(x) for extension of f(xmax) for flat extrapolation.

The Extrapolator class would seem the obvious choice for defining such behavior; but, unfortunately, this wouldn't work if we still want to make different choices on different boundaries. As a base class, Extrapolator would have no knowledge of the fact that, for instance, an interest-rate structure is defined over a time range whose lower bound is 0, while a volatility surface also has a range of strikes. Since it can't distinguish between boundaries, Extrapolator can't define an interface that specifies behavior on any of them; we'd be forced to make a single choice and apply it everywhere.

Therefore, the only possibility I see for code reuse at this time would be to define a polymorphic Extrapolation class, code the different behaviors into derived classes, and store the required number of instances into any given term structure.

Bibliography

[1] International Standards Organization, Programming Languages – C++, International Standard ISO/IEC 14882:2011. Available as a working draft.

Share this post: