C++

Bonds

/*!
 Bonds
 */
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  This example shows how to set up a term structure and then price
    some simple bonds. The last part is dedicated to peripherical
    computations such as "Yield to Price" or "Price to Yield"
 */

// the only header you need to use QuantLib
#include <ql/quantlib.hpp>

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

using namespace QuantLib;

#ifdef BOOST_MSVC
#  ifdef QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN
#    include <ql/auto_link.hpp>
#    define BOOST_LIB_NAME boost_system
#    include <boost/config/auto_link.hpp>
#    undef BOOST_LIB_NAME
#    define BOOST_LIB_NAME boost_thread
#    include <boost/config/auto_link.hpp>
#    undef BOOST_LIB_NAME
#  endif
#endif


#if defined(QL_ENABLE_SESSIONS)
namespace QuantLib {

Integer sessionId() { return 0; }

}
#endif


int main(int, char* []) {

    try {

        boost::timer timer;
        std::cout << std::endl;

        /*********************
         ***  MARKET DATA  ***
         *********************/

        Calendar calendar = TARGET();

        Date settlementDate(18, September, 2008);
        // must be a business day
        settlementDate = calendar.adjust(settlementDate);

        Integer fixingDays = 3;
        Natural settlementDays = 3;

        Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days);
        // nothing to do with Date::todaysDate
        Settings::instance().evaluationDate() = todaysDate;

        std::cout << "Today: " << todaysDate.weekday()
        << ", " << todaysDate << std::endl;

        std::cout << "Settlement date: " << settlementDate.weekday()
        << ", " << settlementDate << std::endl;


        // Building of the bonds discounting yield curve

        /*********************
         ***  RATE HELPERS ***
         *********************/

        // RateHelpers are built from the above quotes together with
        // other instrument dependant infos.  Quotes are passed in
        // relinkable handles which could be relinked to some other
        // data source later.

        // Common data

        // ZC rates for the short end
         Rate zc3mQuote=0.0096;
         Rate zc6mQuote=0.0145;
         Rate zc1yQuote=0.0194;

         boost::shared_ptr<Quote> zc3mRate(new SimpleQuote(zc3mQuote));
         boost::shared_ptr<Quote> zc6mRate(new SimpleQuote(zc6mQuote));
         boost::shared_ptr<Quote> zc1yRate(new SimpleQuote(zc1yQuote));

         DayCounter zcBondsDayCounter = Actual365Fixed();

         boost::shared_ptr<RateHelper> zc3m(new DepositRateHelper(
                 Handle<Quote>(zc3mRate),
                 3*Months, fixingDays,
                 calendar, ModifiedFollowing,
                 true, zcBondsDayCounter));
         boost::shared_ptr<RateHelper> zc6m(new DepositRateHelper(
                 Handle<Quote>(zc6mRate),
                 6*Months, fixingDays,
                 calendar, ModifiedFollowing,
                 true, zcBondsDayCounter));
         boost::shared_ptr<RateHelper> zc1y(new DepositRateHelper(
                 Handle<Quote>(zc1yRate),
                 1*Years, fixingDays,
                 calendar, ModifiedFollowing,
                 true, zcBondsDayCounter));

        // setup bonds
        Real redemption = 100.0;

        const Size numberOfBonds = 5;

        Date issueDates[] = {
                Date (15, March, 2005),
                Date (15, June, 2005),
                Date (30, June, 2006),
                Date (15, November, 2002),
                Date (15, May, 1987)
        };

        Date maturities[] = {
                Date (31, August, 2010),
                Date (31, August, 2011),
                Date (31, August, 2013),
                Date (15, August, 2018),
                Date (15, May, 2038)
        };

        Real couponRates[] = {
                0.02375,
                0.04625,
                0.03125,
                0.04000,
                0.04500
        };

        Real marketQuotes[] = {
                100.390625,
                106.21875,
                100.59375,
                101.6875,
                102.140625
        };

        std::vector< boost::shared_ptr<SimpleQuote> > quote;
        for (Size i=0; i<numberOfBonds; i++) {
            boost::shared_ptr<SimpleQuote> cp(new SimpleQuote(marketQuotes[i]));
            quote.push_back(cp);
        }

        RelinkableHandle<Quote> quoteHandle[numberOfBonds];
        for (Size i=0; i<numberOfBonds; i++) {
            quoteHandle[i].linkTo(quote[i]);
        }

        // Definition of the rate helpers
        std::vector<boost::shared_ptr<BondHelper> > bondsHelpers;

        for (Size i=0; i<numberOfBonds; i++) {

            Schedule schedule(issueDates[i], maturities[i], Period(Semiannual), UnitedStates(UnitedStates::GovernmentBond),
                    Unadjusted, Unadjusted, DateGeneration::Backward, false);

            boost::shared_ptr<FixedRateBondHelper> bondHelper(new FixedRateBondHelper(
                    quoteHandle[i],
                    settlementDays,
                    100.0,
                    schedule,
                    std::vector<Rate>(1,couponRates[i]),
                    ActualActual(ActualActual::Bond),
                    Unadjusted,
                    redemption,
                    issueDates[i]));

            // the above could also be done by creating a
            // FixedRateBond instance and writing:
            //
            // boost::shared_ptr<BondHelper> bondHelper(
            //         new BondHelper(quoteHandle[i], bond));
            //
            // This would also work for bonds that still don't have a
            // specialized helper, such as floating-rate bonds.


            bondsHelpers.push_back(bondHelper);
        }

        /*********************
         **  CURVE BUILDING **
         *********************/

         // Any DayCounter would be fine.
         // ActualActual::ISDA ensures that 30 years is 30.0
         DayCounter termStructureDayCounter =
             ActualActual(ActualActual::ISDA);

         double tolerance = 1.0e-15;

         // A depo-bond curve
         std::vector<boost::shared_ptr<RateHelper> > bondInstruments;

         // Adding the ZC bonds to the curve for the short end
         bondInstruments.push_back(zc3m);
         bondInstruments.push_back(zc6m);
         bondInstruments.push_back(zc1y);

         // Adding the Fixed rate bonds to the curve for the long end
         for (Size i=0; i<numberOfBonds; i++) {
             bondInstruments.push_back(bondsHelpers[i]);
         }

         boost::shared_ptr<YieldTermStructure> bondDiscountingTermStructure(
                 new PiecewiseYieldCurve<Discount,LogLinear>(
                         settlementDate, bondInstruments,
                         termStructureDayCounter,
                         tolerance));

         // Building of the Libor forecasting curve
         // 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;
         // swaps
         Rate s2yQuote=0.0295;
         Rate s3yQuote=0.0323;
         Rate s5yQuote=0.0359;
         Rate s10yQuote=0.0412;
         Rate s15yQuote=0.0433;


         /********************
          ***    QUOTES    ***
          ********************/

         // SimpleQuote stores a value which can be manually changed;
         // other Quote subclasses could read the value from a database
         // or some kind of data feed.

         // deposits
         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));
         // swaps
         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 HELPERS ***
          *********************/

         // RateHelpers are built from the above quotes together with
         // other instrument dependant infos.  Quotes are passed in
         // relinkable handles which could be relinked to some other
         // data source later.

         // 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 swaps
         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));


         /*********************
          **  CURVE BUILDING **
          *********************/

         // Any DayCounter would be fine.
         // ActualActual::ISDA ensures that 30 years is 30.0

         // 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));

         // Term structures that will be used for pricing:
         // the one used for discounting cash flows
         RelinkableHandle<YieldTermStructure> discountingTermStructure;
         // the one used for forward rate forecasting
         RelinkableHandle<YieldTermStructure> forecastingTermStructure;

         /*********************
          * BONDS TO BE PRICED *
          **********************/

         // Common data
         Real faceAmount = 100;

         // Pricing engine
         boost::shared_ptr<PricingEngine> bondEngine(
                 new DiscountingBondEngine(discountingTermStructure));

         // Zero coupon bond
         ZeroCouponBond zeroCouponBond(
                 settlementDays,
                 UnitedStates(UnitedStates::GovernmentBond),
                 faceAmount,
                 Date(15,August,2013),
                 Following,
                 Real(116.92),
                 Date(15,August,2003));

         zeroCouponBond.setPricingEngine(bondEngine);

         // Fixed 4.5% US Treasury Note
         Schedule fixedBondSchedule(Date(15, May, 2007),
                 Date(15,May,2017), Period(Semiannual),
                 UnitedStates(UnitedStates::GovernmentBond),
                 Unadjusted, Unadjusted, DateGeneration::Backward, false);

         FixedRateBond fixedRateBond(
                 settlementDays,
                 faceAmount,
                 fixedBondSchedule,
                 std::vector<Rate>(1, 0.045),
                 ActualActual(ActualActual::Bond),
                 ModifiedFollowing,
                 100.0, Date(15, May, 2007));

         fixedRateBond.setPricingEngine(bondEngine);

         // Floating rate bond (3M USD Libor + 0.1%)
         // Should and will be priced on another curve later...

         RelinkableHandle<YieldTermStructure> liborTermStructure;
         const boost::shared_ptr<IborIndex> libor3m(
                 new USDLibor(Period(3,Months),liborTermStructure));
         libor3m->addFixing(Date(17, July, 2008),0.0278625);

         Schedule floatingBondSchedule(Date(21, October, 2005),
                 Date(21, October, 2010), Period(Quarterly),
                 UnitedStates(UnitedStates::NYSE),
                 Unadjusted, Unadjusted, DateGeneration::Backward, true);

         FloatingRateBond floatingRateBond(
                 settlementDays,
                 faceAmount,
                 floatingBondSchedule,
                 libor3m,
                 Actual360(),
                 ModifiedFollowing,
                 Natural(2),
                 // Gearings
                 std::vector<Real>(1, 1.0),
                 // Spreads
                 std::vector<Rate>(1, 0.001),
                 // Caps
                 std::vector<Rate>(),
                 // Floors
                 std::vector<Rate>(),
                 // Fixing in arrears
                 true,
                 Real(100.0),
                 Date(21, October, 2005));

         floatingRateBond.setPricingEngine(bondEngine);

         // Coupon pricers
         boost::shared_ptr<IborCouponPricer> pricer(new BlackIborCouponPricer);

         // optionLet volatilities
         Volatility volatility = 0.0;
         Handle<OptionletVolatilityStructure> vol;
         vol = Handle<OptionletVolatilityStructure>(
                 boost::shared_ptr<OptionletVolatilityStructure>(new
                         ConstantOptionletVolatility(
                                 settlementDays,
                                 calendar,
                                 ModifiedFollowing,
                                 volatility,
                                 Actual365Fixed())));

         pricer->setCapletVolatility(vol);
         setCouponPricer(floatingRateBond.cashflows(),pricer);

         // Yield curve bootstrapping
         forecastingTermStructure.linkTo(depoSwapTermStructure);
         discountingTermStructure.linkTo(bondDiscountingTermStructure);

         // We are using the depo & swap curve to estimate the future Libor rates
         liborTermStructure.linkTo(depoSwapTermStructure);

         /***************
          * BOND PRICING *
          ****************/

         std::cout << std::endl;

         // write column headings
         Size widths[] = { 18, 10, 10, 10 };

         std::cout << std::setw(widths[0]) <<  "                 "
         << std::setw(widths[1]) << "ZC"
         << std::setw(widths[2]) << "Fixed"
         << std::setw(widths[3]) << "Floating"
         << std::endl;

         std::string separator = " | ";
         Size width = widths[0]
                             + widths[1]
                                      + widths[2]
                                               + widths[3];
         std::string rule(width, '-'), dblrule(width, '=');
         std::string tab(8, ' ');

         std::cout << rule << std::endl;

         std::cout << std::fixed;
         std::cout << std::setprecision(2);

         std::cout << std::setw(widths[0]) << "Net present value"
         << std::setw(widths[1]) << zeroCouponBond.NPV()
         << std::setw(widths[2]) << fixedRateBond.NPV()
         << std::setw(widths[3]) << floatingRateBond.NPV()
         << std::endl;

         std::cout << std::setw(widths[0]) << "Clean price"
         << std::setw(widths[1]) << zeroCouponBond.cleanPrice()
         << std::setw(widths[2]) << fixedRateBond.cleanPrice()
         << std::setw(widths[3]) << floatingRateBond.cleanPrice()
         << std::endl;

         std::cout << std::setw(widths[0]) << "Dirty price"
         << std::setw(widths[1]) << zeroCouponBond.dirtyPrice()
         << std::setw(widths[2]) << fixedRateBond.dirtyPrice()
         << std::setw(widths[3]) << floatingRateBond.dirtyPrice()
         << std::endl;

         std::cout << std::setw(widths[0]) << "Accrued coupon"
         << std::setw(widths[1]) << zeroCouponBond.accruedAmount()
         << std::setw(widths[2]) << fixedRateBond.accruedAmount()
         << std::setw(widths[3]) << floatingRateBond.accruedAmount()
         << std::endl;

         std::cout << std::setw(widths[0]) << "Previous coupon"
         << std::setw(widths[1]) << "N/A" // zeroCouponBond
         << std::setw(widths[2]) << io::rate(fixedRateBond.previousCouponRate())
         << std::setw(widths[3]) << io::rate(floatingRateBond.previousCouponRate())
         << std::endl;

         std::cout << std::setw(widths[0]) << "Next coupon"
         << std::setw(widths[1]) << "N/A" // zeroCouponBond
         << std::setw(widths[2]) << io::rate(fixedRateBond.nextCouponRate())
         << std::setw(widths[3]) << io::rate(floatingRateBond.nextCouponRate())
         << std::endl;

         std::cout << std::setw(widths[0]) << "Yield"
         << std::setw(widths[1])
         << io::rate(zeroCouponBond.yield(Actual360(),Compounded,Annual))
         << std::setw(widths[2])
         << io::rate(fixedRateBond.yield(Actual360(),Compounded,Annual))
         << std::setw(widths[3])
         << io::rate(floatingRateBond.yield(Actual360(),Compounded,Annual))
         << std::endl;

         std::cout << std::endl;

         // Other computations
         std::cout << "Sample indirect computations (for the floating rate bond): " << std::endl;
         std::cout << rule << std::endl;

         std::cout << "Yield to Clean Price: "
         << floatingRateBond.cleanPrice(floatingRateBond.yield(Actual360(),Compounded,Annual),Actual360(),Compounded,Annual,settlementDate) << std::endl;

         std::cout << "Clean Price to Yield: "
         << io::rate(floatingRateBond.yield(floatingRateBond.cleanPrice(),Actual360(),Compounded,Annual,settlementDate)) << std::endl;

         /* "Yield to Price"
            "Price to Yield" */

         double seconds = timer.elapsed();
         Integer hours = int(seconds/3600);
         seconds -= hours * 3600;
         Integer minutes = int(seconds/60);
         seconds -= minutes * 60;
         std::cout << " \nRun completed in ";
         if (hours > 0)
             std::cout << hours << " h ";
         if (hours > 0 || minutes > 0)
             std::cout << minutes << " m ";
         std::cout << std::fixed << std::setprecision(0)
         << seconds << " s\n" << std::endl;

         return 0;

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