Chapter 4, part 2 of 5: floating-rate coupons
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.
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.
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.
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.
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.
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
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.
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.
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,
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.