Hi,
I have been playing with QuantLib for a week and I need to admit that it rocks! This is really a heaven for who is involved in pricing, benchmarking, experimenting with cutting-hedge quantitative technology. I would like to ask a question related floating rate bonds. 1) Is there a plain-english document which explains how to setup FloatingRateBond class in order to calculate standard indicators, such as Duration and Convexity, given the bond price (i.e. Starting from the current market value I would like to calculate the Duration/Convexity implied in the price) 2) Is there anyone who can explain a bit how to setup discounting and forecasting curves, which are required to price a floating rate bond? Thanks in advance, Regards, Antonio |
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<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<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<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)); // 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; } |
Hello,
[note: your mail client seems to have stripped some template arguments from the pasted code, so I haven't been able to try and run it. Next time, it would help if you might attach the file instead of pasting the code.] However: the problem is that, in the duration() method, the yield that is passed is only used for discounting and not for forecasting the Libor coupons. This way, the bond is not really used as a floating-rate bond, but rather as a fixed-rate bond which happens to pay the same rates as the floating-rate bond (hence the duration close to the time to maturity). Unfortunately, there's no simple way to change the method so that it can detect the kind of coupons contained in the bond (especially since you could define your own coupon classes). Instead of using the duration method, I suggest you calculate the duration manually. You'll have to link both the forwarding term structure and the discounting term structure to a flat curve with rate equal to the yield, which gives you the price P as function of the yield y; once you have that, you can calculate the modified duration as 1/P dP/dy. Luigi On Thu, Dec 5, 2013 at 4:32 PM, asavoldi <[hidden email]> wrote: > 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-users -- <https://implementingquantlib.blogspot.com> <https://twitter.com/lballabio> ------------------------------------------------------------------------------ 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-users |
Dear Luigi,
thank you so much for your kind answer. Regarding your suggestion I will try the illustrated method for calculating Duration of a floating rate bond. I would like to ask a further question about this topic. Let us suppose to have the market (fair) price of an FRN with the related date (issue date, frequency, next coupon date, etc.). Is it possible to infer the Duration from the market price without having to deal with discounting and forward curves ? (basically with the same approach we might use to calculate Bond indicators (e.g. yielld to maturity, duration, convexity...) of a zero coupon and fixed rate bond). Thanks in advance, Regards, Antonio |
You mean by using some closed formula involving a constant yield? How
would you do it for a fixed-rate bond? Luigi On Tue, Dec 10, 2013 at 8:48 PM, asavoldi <[hidden email]> wrote: > Dear Luigi, > > thank you so much for your kind answer. Regarding your suggestion I will try > the illustrated method for calculating Duration of a floating rate bond. I > would like to ask a further question about this topic. Let us suppose to > have the market (fair) price of an FRN with the related date (issue date, > frequency, next coupon date, etc.). Is it possible to infer the Duration > from the market price without having to deal with discounting and forward > curves ? (basically with the same approach we might use to calculate Bond > indicators (e.g. yielld to maturity, duration, convexity...) of a zero > coupon and fixed rate bond). > > Thanks in advance, > Regards, > Antonio > > > > -- > View this message in context: http://quantlib.10058.n7.nabble.com/Duration-and-Convexity-of-a-Floating-Rate-Bond-tp14689p14714.html > Sent from the quantlib-users mailing list archive at Nabble.com. > > ------------------------------------------------------------------------------ > Rapidly troubleshoot problems before they affect your business. Most IT > organizations don't have a clear picture of how application performance > affects their revenue. With AppDynamics, you get 100% visibility into your > Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro! > http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk > _______________________________________________ > QuantLib-users mailing list > [hidden email] > https://lists.sourceforge.net/lists/listinfo/quantlib-users -- <https://implementingquantlib.blogspot.com> <https://twitter.com/lballabio> ------------------------------------------------------------------------------ Rapidly troubleshoot problems before they affect your business. Most IT organizations don't have a clear picture of how application performance affects their revenue. With AppDynamics, you get 100% visibility into your Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro! http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Yes correct. You might use ZCB_value(t) = FaceValue / (1 + ytm)^n, where ytm is the yield to maturity, n are the periods to redemption, and ZCB_value(t) is the current market value. For other sensitivity indicators (e.g. Duration) we might use the standard formula (D = (-1/P)*dP/dytm). Another way to calculate the duration of a ZCB, as well as for an FRN (Floating-Rate-Note), is by calculating the time to maturity (i.e. D = (t_maturity - todaysDate)/365).
Regards. |
Hello,
you would have to write a corresponding formula for the value of the floating-rate bond, expressing the future LIBOR fixings in terms of the ytm. Once you have that, I guess you can obtain the duration by derivation. Luigi On Tue, Dec 17, 2013 at 4:50 PM, asavoldi <[hidden email]> wrote: > Yes correct. You might use ZCB_value(t) = FaceValue / (1 + ytm)^n, where ytm > is the yield to maturity, n are the periods to redemption, and ZCB_value(t) > is the current market value. For other sensitivity indicators (e.g. > Duration) we might use the standard formula (D = (-1/P)*dP/dytm). Another > way to calculate the duration of a ZCB, as well as for an FRN > (Floating-Rate-Note), is by calculating the time to maturity (i.e. D = > (t_maturity - todaysDate)/365). > > Regards. > > > > -- > View this message in context: http://quantlib.10058.n7.nabble.com/Duration-and-Convexity-of-a-Floating-Rate-Bond-tp14689p14754.html > Sent from the quantlib-users mailing list archive at Nabble.com. > > ------------------------------------------------------------------------------ > Rapidly troubleshoot problems before they affect your business. Most IT > organizations don't have a clear picture of how application performance > affects their revenue. With AppDynamics, you get 100% visibility into your > Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro! > http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk > _______________________________________________ > QuantLib-users mailing list > [hidden email] > https://lists.sourceforge.net/lists/listinfo/quantlib-users -- <https://implementingquantlib.blogspot.com> <https://twitter.com/lballabio> ------------------------------------------------------------------------------ Rapidly troubleshoot problems before they affect your business. Most IT organizations don't have a clear picture of how application performance affects their revenue. With AppDynamics, you get 100% visibility into your Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro! http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Free forum by Nabble | Edit this page |