Login  Register

CPIBond to price US Treasury TIPS

Posted by ian_dfw on Oct 30, 2015; 8:07pm
URL: http://quantlib.414.s1.nabble.com/CPIBond-to-price-US-Treasury-TIPS-tp17011.html

Hi,
I am new user of Quantlib and now trying to price US Treasury TIPS with the CPIBond class, so I basically try to follow the inflationcpibond sampole C++ code with some modification of dates of settlement and bond start/end dates, also the zcii data. But after such changes, the clean price is only $8.9 when notional is $100.  What am I doing wrong?

#include "stdafx.h"

#include <ql/indexes/inflation/ukrpi.hpp>
#include <ql/indexes/inflation/uscpi.hpp>
#include <ql/time/calendars/unitedkingdom.hpp>
#include <ql/time/calendars/unitedstates.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <ql/time/daycounters/actual365fixed.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/indexes/ibor/gbplibor.hpp>
#include <ql/termstructures/inflation/inflationhelpers.hpp>
#include <ql/termstructures/inflation/piecewisezeroinflationcurve.hpp>
#include <ql/cashflows/indexedcashflow.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
#include <ql/instruments/zerocouponinflationswap.hpp>
#include <ql/pricingengines/bond/discountingbondengine.hpp>
#include <ql/cashflows/cpicoupon.hpp>
#include <ql/cashflows/cpicouponpricer.hpp>
#include <ql/instruments/cpiswap.hpp>
#include <ql/instruments/bonds/cpibond.hpp>

using namespace QuantLib;
using namespace std;

#include <iostream>


namespace
{

    struct Datum
    {
        Date date;
        Rate rate;
    };

    typedef BootstrapHelper<ZeroInflationTermStructure> Helper;

    std::vector<boost::shared_ptr<Helper> > makeHelpers(Datum iiData[],
                                                        Size N,
                                                        const boost::shared_ptr<ZeroInflationIndex>& ii,
                                                        const Period& observationLag,
                                                        const Calendar& calendar,
                                                        const BusinessDayConvention& bdc,
                                                        const DayCounter& dc)
    {

            std::vector<boost::shared_ptr<Helper>> instruments;

            for (Size i = 0; i < N; i++)
            {
                Date maturity = iiData[i].date;

                Handle<Quote> quote(boost::shared_ptr<Quote>(new SimpleQuote(iiData[i].rate / 100.0)));

                boost::shared_ptr<Helper> h(
                    new ZeroCouponInflationSwapHelper(quote,
                                                      observationLag,
                                                      maturity, calendar,
                                                      bdc,
                                                      dc,
                                                      ii)
                );
               
                instruments.push_back(h);
            }

            return instruments;
    }


    struct CommonVars
    {

        Calendar              calendar;
        BusinessDayConvention convention;
        Date                  evaluationDate;
        Period                observationLag;
        DayCounter            dayCounter;

        boost::shared_ptr<USCPI> ii;

        RelinkableHandle<YieldTermStructure> yTS;
        RelinkableHandle<ZeroInflationTermStructure> cpiTS;


        // setup
        CommonVars()
        {
            // usual setup
            calendar = UnitedStates();
            convention = ModifiedFollowing;

            Date today(25, Oct, 2015);

            evaluationDate = calendar.adjust(today);
            Settings::instance().evaluationDate() = evaluationDate;
            dayCounter = ActualActual();

            Date from(20, Jun, 2013);
            Date to(20, Oct, 2015);

            Schedule rpiSchedule =
                MakeSchedule().from(from).to(to)
                .withTenor(1 * Months)
                .withCalendar(UnitedStates())
                .withConvention(ModifiedFollowing);

            bool interp = false;
            ii = boost::shared_ptr<USCPI>(new USCPI(interp, cpiTS));

            Real fixData[] =
            {
                206.1, 207.3, 208.0, 208.9, 209.7, 210.9,
                209.8, 211.4, 212.1, 214.0, 215.1, 216.8,
                216.5, 217.2, 218.4, 217.7, 216,
                212.9, 210.1, 211.4, 211.3, 211.5,
                212.8, 213.4, 213.4, 213.4, 214.4

                /*
                237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945,
                237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945,
                237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945, 237.945
                */
            };

            for (Size i = 0; i < sizeof(fixData) / sizeof(Real); ++i)
            {
                ii->addFixing(rpiSchedule[i], fixData[i]);
            }

            yTS.linkTo(boost::shared_ptr<YieldTermStructure>(new FlatForward(evaluationDate, 0.0075, dayCounter)));

            // now build the zero inflation curve
            observationLag = Period(2, Months);

            Datum zciisData[] =
            {
                { Date(25, November, 2010), 0.010 },
                { Date(25, November, 2011), 0.020 },
                { Date(26, November, 2012), 0.030 },
                { Date(25, November, 2013), 0.040 },
                { Date(25, November, 2014), 0.050 },

                { Date(25, November, 2015), 0.500 },
                { Date(25, November, 2016), 0.800 },
                { Date(25, November, 2017), 1.100 },
                { Date(25, November, 2018), 1.500 },
                { Date(25, November, 2019), 1.800 },
                { Date(25, November, 2021), 2.033 },
                { Date(25, November, 2024), 2.133 },
                { Date(26, November, 2029), 2.300 },
                { Date(27, November, 2034), 2.467 },
                { Date(25, November, 2039), 2.633 },
                { Date(25, November, 2049), 2.967 },
                { Date(25, November, 2059), 3.000 },
            };

            std::vector<boost::shared_ptr<Helper> > helpers =
                makeHelpers(zciisData,
                            sizeof(zciisData) / sizeof(Datum),
                            ii,
                            observationLag,
                            calendar,
                            convention,
                            dayCounter);

            Rate baseZeroRate = zciisData[0].rate / 100.0;

            cpiTS.linkTo(
                boost::shared_ptr<ZeroInflationTermStructure>(
                    new PiecewiseZeroInflationCurve<Linear>(evaluationDate,
                                                            calendar,
                                                            dayCounter,
                                                            observationLag,
                                                            ii->frequency(),
                                                            ii->interpolated(),
                                                            baseZeroRate,
                                                            Handle<YieldTermStructure>(yTS),
                                                            helpers)
                )
            );
        }

        // teardown
        ~CommonVars()
        {
            // break circular references and allow curves to be destroyed
            cpiTS.linkTo(boost::shared_ptr<ZeroInflationTermStructure>());
        }
    };

}


void testInflationCleanPrice()
{
    CommonVars common;

    Real notional = 100.0;


    std::vector<Rate> fixedRates(1, 0.02375);


    DayCounter fixedDayCount = Actual365Fixed();
    BusinessDayConvention fixedPaymentConvention = ModifiedFollowing;
    Calendar fixedPaymentCalendar = UnitedStates();
    boost::shared_ptr<ZeroInflationIndex> fixedIndex = common.ii;
    Period contractObservationLag = Period(1, Months);
    CPI::InterpolationType observationInterpolation = CPI::Flat;
    Natural settlementDays = 1;
    bool growthOnly = true;

    Real baseCPI = 206.1;

    // set the schedules
    Date startDate(15, Jan, 2007);
    Date endDate(15, Jan, 2017);

    Schedule fixedSchedule =
        MakeSchedule().from(startDate).to(endDate)
        .withTenor(Period(6, Months))
        .withCalendar(UnitedStates())
        .withConvention(ModifiedFollowing)
        .backwards();

    CPIBond bond(settlementDays,
                 notional,
                 growthOnly,
                 baseCPI,
                 contractObservationLag,
                 fixedIndex,
                 observationInterpolation,
                 fixedSchedule,
                 fixedRates,
                 fixedDayCount,
                 fixedPaymentConvention);

    boost::shared_ptr<DiscountingBondEngine> engine(new DiscountingBondEngine(common.yTS));
    bond.setPricingEngine(engine);


    Real calculated = bond.cleanPrice();
    Real tolerance = 1.0e-8;

    cout << "NPV: " << bond.NPV() << endl;
    cout << "Clean price: " << calculated << endl;
    cout << "Dirty price: " << bond.dirtyPrice() << endl;


}