Floating coupons

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Floating coupons

Luigi Ballabio-4
Hi all,
     here is where I step forward and show my ignorance, which in Lent is
kind of appropriate after all :)

The problem in short: FloatingRateCoupon has outgrown its definition.

It was born as a coupon at par on a term structure, i.e., one whose
amount is calculated simply as
(discount(start)/discount(end)-1.0) * nominal
as opposed to
liborFixing * accrualPeriod * nominal.

Our benevolent dictator's rationale for the above choice was that due to
holidays and date adjustments, the end date for a 6-months coupon could be a
few days off the end date for the fixing of the corresponding 6-months Libor.
Therefore, if the second formula was used, one would be accruing a rate over a
period which is not exactly its tenor, which causes a (small) convexity error.
This does not apply to the first formula, in which the rate is forecast and
accrued over the same period.

Which didn't persuade me at all; while it is true that there is no convexity
error in the first formula, an error is being made just the same: stepping
out of the model and into the real world, it is the Libor fixing that the
coupon
will actually pay, not the forward rate between its start and end dates.

So I step forward and ask: which formula has the largest error? Is there any
reason to use the one or the other?


The reason I ask is that since that choice, FloatingRateCoupon has grown a
few clumsy extremities, such as:

1) the possibility to add a spread was added. This forced the coupon to
    take a Xibor instance as a data member from which to retrieve a
    day counter for accrual period calculation (since the spread gave an
    additional amount spread * accrualPeriod * nominal);
2) the possibility to specify a number of fixing days was added;
3) the retrieving of past fixings was delegated to the Xibor data member.

Thus, FloatingRateCoupon was made into a sorry excuse for a coupon class.
In particular:

a) because of 1) and 2), the coupon is no longer at par. However, it
    retains the limitations of the par coupon calculations, which prevent
    it from growing more useful: for instance, it is not possible to use
    a different day counter for accruing. Say 'bye' to basis swaps.
b) the parameter list is actually misleading: which curve is used for
    forecast in the following code?

    Handle<TermStructure> curve1 = ...;
    Handle<TermStructure> curve2 = ...;
    // the first one is passed to the index
    Handle<Xibor> index(new Euribor(6,Months,
                                    RelinkableHandle<TermStructure>(curve1));
    // the second one is passed to the coupon
    FloatingRateCoupon coupon(10000, index,
                              RelinkableHandle<TermStructure>(curve2).
                              startDate, endDate, fixingDays, spread);
    // which one is used here?
    std::cout << coupon.amount() << std::endl;

    As a matter of fact, it is the second.
    But one shouldn't have to go and read the amount() implementation to know.
    It should be straightforward---which it isn't.


What I would do is:
1) drop this FloatingCoupon mix which cannot be amended;
2) keep a ParCoupon class which only does what its definition claims
    (no spread, no index, no fixing days, no past fixings, forecast only)
3) write and use a full featured IndexedCoupon class which delegates the
    forecasting of the fixing to an Index class and does not have any of the
    limitations of ParCoupon. A hook for a convexity adjustment calculation
    can be put in place whose default implementation does nothing.

But then again, maybe I don't know jack.

Any thought? Advice? Screams?

Bye,
         Luigi