In QuantLib, what is the difference between redemption
and face value for a fixed rate bond? I'm asking because I thought I knew the difference, and have been getting screwy answers. I'm working with a bond with the following parameters: Maturity: 5/3/2041 Coupon: 5.375% Coupon Frequency: Quarterly Coupon Type: Fixed Redemption: $50 Credit Spread: 500 bps If I use my code to price a bond with a $100 redemption value, I get a present value of around $65. If I then change it to a redemption of $50, I get a value of $62 (when I expected to get a present value of $65/2 = $32.5). I don't understand how a bond could be worth more now than at redemption. I tried my code with redemptions ranging from $10 - $100, and received results around $58 - $65. I don't know if this is a problem in my code, or some misunderstanding I have between face value and redemption. The code I used is below. Thanks in advance. // TestQuantLib.cpp : Defines the entry point for the console // application. // #include "stdafx.h" #include <ql/quantlib.hpp> #include <boost/timer.hpp> using namespace std; using namespace QuantLib; #define LENGTH(a) (sizeof(a)/sizeof(a[0])) int _tmain(int argc, _TCHAR* argv[]) { try { // parameters // schedule frequency int schedulefrequency = 52; // coupon frequency int couponFrequency = 4; // coupon double coupon = 0.05375; // redemption value double redemption = 50; // face value double faceValue = 100; // days between today and issue int issueDays = 0; // days between today and maturity int maturityDays = 12224; // number of points in interest rate curve int yLen = 10; // days between today and interest rate curve date int yieldDays[] = {92, 182, 366, 731, 1096, 1827, 3653, 7305, 10958, 12224}; // interest yield curve points double yieldCurve[] = {0.034278, 0.037308, 0.036284, 0.035433, 0.034892, 0.038433, 0.042665, 0.046507, 0.046163, 0.046045}; // number of points in credit spread curve int sLen = 1; // credit spread curve points double spreadCurve[] = {0.05}; // set up interest rate points std::vector<Real> riskFree; std::vector<int> riskFreeDays; for(int i = 0; i < yLen; i++){ riskFree.push_back(yieldCurve[i]); riskFreeDays.push_back(yieldDays[i]); } // set up credit spread points std::vector<Real> convSpread; for(int i = 0; i < sLen; i++) convSpread.push_back(spreadCurve[i]); // set calendar and dates Calendar calendar_ = UnitedStates(UnitedStates::Market::NYSE); Date today = calendar_.adjust(Date::todaysDate()); Settings::instance().evaluationDate() = today; DayCounter dayCount = Actual365Fixed(); Date issueDate = today + issueDays; Date maturityDate = today + maturityDays; Date earlyDate; if(issueDate > today) earlyDate = issueDate; else earlyDate = today; Schedule schedule_(earlyDate, maturityDate, Period(static_cast<QuantLib::Frequency>(schedulefrequency)), calendar_, Unadjusted, Unadjusted, true, false); // put interest rate and credit spread points // into yield term structure std::vector<Date> yDates; std::vector<Real> yRates; std::vector<Real> ySpreads; for(Size i=0; i<schedule_.size(); i++) yDates.push_back(schedule_.at(i)); boost::shared_ptr<YieldTermStructure> termStructure_; std::vector<Date> dates; dates.push_back(today); for(int i = 0; i < yLen; i++) dates.push_back(today + riskFreeDays.at(i)); std::vector<Real> yTemp = riskFree; riskFree.clear(); riskFree.push_back(yTemp.at(0)); for(Size i=0; i<yTemp.size(); i++) riskFree.push_back(yTemp.at(i)); //figures out yield curve, uses linear fit termStructure_ = boost::shared_ptr<YieldTermStructure>(new InterpolatedZeroCurve<Linear>(dates, riskFree, dayCount)); for(Size i=0; i<yDates.size(); i++) yRates.push_back(termStructure_->zeroRate(yDates.at(i), dayCount, Continuous, NoFrequency)); for(Size i=0; i<yDates.size(); i++) ySpreads.push_back(convSpread.at(0)); // risk-free rate + credit spread curve std::vector<Real> yTotal; for(Size i = 0; i < yRates.size(); i++) yTotal.push_back(yRates.at(i) + ySpreads.at(i)); Handle<YieldTermStructure> totalStructure (boost::shared_ptr<YieldTermStructure>(new InterpolatedZeroCurve<Linear>(yDates, yTotal, dayCount))); // determine coupon schedule Frequency coupFreq = static_cast<QuantLib::Frequency>(couponFrequency); Date beforeMaturity = calendar_.advance(maturityDate, -Period(coupFreq), Unadjusted, true); if(beforeMaturity < earlyDate) beforeMaturity = maturityDate; Date afterIssue = beforeMaturity; while(afterIssue > earlyDate) afterIssue = calendar_.advance(afterIssue, -Period(coupFreq), Unadjusted, true); while(afterIssue <= earlyDate) afterIssue = calendar_.advance(afterIssue, Period(coupFreq), Unadjusted, true); Schedule bondSchedule; if((afterIssue <= earlyDate) || (afterIssue >= maturityDate) || (beforeMaturity <= earlyDate) || (beforeMaturity >= maturityDate)) { bondSchedule = Schedule(today, maturityDate, Period(coupFreq), calendar_, Unadjusted, Unadjusted, true, true); } else { bondSchedule = Schedule(today, maturityDate, Period(coupFreq), calendar_, Unadjusted, Unadjusted, true, true, afterIssue, beforeMaturity); } // set up bond boost::shared_ptr<Bond> bond_; DayCounter bondDayCount_ = Thirty360(); std::vector<Real> coupons_(1, coupon); bond_ = boost::shared_ptr<FixedRateBond>(new FixedRateBond(0, faceValue, bondSchedule, coupons_, bondDayCount_, Unadjusted, redemption, issueDate, totalStructure)); std::vector<Time> yTimes; //set up vector of times for(Size i=0; i<yDates.size(); i++) yTimes.push_back(dayCount.yearFraction(earlyDate, yDates.at(i))); //set up vector of bond amounts std::vector<Real> bondAmounts; for(Size k = 0; k < yDates.size(); k++){ bondAmounts.push_back(bond_->dirtyPrice(yTotal[k], Continuous, yDates[k])); } //send results to text file FILE * pFile; char timez[6] = "Time"; char valuez[5] = "Bond"; std::string filename = "straight_bond_values.txt"; pFile = fopen (filename.c_str(),"w"); fprintf (pFile, "%-10.10s \t %-10.10s \n", timez, valuez); for(Size j = 0; j < yTimes.size(); j++){ fprintf (pFile, "%f \t %f \n", yTimes.at(j), bondAmounts.at(j)); } fclose (pFile); //end print job system("PAUSE"); } catch (std::exception& e) { cout << e.what() << endl; system("PAUSE"); } return 0; } ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
John, Bascially the faceValue is the notional of your bond. The internally computed bond coupon amounts are based on this number. For the Redemption parameter, this is actually a function of the Face Value amount and IS NOT the final redemption value used for the last bond CashFlow. Basically the FixedRatebond computes the internal redemption amount as... BondRedemption = FaceValue*Redemption/100.0, where Redemption is what you supply to the constructor. You can look at it like this..., Redemption/100.0 acts as a multiplier for the FaceValue amount when working out the redemption cashflow amount. By default, Redemption is set to 100.0 and thus if you want to play with the notional of the bond, where the same notional is used for the bond's redemption cashflow amount, leave the Redemption parameter to it's default and play with the faceValue. Others may provide a more market centric explanation... Toy out... > To: [hidden email] > From: [hidden email] > Date: Thu, 15 Nov 2007 19:09:46 +0000 > Subject: [Quantlib-users] Redemption vs. Face Value > > In QuantLib, what is the difference between redemption > and face value for a fixed rate bond? I'm asking because > I thought I knew the difference, and have been getting > screwy answers. I'm working with a bond with the following > parameters: > > Maturity: 5/3/2041 > Coupon: 5.375% > Coupon Frequency: Quarterly > Coupon Type: Fixed > Redemption: $50 > Credit Spread: 500 bps > > If I use my code to price a bond with a $100 redemption > value, I get a present value of around $65. If I then > change it to a redemption of $50, I get a value of $62 > (when I expected to get a present value of $65/2 = $32.5). > I don't understand how a bond could be worth more now than > at redemption. I tried my code with redemptions ranging > from $10 - $100, and received results around $58 - $65. > I don't know if this is a problem in my code, or some > misunderstanding I have between face value and redemption. > The code I used is below. Thanks in advance. > > // TestQuantLib.cpp : Defines the entry point for the console > // application. > // > #include "stdafx.h" > #include <ql/quantlib.hpp> > #include <boost/timer.hpp> > > using namespace std; > using namespace QuantLib; > > #define LENGTH(a) (sizeof(a)/sizeof(a[0])) > > int _tmain(int argc, _TCHAR* argv[]) > { > try { > > // parameters > > // schedule frequency > int schedulefrequency = 52; > // coupon frequency > int couponFrequency = 4; > // coupon > double coupon = 0.05375; > // redemption value > double redemption = 50; > // face value > double faceValue = 100; > // days between today and issue > int issueDays = 0; > // days between today and maturity > int maturityDays = 12224; > // number of points in interest rate curve > int yLen = 10; > // days between today and interest rate curve date > int yieldDays[] = {92, 182, 366, 731, 1096, 1827, 3653, > 7305, 10958, 12224}; > // interest yield curve points > double yieldCurve[] = {0.034278, 0.037308, 0.036284, > 0.035433, 0.034892, > 0.038433, 0.042665, 0.046507, > 0.046163, 0.046045}; > // number of points in credit spread curve > int sLen = 1; > // credit spread curve points > double spreadCurve[] = {0.05}; > > // set up interest rate points > std::vector<Real> riskFree; > std::vector<int> riskFreeDays; > for(int i = 0; i < yLen; i++){ > riskFree.push_back(yieldCurve[i]); > riskFreeDays.push_back(yieldDays[i]); > } > > // set up credit spread points > std::vector<Real> convSpread; > for(int i = 0; i < sLen; i++) > convSpread.push_back(spreadCurve[i]); > > // set calendar and dates > Calendar calendar_ = UnitedStates(UnitedStates::Market::NYSE); > Date today = calendar_.adjust(Date::todaysDate()); > Settings::instance().evaluationDate() = today; > > DayCounter dayCount = Actual365Fixed(); > > Date issueDate = today + issueDays; > Date maturityDate = today + maturityDays; > Date earlyDate; > if(issueDate > today) > earlyDate = issueDate; > else > earlyDate = today; > > Schedule schedule_(earlyDate, maturityDate, > Period(static_cast<QuantLib::Frequency>(schedulefrequency)), > calendar_, Unadjusted, Unadjusted, true, false); > > // put interest rate and credit spread points > // into yield term structure > std::vector<Date> yDates; > std::vector<Real> yRates; > std::vector<Real> ySpreads; > > for(Size i=0; i<schedule_.size(); i++) > yDates.push_back(schedule_.at(i)); > > boost::shared_ptr<YieldTermStructure> termStructure_; > > std::vector<Date> dates; > > dates.push_back(today); > for(int i = 0; i < yLen; i++) > dates.push_back(today + riskFreeDays.at(i)); > > std::vector<Real> yTemp = riskFree; > riskFree.clear(); > riskFree.push_back(yTemp.at(0)); > for(Size i=0; i<yTemp.size(); i++) > riskFree.push_back(yTemp.at(i)); > > //figures out yield curve, uses linear fit > termStructure_ = boost::shared_ptr<YieldTermStructure>(new > InterpolatedZeroCurve<Linear>(dates, riskFree, > dayCount)); > > for(Size i=0; i<yDates.size(); i++) > yRates.push_back(termStructure_->zeroRate(yDates.at(i), > dayCount, Continuous, NoFrequency)); > > for(Size i=0; i<yDates.size(); i++) > ySpreads.push_back(convSpread.at(0)); > > // risk-free rate + credit spread curve > std::vector<Real> yTotal; > > for(Size i = 0; i < yRates.size(); i++) > yTotal.push_back(yRates.at(i) + ySpreads.at(i)); > > Handle<YieldTermStructure> totalStructure > (boost::shared_ptr<YieldTermStructure>(new > InterpolatedZeroCurve<Linear>(yDates, yTotal, > dayCount))); > > // determine coupon schedule > Frequency coupFreq = static_cast<QuantLib::Frequency>(couponFrequency); > > Date beforeMaturity = calendar_.advance(maturityDate, > -Period(coupFreq), > Unadjusted, true); > if(beforeMaturity < earlyDate) > beforeMaturity = maturityDate; > Date afterIssue = beforeMaturity; > while(afterIssue > earlyDate) > afterIssue = calendar_.advance(afterIssue, > -Period(coupFreq), Unadjusted, true); > while(afterIssue <= earlyDate) > afterIssue = calendar_.advance(afterIssue, > Period(coupFreq), Unadjusted, true); > > Schedule bondSchedule; > if((afterIssue <= earlyDate) || (afterIssue >= maturityDate) || > (beforeMaturity <= earlyDate) || (beforeMaturity >= maturityDate)) { > bondSchedule = Schedule(today, maturityDate, Period(coupFreq), > calendar_, Unadjusted, Unadjusted, true, true); > } else { > bondSchedule = Schedule(today, maturityDate, Period(coupFreq), > calendar_, Unadjusted, Unadjusted, true, true, afterIssue, beforeMaturity); > } > > // set up bond > boost::shared_ptr<Bond> bond_; > > DayCounter bondDayCount_ = Thirty360(); > > std::vector<Real> coupons_(1, coupon); > > bond_ = boost::shared_ptr<FixedRateBond>(new FixedRateBond(0, faceValue, > bondSchedule, coupons_, bondDayCount_, Unadjusted, redemption, > issueDate, totalStructure)); > > std::vector<Time> yTimes; > > //set up vector of times > for(Size i=0; i<yDates.size(); i++) > yTimes.push_back(dayCount.yearFraction(earlyDate, > yDates.at(i))); > > //set up vector of bond amounts > std::vector<Real> bondAmounts; > > for(Size k = 0; k < yDates.size(); k++){ > bondAmounts.push_back(bond_->dirtyPrice(yTotal[k], Continuous, yDates[k])); > } > > //send results to text file > FILE * pFile; > > char timez[6] = "Time"; > char valuez[5] = "Bond"; > > std::string filename = "straight_bond_values.txt"; > > pFile = fopen (filename.c_str(),"w"); > > fprintf (pFile, "%-10.10s \t %-10.10s \n", timez, valuez); > > for(Size j = 0; j < yTimes.size(); j++){ > fprintf (pFile, "%f \t %f \n", yTimes.at(j), bondAmounts.at(j)); > } > fclose (pFile); > > //end print job > > system("PAUSE"); > > } catch (std::exception& e) { > cout << e.what() << endl; > > system("PAUSE"); > } > return 0; > } > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > _______________________________________________ > QuantLib-users mailing list > [hidden email] > https://lists.sourceforge.net/lists/listinfo/quantlib-users Get free emoticon packs and customisation from Windows Live. Pimp My Live! ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
However... I haven't ran your code yet, but I must admit that I am baffled as to why you are getting the narrow range of dirty bond values you are computing for the large input redemption range... The bond price should be heavily inflenced by the Redemption value. In fact when changing the redemption value, the value of the bond cashflows (bar the last) should be constant. Have you tried valuing the bond across redemption values with a fixed settlement date? Looking at your code, your settlement date varies. Do you still see the same narrow range of dirty prices for the same fixed settle date? Actually it looks like the version of the dirtyPrice() function you are using is not present within SVN's Bond class (third parameter taking a Date parameter). Toy out.
The next generation of MSN Hotmail has arrived - Windows Live Hotmail ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Don't know what you mean by fixed settlement date. As far as I know, I set
the settlement date to today. The code looks a little confusing because it's been parsed from a longer version, but it's a working version that returns the values I've been talking about. Either the code is wacky (which I fully admit is highly likely), or something is hard coded that I'm not accounting for. I tried four different combinations of values for face value and redemption yesterday, and I received the following four values: Face Redemption Present Value 50 50 62.328 50 100 65.308 100 50 62.328 100 100 65.306 When I used this code earlier I had made the redemption and face value the same value. I then used a separate function to separate the coupon values from the bond, and found that these increments scaled like I expected to, i.e. the bond with a $10 face value/redemption had coupons that were 1/10 of a bond with a $100 face value/redemption. Yet the final values were only a few dollars away from each other. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
On Fri, 2007-11-16 at 13:58 +0000, John Maiden wrote:
> Don't know what you mean by fixed settlement date. As far as I know, I set > the settlement date to today. The code looks a little confusing because it's > been parsed from a longer version, but it's a working version that returns the > values I've been talking about. Either the code is wacky (which I fully admit is > highly likely), or something is hard coded that I'm not accounting for. I tried > four different combinations of values for face value and redemption yesterday, > and I received the following four values: > > Face Redemption Present Value > 50 50 62.328 > 50 100 65.308 > 100 50 62.328 > 100 100 65.306 What method are you using to retrieve the values above? I haven't looked at the bonds in a while, but I think that NPV() returns the dollar value while the several xyzPrice() returns the price in base 100. This said, the above is puzzling anyway. Can you attach the code you're using? Luigi -- Zawinski's Law: Every program attempts to expand until it can read mail. Those programs which cannot so expand are replaced by ones which can. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Luigi-
See the first post in this thread for the code. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Luigi-
I used the dirty price to get the present value, because I wanted to see the intermediate values over time. They produced a very weird graph. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
In reply to this post by Luigi Ballabio
Looks like a big portion of my issue came from a lack of understanding about the
use of dirty price. I was using dirtyPrice to compute what I thought was the evolution of the bond price over time using a fixed yield curve. If I use NPV(), then I get the answer I was expecting for the final value. Thanks Allen, Toy, and Chiara for clearing up my problems. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Hi:
Can you please advise me how I can unsubscribe from this list? I tried the link to unsubscribe but it does not seem to work.
Thanks in advance.
Srinivasan > To: [hidden email] > From: [hidden email] > Date: Fri, 16 Nov 2007 15:18:25 +0000 > Subject: Re: [Quantlib-users] Redemption vs. Face Value > > Looks like a big portion of my issue came from a lack of understanding about the > use of dirty price. I was using dirtyPrice to compute what I thought was the > evolution of the bond price over time using a fixed yield curve. If I use NPV(), > then I get the answer I was expecting for the final value. Thanks Allen, Toy, > and Chiara for clearing up my problems. > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > _______________________________________________ > QuantLib-users mailing list > [hidden email] > https://lists.sourceforge.net/lists/listinfo/quantlib-users ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
On Nov 17, 2007 12:20 PM, Srinivasan Rajasekaran <[hidden email]> wrote:
> Can you please advise me how I can unsubscribe from this list? I tried the > link to unsubscribe but it does not seem to work. try harder... scroll down to the end of https://lists.sourceforge.net/lists/listinfo/quantlib-users and follow the (standard Mailman) instructions. hope it helps ciao -- Nando ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Free forum by Nabble | Edit this page |