On the Design Board: From Single- to Multi-Curve

Introduction

Standard fixed-income applications make a larger and larger use of the multi-curve framework to price products and hedge risks. For whatever reason this is the case, it is useful to know how to implement such a framework.

We have already talked about multi-curves in the past. Here we gave a list useful references and here we illustrated the mean features of risk metrics and sensitivity patterns. In this blog, we describe how to design the multi-curve framework. We do not claim that this is the only way or the best way. This is one possible way, which however turned out to work quite well within our system and happened to be easily integrated into our library.

Code snippets that will be shown below have been developed in C# using Visual Studio.

Starting Point

Our starting point is the single-curve framework. This contains implementations of yield curve constructions from various financial instruments (e.g. cash, swaps, etc.). The single curve framework is implemented within its own namespace:

namespace nl.uglyduckling.finlib.curve.singlecurve

Within this namespace we define curve and instrument interfaces.

A singlecurve.ICurve type defines method to compute fixed-income quantities, such as zero rates and discount factors, and to return curve properties, such as today's date and interpolator type. An example is given here:

namespace nl.uglyduckling.finlib.curve.singlecurve
{
   public interface ICurve
   {
      double DiscountFactor(Date start, Date end);
      ZeroRate ZeroRate(Date start, Date end);
      Date TodaysDate();
      Nodes Nodes();
      Type GetInterpolatorType();
      IInterpolator GetInterpolator();
      IDayCountConvention DayCountConvention();
      Currency Currency();
      Matrix HedgingMatrixPi();
      Matrix HedgingMatrixPsi();
      // etc..
   }
}

and

namespace nl.uglyduckling.finlib.curve.singlecurve
{
   public interface IZeroCurve : ICurve 
   {
      void AddZeroRate(double rate, IInstrument instrument);
   }
}

The AddZeroRate method allows to add any instrument to the curve. The singlecurve.IInstrument type is specified by the interface:

namespace nl.uglyduckling.finlib.curve.singlecurve
{
   public interface IInstrument 
   {
      IZeroCurve AddToCurve(IZeroCurve currentCurve);
      Date StartDate();
      Date EndDate();
      Date MovedEndDate();
      double Rate { get; }
      ITenor Tenor(); 
      double PresentValue(ICurve curve);
      // etc.. 
   }
}

It defines basic methods to return instruments properties, such as rate and start date, as well as the AddToCurve method to add the instrument to the curve that uses such instrument as node point.

Once the instrument has been added to the curve, the curve automatically figures out which zero rate corresponds to that instrument and the curve is then bootstrapped.

Note the presence of the PresentValue(ICurve curve) method: it returns the price of the instrument, computed using the yield curve in the argument. We will come back to this method later.

Additional Types and Wrappers

How can we re-use the work done for the single curve when we move to the multi curve? We simply use wrappers for curves and instruments.

Curve Wrappers

The first thing to do is to create a separate namespace for the multi curve:

namespace nl.uglyduckling.finlib.curve.multicurve

Then we wrap a single curve into a bigger object that contains:

  • the single curve
  • other additional properties that  identify the particular curve

Hence we define a new multicurve.ICurveId type as

namespace nl.uglyduckling.finlib.curve.multicurve
{
   public interface ICurveId
   {
      IMarketId MarketId();
      ITenor Tenor();
      bool Same(ICurveId curveId);
      bool IsDiscount();
   }
}

The curve Id specifies market (e.g. currency) and tenor as well as whether the curve is used for discounting. Our curve wrapper will be then defined as

namespace nl.uglyduckling.finlib.curve.multicurve
{
   public interface ICurveWrapper
   {
      Date TodaysDate { get; }
      Date StartDate { get; }
      ICurveId CurveId { get; }
      ICurve Curve { get; }
 }
}

In this way we can differentiate between a EUR curve from a US curve, a 3M-tenor curve from a 6M-tenor curve, a discount curve from a tenor curve, etc..

Instrument Wrappers

A similar approach is used to attach an instrument to a specific curve. This is relevant in two situations: as an instrument, it needs to know to which curve it belongs and as a product it needs to know which curve to use for pricing purposes.

This is achieved within the same namespace

namespace nl.uglyduckling.finlib.curve.multicurve

by the following instrument wrapper:

namespace nl.uglyduckling.finlib.curve.multicurve
{
   public interface IInstrument : singlecurve.IInstrument
   {
      singlecurve.IInstrument GetInstrument();
      ICurveId CurveId { get; }
   }
}

Hence, an object of type multicurve.IInstrument is also of type singlecurve.IInstrument and contains a method to return the underlying singlecurve.IInstrument.

How can we price an instrument using a multi curve?

Any instrument can always be considered a financial product with a fair price determined by the current market situation. In fact, in the single-curve framework we had the PresentValue(ICurve curve) method that returned the price of the product given the current yield curve. Similarly, in the multi-curve framework there will be an analogous method PresentValue(IMultiCurve multiCurve) that we can add into our instrument type. This method will return the price of the instrument given a multi-curve. The instrument will know which discounting and tenor curves to use.

namespace nl.uglyduckling.finlib.curve.singlecurve
{
   public interface IInstrument 
   {
      double PresentValue(ICurve curve);
      double PresentValue(IMultiCurve multiCurve);
      // etc..
   }
}

In this was we can evaluate the price of each product using both the single-curve and the multi-curve framework.

Multi-Curve Builder

With our notation, a multi curve is a collection of curve wrappers that have been bootstrapped out of a set of instrument wrappers. We can think of the final multi-curve as a type that implements the following interface

namespace nl.uglyduckling.finlib.curve.multicurve
{
   public interface IMultiCurve 
   {
     ICurveWrapper GetCurve(ICurveId curveId);
     List<ICurveWrapper> ListCurves();
     List<ICurveWrapper> ListCurves(IMarketId marketId);
     ICurveWrapper GetDiscountCurve(IMarketId marketId);
     // etc..
   }
}

In other words, a multi curve is nothing else then a wrapper of a list of curve wrappers!

The actual multi-curve bootstrap is implemented somewhere else. In particular, we use a multi-curve builder milticurve.IMCBuilder:

namespace nl.uglyduckling.finlib.curve.multicurve
{
   public interface IMCBuilder
   {
      IMultiCurve GetMultiCurve();
   }
}

Given a set of instruments (better, instrument wrappers), the builder figures out which of them are used for discounting and which ones are used for the various tenor curves. The builder also determines market properties, such as currencies, and for each market constructs the corresponding multi curve. For each market, the multi-curve builder bootstraps first the unique discounting curve using the single-curve framework, then it bootstraps all the other tenor curves using the previously-bootstrapped discounting curve. Finally the resulting list of curve wrappers is wrapped up into the returned multi-curve.

Leave a Reply

Your email address will not be published. Required fields are marked *