Welcome back.

Today’s post is the second part of a series that started here and covers chapter 4 of my book.

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.

Floating-rate coupons

The FloatingRateCoupon class is emblematic of the life of most software. It started simple, became more complex as time went by, and might now need some refactoring; its current implementation (sketched in listing 4.4) has a number of issues that I’ll point out as I describe it. (Unless they can be fixed without breaking backward compatibility, we’ll have to live with any shortcomings until the yet unplanned release 2.0.)

Listing 4.4: Sketch of the FloatingRateCoupon class.

    class FloatingRateCoupon : public Coupon, public Observer {
      public:
        FloatingRateCoupon(
                    const Date& paymentDate,
                    const Real nominal,
                    const Date& startDate,
                    const Date& endDate,
                    const Natural fixingDays,
                    const shared_ptr<InterestRateIndex>& index,
                    const Real gearing = 1.0,
                    const Spread spread = 0.0,
                    const Date& refPeriodStart = Date(),
                    const Date& refPeriodEnd = Date(),
                    const DayCounter& dayCounter = DayCounter(),
                    bool isInArrears = false);

        Real amount() const;
        Rate rate() const;
        Real accruedAmount(const Date&) const;
        DayCounter dayCounter() const;

        const shared_ptr<InterestRateIndex>& index() const;
        Natural fixingDays() const;
        Real gearing() const;
        Spread spread() const;
        virtual Date fixingDate() const;
        virtual Rate indexFixing() const;
        virtual Rate convexityAdjustment() const;
        virtual Rate adjustedFixing() const;
        bool isInArrears() const;

        void update();
        virtual void accept(AcyclicVisitor&);

        void setPricer(const shared_ptr<FloatingRateCouponPricer>&);
        shared_ptr<FloatingRateCouponPricer> pricer() const;
      protected:
        Rate convexityAdjustmentImpl(Rate fixing) const;
        // data members
    };

The first issue might be the name itself: FloatingRateCoupon suggests a particular type of coupon, i.e., one that pays some kind of LIBOR rate. However, the class is more general that this and can model coupons paying different kind of rates—CMS or whatnot. Unfortunately, other names might be even worse; for instance, the one I briefly considered while writing this paragraph (VariableRateCoupon) suggests that the definition of the rate might change besides the value, which is not the case. All in all, I don’t think there’s any point in changing it now.

But enough with my ramblings; let’s look at the implementation.

    FloatingRateCoupon::FloatingRateCoupon(
                         const Date& paymentDate, const Real nominal,
                         ...other arguments...)
    : Coupon(nominal, paymentDate,
             startDate, endDate, refPeriodStart, refPeriodEnd),
      /* store the other data members */ {
        registerWith(index_);
        registerWith(Settings::instance().evaluationDate());
    }

The constructor takes (and forwards to the base-class constructor) the dates and notional needed by the Coupon class, a day counter, and a number of arguments related to the interest-rate fixing. These include an instance of the InterestRateIndex class taking care of the rate calculation (see this post for details on this class; for the purpose of this section, it is enough to note that it can retrieve past index fixings and forecast future ones) as well as other details of the fixing; namely, the number of fixing days, whether or not the rate is fixed in arrears, and an optional gearing and spread. The arguments that are not passed to the Coupon constructor are stored in data members; moreover, the instance registers as an observer of its interest-rate index and of the current evaluation date. As we will see shortly, the fixingDays and inArrears arguments are used to determine the fixing date. When given, the gearing and spread cause the coupon to pay a rate \( R = g × F + s \) where \( g \) is the gearing, \( F \) is the fixing of the underlying index, and \( s \) is the spread. (In principle, one could model reverse-floater coupons by passing a negative gearing; but in practice, this is not advisable as it would neglect the implicit floor at zero that such coupons usually sport.)

This choice of the constructor signature (and therefore, of the stored data members) implies a constraint on the kinds of coupon that can be adequately modeled by this class. We are limiting them to those whose rate is based on the fixing of a single index; others, such as those paying the spread between two rates, are excluded. True, they can be forcibly bolted on the FloatingRateCoupon class by creating some kind of spread class and inheriting it from InterestRateIndex; but this would somewhat break the mapping between the financial concepts being modeled and the class hierarchy, since the spread between two indexes is not itself an index (or at least, it is not usually considered one).

Other methods implement the required CashFlow and Coupon interfaces.

    Real FloatingRateCoupon::amount() const {
        return rate() * accrualPeriod() * nominal();
    }

    Rate FloatingRateCoupon::rate() const {
        pricer_->initialize(*this);
        return pricer_->swapletRate();
    }

Curiously enough, even though floating-rate coupons are more complex than fixed-rate ones, the amount method has the simpler implementation: it multiplies the rate by the accrual time and the nominal. This seems to support moving it to the Coupon class. The accrualAmount method has a similar implementation (not shown in the listing) with a different accrual time. For the time being, I’ll skip the rate method; we’ll come back to its implementation in a short while.

Next come a number of inspectors. Besides dayCounter (which is required by the Coupon interface) we have those returning the parameters specific to floating-rate coupons, such as index, fixingDays, gearing, and spread. Finally, a number of methods are defined which implement some business logic.

    Date FloatingRateCoupon::fixingDate() const {
        Date d = isInArrears_ ? accrualEndDate_ : accrualStartDate_;
        return index_->fixingCalendar().advance(
                                  d, -fixingDays_, Days, Preceding);
    }

    Rate FloatingRateCoupon::indexFixing() const {
        return index_->fixing(fixingDate());
    }

The first two methods are fixingDate and indexFixing. They are both straightforward enough. The fixingDate method checks whether or not the coupon fixes in arrears, chooses a reference date accordingly (the end date of the coupon when in arrears, the start date otherwise) and moves it backward for the required fixing days; holidays are skipped according to the index calendar. The indexFixing method asks the stored index for its fixing at the relevant date.

Although the implementations of both methods are, as I said, straightforward, there is an issue with their signature. Just as the constructor assumes a single index, these two methods assume a single index fixing. This results in a loss of generality; for instance, it excludes coupons that pay the average fixing of an index over a set of several fixing dates, or that compounds rates over a number of sub-periods of the coupon life.

The last methods deal with the convexity adjustment (if any) to apply to the index fixing.

    Rate FloatingRateCoupon::adjustedFixing() const {
        return (rate()-spread())/gearing();
    }

    Rate FloatingRateCoupon::convexityAdjustmentImpl(Rate f) const {
       return (gearing() == 0.0 ? 0.0 : adjustedFixing()-f);
    }

    Rate FloatingRateCoupon::convexityAdjustment() const {
        return convexityAdjustmentImpl(indexFixing());
    }

The adjustedFixing method is written in terms of the rate method and inverts the \( R = g × F’ + s \) formula to return the adjusted fixing \( F’ = (R - s)/g \). Its implementation is rather fragile, since it depends on the previous relationship between the rate and the fixing. If a derived class were to modify it (for instance, by adding a cap or floor to the paid rate—which has happened already, as we’ll see later) this method should be modified accordingly. Unfortunately, this is left to the programmer; there’s no language feature that can force one to override two methods at the same time.

The convexityAdjustment method returns the adjustment alone by taking the difference between the original fixing and the adjusted one. It does this by delegating to a protected convexityAdjustmentImpl method; this is a leftover of a previous implementation, in which the presence of a separate method allowed us to optimize the calculation. This is no longer needed in the current implementation; for the sake of simplicity, the protected method might be inlined into the public one and removed.

Back to the rate method. In previous versions of the library, it was implemented as you might have expected—something like

    Rate f = index_->fixing(fixingDate());
    return gearing_ * (f + convexityAdjustment(f)) + spread_;

based on the fixing provided by the stored InterestRateIndex instance. (As you might have noted, the current convexityAdjustment implementation would cause an infinite recursion together with the code above. Its implementation was also different at that time and returned an explicit calculation of the adjustment.) As much as I liked its simplicity, that implementation had to be changed when a new requirement came in: namely, that floating-rate coupons may be priced in several different ways. This was an issue that we had already faced with the Instrument class (see this post for details).

Like we did for Instrument, we used the Strategy pattern [1] to code our solution. However, the implementation we chose in this case was different. On the one hand, the context was more specific; we knew what kind of results we wanted from the calculations. On the other hand, FloatingRateCoupon had a richer interface than Instrument. This allowed us to avoid the opaque argument and result structures used in the implementation of the PricingEngine class.

The resulting FloatingRateCouponPricer class is sketched in listing 4.5.

Listing 4.5: Sketch of the FloatingRateCouponPricer class.

    class FloatingRateCouponPricer: public virtual Observer,
                                    public virtual Observable {
      public:
        virtual ~FloatingRateCouponPricer();
        virtual void initialize(const FloatingRateCoupon&) = 0;
        virtual Rate swapletRate() const = 0;
        virtual Rate capletRate(Rate effectiveCap) const = 0;
        virtual Rate floorletRate(Rate effectiveFloor) const = 0;
        // other methods
    };

It declares methods for returning a number of rates: swapletRate returns the coupon rate, adjusted for convexity, gearing and spread (if any); capletRate returns the adjusted rate paid by a cap on the index fixing; and floorletRate returns does the same for a floor. (The class declares other methods, not shown here.) The initialize method causes the pricer to store a reference to the passed coupon that will provide any information not passed to the other methods as part of the argument list.

The FloatingRateCoupon class defines a setPricer method that takes a pricer instance and stores it into the coupon. (The implementation is not as simple as that, but we can skip the details here.) Finally, the rate method is defined as shown below: the stored pricer is initialized with the current coupon and the calculated rate is returned.

    Rate FloatingRateCoupon::rate() const {
        pricer_->initialize(*this);
        return pricer_->swapletRate();
    }

You might have noted that initialization is performed in the rate method, rather than in the setPricer method. This is done because the same pricer instance can be used for several coupons; therefore, one must make sure that the current coupon is stored each time the pricer is asked for a result. A previous calculation might have stored a different reference—which by now might even be dangling.

Of course, this implementation is not entirely satisfactory (and furthermore, it hinders parallelism, which is becoming more and more important since the last couple of years; as of now, we cannot pass the same pricer to several coupons and evaluate them simultaneously). It might have been a better design to define the pricer methods as, for instance,

    Rate swapletRate(const FloatingRateCoupon& coupon);

and avoid the repeated call to initialize. Once again, I have to admit that we are guilty of premature optimization. We thought that, when swapletRate and other similar methods were called in sequence (say, to price a floored coupon), a separate initialization method could precompute some accessory quantities that would be needed in the different rate calculations; and we let that possibility drive the design. As it turned out, most pricers do perform some computations in their initialize method; but in my opinion, not enough to justify doing a Texas two-step to calculate a rate.

A refreshing remark to end this section. If you want to implement a specific floating-rate coupon but you don’t care for the complexity added by the pricer machinery, you can inherit your class from FloatingRateCoupon, override its rate method to perform the calculation directly, and forget about pricers. They can be added later if the need arises.

Aside: keeping one’s balance.

The assumptions built into the FloatingRateCoupon class (single index, single fixing date) are, of course, unfortunate. However, it is caused by the need to balance generality and usefulness in the class interface; the more general a class is, the fewer inspectors it can have and the less information it can return. The problem could be solved in part by adding more levels of inheritance (we might do that, if the need arises); but this adds complexity and brings its own problems. The current implementation of FloatingRateCoupon is probably not the best compromise; but it’s one we can live with for the time being.

Bibliography

[1] E. Gamma, R. Helm, R. Johnson and J. Vlissides, Design Patterns: Element of Reusable Object-Oriented Software. Addison-Wesley, 1995.