http://quantlib.414.s1.nabble.com/Duration-and-Convexity-of-a-Floating-Rate-Bond-tp14689p14712.html
it. Next time, it would help if you might attach the file instead of
Libor coupons. This way, the bond is not really used as a
to the time to maturity).
you could define your own coupon classes).
duration manually. You'll have to link both the forwarding term
as 1/P dP/dy.
> So far, I've been able to simulate a floating rate bond with the following
> code. Surprisingly, the duration, which is expected to be the residual time
> until the following coupon (should be less than 0.25 being the period
> quarterly), is evaluated as the residual time to expiration (in this case
> the calculated duration is about 2 that is the time to expiration)
>
> Is anyone able to provide an explanation about this result?
>
>
> ---------------------------------
> Today: Monday, September 15th, 2008
> Settlement date: Thursday, September 18th, 2008
> Floating Rate Bond
> Net present value = 102.359
> Clean price = 101.797
> Dirty price = 102.359
> Accrued coupon = 0.562113
> Previous coupon = 2.886250 %
> Next coupon = 3.429841 %
> Yield = 2.200956 %
>
> Sample indirect computations (for the floating rate bond):
> Yield to Clean Price = 101.797
> Clean Price to Yield = 2.200956 %
> Macaulay Duration = 2.01408
> Modified Duration = 2.00306
> Convexity = 4.60674
> Price Duration = 103.836
> Price Convexity = 103.86
>
>
>
>
>
> #include <ql/quantlib.hpp>
> #include <iostream>
> #include <iomanip>
> using namespace QuantLib;
> #if defined(QL_ENABLE_SESSIONS)
> namespace QuantLib {
> Integer sessionId() { return 0; }
> }
> #endif
>
>
> /*
> Definitions:
>
> gearings: optional multipliers of the LIBOR fixing (some bonds might pay,
> for instance, 0.8 times the LIBOR)
>
> spreads: are the added spreads. In your case, the gearing is 1 and the
> spread is 0.0140 (that is, 140 bps; rates
> and spread must be expressed in decimal form).
>
> curve: the curve you want to use for discounting. Using the swap curve plus
> a spread is a possibility. However, note
> that the CDS spread might not be an exact proxy for the spread to be
> applied. At the very least, the CDS spread
> is a quarterly rate simply compounded, whereas (depending on what
> classes are exported) you might need a continuously
> compounded rate in order to spread the swap curve. You'll have to
> perform the conversion first.
>
> index: an instance of an index class such as Euribor3M, whose constructor in
> turn would take the swap curve.
> */
>
> void floatingRateBondIndicators() {
>
> //*********************
> //*** 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 << "---------------------------------" << std::endl;
> 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 zc3mRate(new SimpleQuote(zc3mQuote));
> boost::shared_ptr zc6mRate(new SimpleQuote(zc6mQuote));
> boost::shared_ptr zc1yRate(new SimpleQuote(zc1yQuote));
> DayCounter zcBondsDayCounter = Actual365Fixed();
> boost::shared_ptr<RateHelper> zc3m(new DepositRateHelper(Handle(zc3mRate),
> 3*Months, fixingDays, calendar, ModifiedFollowing, true,
> zcBondsDayCounter));
> boost::shared_ptr<RateHelper> zc6m(new DepositRateHelper(Handle(zc6mRate),
> 6*Months, fixingDays, calendar, ModifiedFollowing, true,
> zcBondsDayCounter));
> boost::shared_ptr<RateHelper> zc1y(new DepositRateHelper(Handle(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 quoteHandle[numberOfBonds];
> for (Size i=0; i<numberOfBonds; i++) {
> quoteHandle[i].linkTo(quote[i]);
> }
> // Definition of the rate helpers
> std::vector<boost::shared_ptr<FixedRateBondHelper> > 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]));
> 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]);
> }
>
>
> //--------------------------------------------------------------------------------------------------------------------------------------------------------
> //bondDiscountingTermStructure => Discounting Curve (this is one of the
> curves that must be present in order to evaluate properly a floating Rate
> Bond)
>
> //--------------------------------------------------------------------------------------------------------------------------------------------------------
> 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 d1wRate(new SimpleQuote(d1wQuote));
> boost::shared_ptr d1mRate(new SimpleQuote(d1mQuote));
> boost::shared_ptr d3mRate(new SimpleQuote(d3mQuote));
> boost::shared_ptr d6mRate(new SimpleQuote(d6mQuote));
> boost::shared_ptr d9mRate(new SimpleQuote(d9mQuote));
> boost::shared_ptr d1yRate(new SimpleQuote(d1yQuote));
> // swaps
> boost::shared_ptr s2yRate(new SimpleQuote(s2yQuote));
> boost::shared_ptr s3yRate(new SimpleQuote(s3yQuote));
> boost::shared_ptr s5yRate(new SimpleQuote(s5yQuote));
> boost::shared_ptr s10yRate(new SimpleQuote(s10yQuote));
> boost::shared_ptr 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(d1wRate),
> 1*Weeks, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter));
> boost::shared_ptr<RateHelper> d1m(new DepositRateHelper(Handle(d1mRate),
> 1*Months, fixingDays, calendar, ModifiedFollowing, true,
> depositDayCounter));
> boost::shared_ptr<RateHelper> d3m(new DepositRateHelper(Handle(d3mRate),
> 3*Months, fixingDays, calendar, ModifiedFollowing, true,
> depositDayCounter));
> boost::shared_ptr<RateHelper> d6m(new DepositRateHelper(Handle(d6mRate),
> 6*Months, fixingDays, calendar, ModifiedFollowing, true,
> depositDayCounter));
> boost::shared_ptr<RateHelper> d9m(new DepositRateHelper(Handle(d9mRate),
> 9*Months, fixingDays, calendar, ModifiedFollowing, true,
> depositDayCounter));
> boost::shared_ptr<RateHelper> d1y(new DepositRateHelper(Handle(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(s2yRate),
> 2*Years, calendar, swFixedLegFrequency, swFixedLegConvention,
> swFixedLegDayCounter, swFloatingLegIndex, Handle(),forwardStart));
> boost::shared_ptr<RateHelper> s3y(new SwapRateHelper(Handle(s3yRate),
> 3*Years, calendar, swFixedLegFrequency, swFixedLegConvention,
> swFixedLegDayCounter, swFloatingLegIndex, Handle(),forwardStart));
> boost::shared_ptr<RateHelper> s5y(new SwapRateHelper(Handle(s5yRate),
> 5*Years, calendar, swFixedLegFrequency, swFixedLegConvention,
> swFixedLegDayCounter, swFloatingLegIndex, Handle(),forwardStart));
> boost::shared_ptr<RateHelper> s10y(new SwapRateHelper(Handle(s10yRate),
> 10*Years, calendar, swFixedLegFrequency, swFixedLegConvention,
> swFixedLegDayCounter, swFloatingLegIndex, Handle(),forwardStart));
> boost::shared_ptr<RateHelper> s15y(new SwapRateHelper(Handle(s15yRate),
> 15*Years, calendar, swFixedLegFrequency, swFixedLegConvention,
> swFixedLegDayCounter, swFloatingLegIndex, Handle(),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));
>
> // 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); //278.625 bps; this is
> spot value of LIBOR rate
>
>
> Schedule floatingBondSchedule(
> Date(21, October, 2005), //issue day
> Date(21, October, 2010), //maturity day
> Period(Quarterly), //frequency
> UnitedStates(UnitedStates::NYSE), //calendar
> Unadjusted, //day convention
> Unadjusted, //day termination
> DateGeneration::Backward, //date generation
> true //end of the month
> );
>
> FloatingRateBond floatingRateBond(
> settlementDays, //days for bond settlement [Natural settlementDays]
> faceAmount, //face amount (e.g. 100) [Real faceAmount]
> floatingBondSchedule, //schedule object [const Schedule& schedule]
> libor3m, //IborIndex -> linked index used for coupon discounting
> [const boost::shared_ptr<IborIndex>& index]
> Actual360(), //paymentDayCounter [const DayCounter&
> paymentDayCounter]
> ModifiedFollowing, //paymentConvention [BusinessDayConvention
> paymentConvention]
> Natural(2), //[Natural fixingDays]
> // Gearings
> std::vector<Real>(1, 1.0), //[const std::vector<Real>& gearings] ->
> multiplier
> // Spreads
> std::vector<Rate>(1, 0.001), //[const std::vector<Spread>& spreads] ->
> rate added to index curve
> // Caps
> std::vector<Rate>(), //[const std::vector<Rate>& caps] -> upper limit
> which limit the coupon rate
> // Floors
> std::vector<Rate>(), //[const std::vector<Rate>& floors] -> minimum
> rate guaranteed as coupon rate
> // Fixing in arrears
> true, //[bool inArrears]
> Real(100.0), //[Real redemption]
> Date(21, October, 2005)); //[const Date& issueDate]
>
>
> //-----------------------
> //Setting price enginge
> //-----------------------
> 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 << "Floating Rate Bond" << std::endl;
>
> //Net present value
> Real npv = floatingRateBond.NPV();
> std::cout << "Net present value = " << npv << std::endl;
>
> //Clean price
> Real cleanPrice = floatingRateBond.cleanPrice();
> std::cout << "Clean price = " << cleanPrice << std::endl;
>
> //Dirty price
> Real dirtyPrice = floatingRateBond.dirtyPrice();
> std::cout << "Dirty price = " << dirtyPrice << std::endl;
>
> //Accrued amount
> Real accruedAmount = floatingRateBond.accruedAmount();
> std::cout << "Accrued coupon = " << accruedAmount << std::endl;
>
> //Previous coupon
> Real previousCoupon = floatingRateBond.previousCouponRate();
> std::cout << "Previous coupon = " << io::rate(previousCoupon) << std::endl;
>
> //Next coupon
> Real nextCoupon = floatingRateBond.nextCouponRate();
> std::cout << "Next coupon = " << io::rate(nextCoupon) << std::endl;
>
> //yield to maturity
> Real yield = floatingRateBond.yield(Actual360(),Compounded,Annual);
> std::cout << "Yield = " << io::rate(yield) << std::endl;
> std::cout << std::endl;
>
> // Other computations
> std::cout << "Sample indirect computations (for the floating rate bond): "
> << std::endl;
>
> //clean price from yield to maturity
> Real cleanPriceFromYield =
> floatingRateBond.cleanPrice(floatingRateBond.yield(Actual360(),Compounded,Annual),Actual360(),Compounded,Annual,settlementDate);
> std::cout << "Yield to Clean Price = " << cleanPriceFromYield << std::endl;
>
> //yield to maturity from clean price
> Real yieldFromCleanPrice =
> floatingRateBond.yield(floatingRateBond.cleanPrice(),Actual360(),Compounded,Annual,settlementDate);
> std::cout << "Clean Price to Yield = " << io::rate(yieldFromCleanPrice) <<
> std::endl;
>
> DayCounter dayCounter = ActualActual(ActualActual::Bond);
> Compounding interestCompounding = Compounding::Compounded;
> Frequency frequency = Frequency::Quarterly;
>
> //Macauly Duration
> Time macDuration =
> BondFunctions::duration(floatingRateBond,yield,dayCounter,interestCompounding,frequency,Duration::Macaulay,todaysDate);
> std::cout << "Macaulay Duration = " << macDuration << std::endl;
>
> //Modified duration
> Time modDuration =
> BondFunctions::duration(floatingRateBond,yield,dayCounter,interestCompounding,frequency,Duration::Modified,todaysDate);
> std::cout << "Modified Duration = " << modDuration << std::endl;
>
> //Convexity
> Real convexity =
> BondFunctions::convexity(floatingRateBond,yield,dayCounter,interestCompounding,frequency,todaysDate);
> std::cout << "Convexity = " << convexity << std::endl;
>
> //Estimate new bond price for an increase in interest rate of 1% using
> modified duration
> Real priceDuration = cleanPrice + cleanPrice * (modDuration * .01);
> std::cout << "Price Duration = " << priceDuration << std::endl;
>
> //Estimate new bond price for an increase in interest rate of 1% using
> duration and convexity
> Real priceConvexity = cleanPrice + cleanPrice * (modDuration * .01 + (.5 *
> convexity * std::pow(.01, 2)));
> std::cout << "Price Convexity = " << priceConvexity << std::endl;
>
>
> }
>
>
>
> --
> View this message in context:
http://quantlib.10058.n7.nabble.com/Duration-and-Convexity-of-a-Floating-Rate-Bond-tp14689p14691.html> Sent from the quantlib-users mailing list archive at Nabble.com.
>
> ------------------------------------------------------------------------------
> Sponsored by Intel(R) XDK
> Develop, test and display web and hybrid apps with a single code base.
> Download it for free now!
>
http://pubads.g.doubleclick.net/gampad/clk?id=111408631&iu=/4140/ostg.clktrk> _______________________________________________
> QuantLib-users mailing list
>
[hidden email]
>
https://lists.sourceforge.net/lists/listinfo/quantlib-usersDevelop, test and display web and hybrid apps with a single code base.