3 votos

Cómo sumar curvas de tipos de interés en QuantLib

Código C++ extraído de Bonds.cpp y ligeramente modificado:

#include <ql/quantlib.hpp>
#include <boost/timer.hpp>
#include <iostream>
#include <iomanip>

using namespace QuantLib;

int main(int, char* []) {

    try {

        // Just a couple of parameters

        Calendar calendar = TARGET();
        Date settlementDate(18, September, 2008);
        settlementDate = calendar.adjust(settlementDate);
        Integer fixingDays = 3;
        Natural settlementDays = 3;
        Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days);
        Settings::instance().evaluationDate() = todaysDate;

        /* Now let's introduce two curves: the first one is a swap curve built from 
        deposits and IRS, the second one is a credit spread curve which should be 
        added to the former one to get a proper yield curve */

        // Swap curve

        DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA);
        double tolerance = 1.0e-5;

        // Deposits

        Rate d1wQuote = 0.043375;
        Rate d1mQuote = 0.031875;
        Rate d3mQuote = 0.0320375;
        Rate d6mQuote = 0.03385;
        Rate d9mQuote = 0.0338125;
        Rate d1yQuote = 0.0335125;

        boost::shared_ptr<Quote> d1wRate(new SimpleQuote(d1wQuote));
        boost::shared_ptr<Quote> d1mRate(new SimpleQuote(d1mQuote));
        boost::shared_ptr<Quote> d3mRate(new SimpleQuote(d3mQuote));
        boost::shared_ptr<Quote> d6mRate(new SimpleQuote(d6mQuote));
        boost::shared_ptr<Quote> d9mRate(new SimpleQuote(d9mQuote));
        boost::shared_ptr<Quote> d1yRate(new SimpleQuote(d1yQuote));

        // IRS

        Rate s2yQuote = 0.0295;
        Rate s3yQuote = 0.0323;
        Rate s5yQuote = 0.0359;
        Rate s10yQuote = 0.0412;
        Rate s15yQuote = 0.0433;

        boost::shared_ptr<Quote> s2yRate(new SimpleQuote(s2yQuote));
        boost::shared_ptr<Quote> s3yRate(new SimpleQuote(s3yQuote));
        boost::shared_ptr<Quote> s5yRate(new SimpleQuote(s5yQuote));
        boost::shared_ptr<Quote> s10yRate(new SimpleQuote(s10yQuote));
        boost::shared_ptr<Quote> s15yRate(new SimpleQuote(s15yQuote));

        // Rate Helper

        // Deposits
        DayCounter depositDayCounter = Actual360();

        boost::shared_ptr<RateHelper> d1w(new DepositRateHelper(
                Handle<Quote>(d1wRate),
                1*Weeks, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        boost::shared_ptr<RateHelper> d1m(new DepositRateHelper(
                Handle<Quote>(d1mRate),
                1*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        boost::shared_ptr<RateHelper> d3m(new DepositRateHelper(
                Handle<Quote>(d3mRate),
                3*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        boost::shared_ptr<RateHelper> d6m(new DepositRateHelper(
                Handle<Quote>(d6mRate),
                6*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        boost::shared_ptr<RateHelper> d9m(new DepositRateHelper(
                Handle<Quote>(d9mRate),
                9*Months, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));
        boost::shared_ptr<RateHelper> d1y(new DepositRateHelper(
                Handle<Quote>(d1yRate),
                1*Years, fixingDays,
                calendar, ModifiedFollowing,
                true, depositDayCounter));

        // Setup IRS
        Frequency swFixedLegFrequency = Annual;
        BusinessDayConvention swFixedLegConvention = Unadjusted;
        DayCounter swFixedLegDayCounter = Thirty360(Thirty360::European);
        boost::shared_ptr<IborIndex> swFloatingLegIndex(new Euribor6M);

        const Period forwardStart(1*Days);

        boost::shared_ptr<RateHelper> s2y(new SwapRateHelper(
                Handle<Quote>(s2yRate), 2*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> s3y(new SwapRateHelper(
                Handle<Quote>(s3yRate), 3*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> s5y(new SwapRateHelper(
                Handle<Quote>(s5yRate), 5*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> s10y(new SwapRateHelper(
                Handle<Quote>(s10yRate), 10*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> s15y(new SwapRateHelper(
                Handle<Quote>(s15yRate), 15*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));

        // A depo-swap curve
        std::vector<boost::shared_ptr<RateHelper> > depoSwapInstruments;
        depoSwapInstruments.push_back(d1w);
        depoSwapInstruments.push_back(d1m);
        depoSwapInstruments.push_back(d3m);
        depoSwapInstruments.push_back(d6m);
        depoSwapInstruments.push_back(d9m);
        depoSwapInstruments.push_back(d1y);
        depoSwapInstruments.push_back(s2y);
        depoSwapInstruments.push_back(s3y);
        depoSwapInstruments.push_back(s5y);
        depoSwapInstruments.push_back(s10y);
        depoSwapInstruments.push_back(s15y);
        boost::shared_ptr<YieldTermStructure> depoSwapTermStructure(
                new PiecewiseYieldCurve<Discount,LogLinear>(
                        settlementDate, depoSwapInstruments,
                        termStructureDayCounter,
                        tolerance));

        return 0;

    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
        return 1;
    } catch (...) {
        std::cerr << "unknown error" << std::endl;
        return 1;
    }
}

Si no me equivoco, hasta ahora hemos obtenido una especie de curva de descuento sin riesgo.

Ahora permítanme introducir una curva adicional de diferencial de crédito en forma de un objeto manejado por RateHelper (un fragmento que se inserta después de la curva depo-swap del código anterior):

        ...
        Rate d1ySpread = 0.013;
        Rate d2ySpread = 0.011;
        Rate d3ySpread = 0.022;
        Rate d6ySpread = 0.0238;
        Rate d9ySpread = 0.0238;
        Rate d10ySpread = 0.0239;

        boost::shared_ptr<Quote> d1ySpreadRate(new SimpleQuote(d1ySpread));
        boost::shared_ptr<Quote> d2ySpreadRate(new SimpleQuote(d2ySpread));
        boost::shared_ptr<Quote> d3ySpreadRate(new SimpleQuote(d3ySpread));
        boost::shared_ptr<Quote> d6ySpreadRate(new SimpleQuote(d6ySpread));
        boost::shared_ptr<Quote> d9ySpreadRate(new SimpleQuote(d9ySpread));
        boost::shared_ptr<Quote> d10ySpreadRate(new SimpleQuote(d10ySpread));

        boost::shared_ptr<RateHelper> credit1y(new SwapRateHelper(
                Handle<Quote>(d1ySpreadRate), 1*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> credit2y(new SwapRateHelper(
                Handle<Quote>(d2ySpreadRate), 2*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> credit3y(new SwapRateHelper(
                Handle<Quote>(d3ySpreadRate), 3*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> credit6y(new SwapRateHelper(
                Handle<Quote>(d6ySpreadRate), 6*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> credit9y(new SwapRateHelper(
                Handle<Quote>(d9ySpreadRate), 9*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));
        boost::shared_ptr<RateHelper> credit10y(new SwapRateHelper(
                Handle<Quote>(d10ySpreadRate), 10*Years,
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, Handle<Quote>(),forwardStart));

        std::vector<boost::shared_ptr<RateHelper> > creditInstruments;
        creditInstruments.push_back(credit1y);
        creditInstruments.push_back(credit2y);
        creditInstruments.push_back(credit3y);
        creditInstruments.push_back(credit6y);
        creditInstruments.push_back(credit9y);
        creditInstruments.push_back(credit10y);
        boost::shared_ptr<YieldTermStructure> creditTermStructure(
                new PiecewiseYieldCurve<Discount,LogLinear>(
                        settlementDate, creditInstruments,
                        termStructureDayCounter,
                        tolerance));
        ...

El objeto creditTermStructure podría representar, por ejemplo, una curva de diferencial de CDS, o una estructura de plazos de este tipo.

Teniendo tanto el depoSwapTermStructure y el creditTermStructure construido por el código anterior, me gustaría producir un nuevo objeto de clase YieldTermStructure mediante la suma depoSwapTermStructure y creditTermStructure teniendo en cuenta los nudos temporales desalineados, es decir, el código debe sumar los tipos por los tenores adecuados (1Y depo-swap + 1Y credit spread, 2Y depo-swap + 2Y credit spread... y así sucesivamente. A partir de los vencimientos que carecen de diferencial de crédito, como el de 18Y, se debe interpolar nudos conocidos).

¿Cómo es posible hacer algo así utilizando QuantLib ?

6voto

Brad Tutterow Puntos 5628

No hay clase en este momento para añadir dos curvas como quieras, pero no será muy difícil escribirlo.

Lo más parecido que se puede encontrar en la biblioteca es el ZeroSpreadedTermStructure que muestra la idea general: hereda de YieldTermStructure (a modo de ZeroYieldStructure ) toma un YieldTermStructure y una extensión (constante, en este caso) y anular sus propios métodos para que devuelvan la suma de los dos: por ejemplo

Rate ZeroSpreadedTermStructure::forwardImpl(Time t) const {
    return originalCurve_->forwardRate(t, t, comp_, freq_, true)
        + spread_->value();
}

En tu caso, tendrás que escribir una clase similar que tome dos Handle s a YieldTermStructure en su lugar. Sorprendentemente, esto le facilitará el trabajo. Todavía puede tomar ZeroSpreadedTermStructure como modelo para otras tareas como el registro con los observadores necesarios, pero todo lo que hay que hacer en este caso es heredar de YieldTermStructure directamente y anular el único discountImpl método:

DiscountFactor YourClass::discountImpl(Time t) const {
    return baseCurve_->discount(t, true)
         * spreadCurve_->discount(t, true);
}    

ya que la suma de los tipos implica el producto de los correspondientes factores de descuento.

Si necesita más información, una descripción del YieldTermStructure y los métodos que implementa (que es un poco largo para incluirlo aquí) está disponible en http://implementingquantlib.blogspot.com/2013/09/chapter-3-part-2-of-n-yield-term.html y los puestos posteriores.

Y, por supuesto, una vez que tenga su curva funcionando, puede contribuir a QuantLib. La forma más fácil sería conseguir una cuenta en GitHub y seguir las instrucciones del readme en https://github.com/lballabio/quantlib .

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X