Piecewise Yield Curve Errors

Posted by Neo G.W. on
URL: http://quantlib.414.s1.nabble.com/Piecewise-Yield-Curve-Errors-tp16656.html

Hi,

I am trying to build a yield curve using the following inputs:

USD Libor 1m, 3m
EDF prices (12 of them, 3m apart, let's suppose convexity adjustment is zero)
Swap rates (5yr to 50yr)

To be able to interpolate with swap rates, I have to set my calendar to be the joint calendar of US and UK. Theses are the errors I am getting:

For pricing date 1/17/2014:
negative time (-0.00277778) given

For pricing date 2/13/2014:
interpolation range is [0.0777778, 7.10278]: extrapolation at 0.075 not allowed

To avoid out of range errors, I also have to enable extrapolation for the yield curve builder.

Can anybody help me with this? The stand alone code is as follows:

#include <ql/quantlib.hpp>

#include <stdio.h>

#include <iostream>

#include <fstream>

#include <sstream>

#include <ql/termstructures/yield/ratehelpers.hpp>

 

using namespace std;

using namespace QuantLib;

using namespace boost;

void testPiecewiseCurve(int yyyymmdd);

int main(int argc, char* argv[])

{

int yyyymmdd = 20140117;

try {

testPiecewiseCurve(yyyymmdd);

}

catch (std::exception& e) {

cout << "Couldn't build yield curve: " << e.what() << endl;

}

return 0;

}

struct Datum {

int n;

TimeUnit units;

Rate rate;

};

struct EDFDatum {

Date expiry;

Real price;

Rate convexityAdj;

};

Datum depositData[] = {

{ 1, Months, 0.157 },

{ 3, Months, 0.2366 }

};

EDFDatum edfData[] = {

{ Date(41715), 99.75, 0.00 },

{ Date(41806), 99.71, 0.00 },

{ Date(41897), 99.66, 0.00 },

{ Date(41988), 99.575, 0.00 },

{ Date(42079), 99.445, 0.00 },

{ Date(42170), 99.28, 0.00 },

{ Date(42261), 99.08, 0.00 },

{ Date(42352), 98.84, 0.00 },

{ Date(42443), 98.56, 0.00 },

{ Date(42534), 98.275, 0.00 },

{ Date(42632), 98.00, 0.00 },

{ Date(42723), 97.735, 0.00 }

};

Datum swapData[] = {

{ 5, Years, 1.73377 },

{ 6, Years, 2.074532 },

{ 7, Years, 2.36113 },

{ 8, Years, 2.592213 },

{ 9, Years, 2.781181 },

{ 10, Years, 2.937271 },

{ 15, Years, 3.418712 },

{ 30, Years, 3.742963 },

{ 35, Years, 3.742963 },

{ 40, Years, 3.742963 },

{ 45, Years, 3.742963 },

{ 50, Years, 3.742963 }

};

 

 

void testPiecewiseCurve(int yyyymmdd){

Calendar calendar = JointCalendar(UnitedStates(UnitedStates::Settlement), UnitedKingdom(UnitedKingdom::Exchange), JoinHolidays);

 

int dd = yyyymmdd%100;

int mm = (yyyymmdd/100)%100;

int yyyy = yyyymmdd/10000;

Date pricingDate = calendar.adjust(Date(dd , Month(mm), yyyy));

Date zeroDate = calendar.advance (pricingDate , 2 , Days );

vector<boost::shared_ptr<SimpleQuote> > rates, prices;

vector <boost::shared_ptr < RateHelper >> instruments;

Size libors = 2;

Size edfs = 12 ;

Size swaps = 12;

instruments = std::vector<boost::shared_ptr<RateHelper> >(libors + edfs + swaps);

rates = vector<boost::shared_ptr<SimpleQuote> >(libors + swaps);

prices = vector<boost::shared_ptr<SimpleQuote> >(edfs);

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

rates[i] = boost::shared_ptr<SimpleQuote>(new SimpleQuote(depositData[i].rate/100));

}

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

prices[i] = boost::shared_ptr<SimpleQuote>(new SimpleQuote(edfData[i].price));

}

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

rates[i+libors] = boost::shared_ptr<SimpleQuote>(new SimpleQuote(swapData[i].rate/100));

}

Settings::instance().evaluationDate() = pricingDate;

//For USD Libor Swap, the fixed leg frequency is semiannual

Frequency fixedLegFrequency = Semiannual;

//For USD Libor Swap, the fixed leg convention is modified following

//Modified Following: Choose the first business day after the given holiday unless it belongs to a different month,

//in which case choose the first business day before the holiday.

BusinessDayConvention fixedLegConvention = ModifiedFollowing;

//For USD Libor Swap, the fixed leg day counter is 30/360

DayCounter fixedLegDayCounter = Thirty360();

boost::shared_ptr<IborIndex> libor1m(new USDLibor(1*Months));

boost::shared_ptr<IborIndex> libor3m(new USDLibor(3*Months));

boost::shared_ptr<IborIndex> libor6m(new USDLibor(6*Months));

Handle<Quote> r0(rates[0]);

instruments[0] = boost::shared_ptr<RateHelper>(new DepositRateHelper(r0, 1*Months, libor1m->fixingDays(), calendar,

libor1m->businessDayConvention(),

libor1m->endOfMonth(),

libor1m->dayCounter()));

Handle<Quote> r1(rates[1]);

instruments[1] = boost::shared_ptr<RateHelper>(new DepositRateHelper(r1, 3*Months, libor3m->fixingDays(), calendar,

libor3m->businessDayConvention(),

libor3m->endOfMonth(),

libor3m->dayCounter()));

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

Handle<Quote> p(prices[i]);

Date immDate = IMM::nextDate(edfData[i].expiry);

//EDF prices should be convexity adjusted

boost::shared_ptr<Quote> convexity(new SimpleQuote(edfData[i].convexityAdj/10000.0));

instruments[i+libors] = boost::shared_ptr<RateHelper>(new FuturesRateHelper(p, immDate, 3, calendar,

libor3m->businessDayConvention(),

libor3m->endOfMonth(),

libor3m->dayCounter(),

Handle<Quote>(convexity)));

}

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

Handle<Quote> r(rates[i+libors]);

instruments[i+libors+edfs] = boost::shared_ptr<RateHelper>(new SwapRateHelper(r, swapData[i].n*swapData[i].units, calendar,

fixedLegFrequency, fixedLegConvention, fixedLegDayCounter, libor3m));

}

 

 

Cubic myCubic(CubicInterpolation::Spline, true,

CubicInterpolation::SecondDerivative, 0.0,

CubicInterpolation::SecondDerivative, 0.0);

DayCounter dc= Actual360 ();

cout << "zero date is " << zeroDate << endl;

boost::shared_ptr <QuantLib::YieldTermStructure> yieldCurve = boost::shared_ptr < YieldTermStructure >( new PiecewiseYieldCurve < ZeroYield , Cubic, IterativeBootstrap >( zeroDate , instruments , dc, myCubic));

yieldCurve -> enableExtrapolation();

Handle < YieldTermStructure > ycHandle ( yieldCurve );

boost::shared_ptr < IborIndex > libor3m_new ( new USDLibor ( Period (3, Months ), ycHandle ));

cout << "Checking estimated rates against input..." << endl;

Real tolerance = 1.0e-7;

// Check Results

// Check deposits

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

//USDLibor index(depositData[i].n*depositData[i].units, ycHandle);

Libor index("USDLibor", depositData[i].n*depositData[i].units, 2,

USDCurrency(),

calendar,

Actual360(), ycHandle);

Rate inputRate = depositData[i].rate/100,

estimatedRate = index.fixing(pricingDate);

if (std::fabs(estimatedRate - inputRate) > tolerance)

cout << depositData[i].n*depositData[i].units

<< " Deposit:"

<< setprecision(8)

<< "\n\t estimated rate: " << estimatedRate

<< "\n\t input rate: " << inputRate

<< endl;

}

// Check swap rate

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

Period tenor = swapData[i].n*swapData[i].units;

// construct a vanilla swap

VanillaSwap swap = MakeVanillaSwap (tenor, libor3m_new)

. withEffectiveDate (zeroDate)

. withFixedLegConvention (ModifiedFollowing)

. withFixedLegTenor (6*Months);

Rate inputRate = swapData[i].rate/100,

estimatedRate = swap.fairRate();

if (std::fabs(estimatedRate - inputRate) > tolerance)

cout << tenor <<" Swap :" << setprecision(8)

<< "\n\t estimated rate: "<< estimatedRate

<< "\n\t input rate: "<< inputRate

<< endl ;

}

cout << "Zero-yield Rates..."<< endl;

for (int i=0; i<=120; i++){

Rate zeroRate = yieldCurve -> zeroRate ( zeroDate + 3*i* Months ,dc , Continuous );

DiscountFactor discountFactor = yieldCurve -> discount( zeroDate + 3*i* Months );

cout << " Zero " << 3*i << "M: " << zeroDate +3*i* Months<< " " << zeroRate << " discount factor " << discountFactor << endl ;

}

 

cout << "\n3m Forward Rates..."<< endl;

for (int i=0; i<=120; i++){

Date d1= zeroDate +3*i* Months, d2=d1 +3* Months ;

Rate forwardRate = yieldCurve -> forwardRate (d1 ,d2 ,dc , Continuous );

cout << 3*i << " x " << 3*i + 3 << " Fwd : " << forwardRate<< endl ;

}

 

}



------------------------------------------------------------------------------

_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users