Rainy day here so I got to play a little, at long last, with the fixed income
functions. I can't make sense of duration() in CashFlows/analysis.{cpp,hpp} In particular this line seems wrong: totalNPV -= marketPrice; before the sum of present value times time (here variable totalDuration) gets divided by totalNPV as in return totalDuration/totalNPV; which is supported via quick googling [ http://www.finpipe.com/duration.htm ] and one of the investments texts here. Likewise, modified duration is normaly given as Macaulay Duration divided by (1 + y / nbcoupons) -- so that a second fix would be case Duration::Modified: //return totalDuration / totalNPV / y; return totalDuration / totalNPV / (1 + y/rate.frequency()); A simplistic program, taken from one of the regression test cases, is below and I added a local copy of the duration function from analysis.cpp. I may have overlooked something, but I guess we should at least add some validated regression tests for some duration, convexity, ... cases. Any volunteers? Oh, and one last question: why isn't the redemption at par payment already included when I call cashflow() on a bond? Dirk #include <iostream> #include <ql/quantlib.hpp> using namespace std; using namespace QuantLib; Time myDuration(const std::vector<boost::shared_ptr<CashFlow> >& cashflows, Real marketPrice, const InterestRate& rate, Duration::Type type, Date settlementDate) { if (settlementDate == Date()) settlementDate = Settings::instance().evaluationDate(); Real totalDuration = 0.0; Real totalNPV = 0.0; Rate y = 0.0; if (type == Duration::Macaulay || type == Duration::Modified) { y = Cashflows::irr(cashflows, marketPrice, rate.dayCounter(), rate.compounding(), rate.frequency(), settlementDate); cout << "Y is " << y << " " << rate.frequency() << endl; } for (Size i = 0; i < cashflows.size(); i++) { Time t = rate.dayCounter().yearFraction(settlementDate, cashflows[i]->date()); Real c = cashflows[i]->amount(); DiscountFactor discount; if (type == Duration::Macaulay) discount = std::exp(-y*t); else discount = rate.discountFactor(t); totalNPV += c * discount; totalDuration += t * c * discount; } //totalNPV -= marketPrice; // edd 28-Jan-2006: this is probably in error if (totalNPV == 0.0) // what to do? return 0.0; switch (type){ case Duration::Modified: //return totalDuration / totalNPV / y; // edd 28-Jan-2006: error? return totalDuration / totalNPV / (1 + y/rate.frequency()); case Duration::Simple: case Duration::Macaulay: return totalDuration/totalNPV; default: QL_FAIL("unknown duration type"); } } int main(void) { Calendar calendar = TARGET(); Date today = calendar.adjust(Date::todaysDate()); Settings::instance().evaluationDate() = today; Real redemption = 100.0; // bond pay $100 face at term Integer issueMonth = -12; // bond issued 12 months ago Integer bondTerm = 5; // bond has a 5yr term-to-maturity Real bondCoupon = 0.05; // bond has 5% coupon Frequency bondCoupFreq = Semiannual; // bond pays coupon annually DayCounter bondDayCount = Thirty360(); Compounding compounding = Compounded; BusinessDayConvention convention = ModifiedFollowing; Integer settlementDays = 3; Rate currentYield = 0.0475; Date dated = calendar.advance(today, issueMonth, Months); Date issue = dated; Date maturity = calendar.advance(issue, bondTerm, Years); boost::shared_ptr<YieldTermStructure> flatRate(new FlatForward(dated, currentYield, bondDayCount, compounding, bondCoupFreq)); FixedCouponBond bond(issue, dated, maturity, settlementDays, std::vector<Rate>(1, bondCoupon), bondCoupFreq, bondDayCount, calendar, convention, redemption, Handle<YieldTermStructure>(flatRate)); Real cleanPrice = bond.cleanPrice(currentYield, compounding); Real dirtyPrice = bond.dirtyPrice(currentYield, compounding); Rate calculated = bond.yield(cleanPrice, compounding); Real accrued = bond.accruedAmount(); cout << "Dirty Price: " << dirtyPrice << endl; cout << "Clean Price: " << cleanPrice << endl; cout << "Yield : " << calculated << endl; cout << "Accrued : " << accrued << endl; // need to explicitly push redemption cash flow into cf vector -- why ? std::vector<boost::shared_ptr<CashFlow> > cfVec(bond.cashflows()); cfVec.push_back(bond.redemption()); Real irr = Cashflows::irr(cfVec, cleanPrice, bondDayCount, compounding, bondCoupFreq, issue); cout << "Irr : " << irr << endl; InterestRate rate(calculated, bondDayCount, compounding, bondCoupFreq); cout << "Rate : " << rate << endl; // Time duration = Cashflows::duration(cfVec, cleanPrice, rate, // Duration::Modified, dated); Time macDuration = myDuration(cfVec, cleanPrice, rate, Duration::Macaulay, dated); Time modDuration = myDuration(cfVec, cleanPrice, rate, Duration::Modified, dated); Time simDuration = myDuration(cfVec, cleanPrice, rate, Duration::Simple, dated); cout << "MacDuration: " << macDuration << endl; cout << "ModDuration: " << modDuration << endl; cout << "SimDuration: " << simDuration << endl; for (unsigned int i=0; i<cfVec.size(); i++) { cout << "Date " << i << " :\t" << cfVec[i]->date() << "\t" << "Amount: " << cfVec[i]->amount() << endl; } } -- Hell, there are no rules here - we're trying to accomplish something. -- Thomas A. Edison |
Dudes,
Nobody followed on the most-likely-a-bug report I made -- does anybody have access to an alternate calculator to check simple, modified and macaulay duration for a few securities? As indicated, I think what we have in analysis.{cpp,hpp} is wrong. Yet another source of documentation is at Wikipedia at http://en.wikipedia.org/wiki/Bond_duration Dirk On 28 January 2006 at 18:46, Dirk Eddelbuettel wrote: | | Rainy day here so I got to play a little, at long last, with the fixed income | functions. I can't make sense of duration() in CashFlows/analysis.{cpp,hpp} | In particular this line seems wrong: | | totalNPV -= marketPrice; | | before the sum of present value times time (here variable totalDuration) gets | divided by totalNPV as in | | return totalDuration/totalNPV; | | which is supported via quick googling [ http://www.finpipe.com/duration.htm ] | and one of the investments texts here. | | Likewise, modified duration is normaly given as Macaulay Duration divided by | (1 + y / nbcoupons) -- so that a second fix would be | | case Duration::Modified: | //return totalDuration / totalNPV / y; | return totalDuration / totalNPV / (1 + y/rate.frequency()); | | A simplistic program, taken from one of the regression test cases, is below | and I added a local copy of the duration function from analysis.cpp. | | I may have overlooked something, but I guess we should at least add some | validated regression tests for some duration, convexity, ... cases. | Any volunteers? | | Oh, and one last question: why isn't the redemption at par payment already | included when I call cashflow() on a bond? | | Dirk | | | #include <iostream> | #include <ql/quantlib.hpp> | | using namespace std; | using namespace QuantLib; | | Time myDuration(const std::vector<boost::shared_ptr<CashFlow> >& cashflows, | Real marketPrice, | const InterestRate& rate, | Duration::Type type, | Date settlementDate) { | | if (settlementDate == Date()) | settlementDate = Settings::instance().evaluationDate(); | | Real totalDuration = 0.0; | Real totalNPV = 0.0; | | Rate y = 0.0; | if (type == Duration::Macaulay || type == Duration::Modified) { | y = Cashflows::irr(cashflows, marketPrice, rate.dayCounter(), | rate.compounding(), rate.frequency(), settlementDate); | cout << "Y is " << y << " " << rate.frequency() << endl; | } | | for (Size i = 0; i < cashflows.size(); i++) { | Time t = rate.dayCounter().yearFraction(settlementDate, | cashflows[i]->date()); | Real c = cashflows[i]->amount(); | DiscountFactor discount; | if (type == Duration::Macaulay) | discount = std::exp(-y*t); | else | discount = rate.discountFactor(t); | | totalNPV += c * discount; | totalDuration += t * c * discount; | } | //totalNPV -= marketPrice; // edd 28-Jan-2006: this is probably in error | | if (totalNPV == 0.0) | // what to do? | return 0.0; | | switch (type){ | case Duration::Modified: | //return totalDuration / totalNPV / y; // edd 28-Jan-2006: error? | return totalDuration / totalNPV / (1 + y/rate.frequency()); | case Duration::Simple: | case Duration::Macaulay: | return totalDuration/totalNPV; | default: | QL_FAIL("unknown duration type"); | } | } | | | int main(void) { | | Calendar calendar = TARGET(); | Date today = calendar.adjust(Date::todaysDate()); | Settings::instance().evaluationDate() = today; | | Real redemption = 100.0; // bond pay $100 face at term | Integer issueMonth = -12; // bond issued 12 months ago | Integer bondTerm = 5; // bond has a 5yr term-to-maturity | Real bondCoupon = 0.05; // bond has 5% coupon | Frequency bondCoupFreq = Semiannual; // bond pays coupon annually | DayCounter bondDayCount = Thirty360(); | Compounding compounding = Compounded; | BusinessDayConvention convention = ModifiedFollowing; | Integer settlementDays = 3; | | Rate currentYield = 0.0475; | | Date dated = calendar.advance(today, issueMonth, Months); | Date issue = dated; | Date maturity = calendar.advance(issue, bondTerm, Years); | | boost::shared_ptr<YieldTermStructure> | flatRate(new FlatForward(dated, currentYield, bondDayCount, | compounding, bondCoupFreq)); | | FixedCouponBond bond(issue, dated, maturity, settlementDays, | std::vector<Rate>(1, bondCoupon), | bondCoupFreq, bondDayCount, | calendar, convention, redemption, | Handle<YieldTermStructure>(flatRate)); | | Real cleanPrice = bond.cleanPrice(currentYield, compounding); | Real dirtyPrice = bond.dirtyPrice(currentYield, compounding); | Rate calculated = bond.yield(cleanPrice, compounding); | Real accrued = bond.accruedAmount(); | | cout << "Dirty Price: " << dirtyPrice << endl; | cout << "Clean Price: " << cleanPrice << endl; | cout << "Yield : " << calculated << endl; | cout << "Accrued : " << accrued << endl; | | // need to explicitly push redemption cash flow into cf vector -- why ? | std::vector<boost::shared_ptr<CashFlow> > cfVec(bond.cashflows()); | cfVec.push_back(bond.redemption()); | | Real irr = Cashflows::irr(cfVec, cleanPrice, | bondDayCount, compounding, bondCoupFreq, issue); | cout << "Irr : " << irr << endl; | | InterestRate rate(calculated, bondDayCount, compounding, bondCoupFreq); | cout << "Rate : " << rate << endl; | // Time duration = Cashflows::duration(cfVec, cleanPrice, rate, | // Duration::Modified, dated); | Time macDuration = myDuration(cfVec, cleanPrice, rate, | Duration::Macaulay, dated); | Time modDuration = myDuration(cfVec, cleanPrice, rate, | Duration::Modified, dated); | Time simDuration = myDuration(cfVec, cleanPrice, rate, | Duration::Simple, dated); | cout << "MacDuration: " << macDuration << endl; | cout << "ModDuration: " << modDuration << endl; | cout << "SimDuration: " << simDuration << endl; | | for (unsigned int i=0; i<cfVec.size(); i++) { | cout << "Date " << i << " :\t" << cfVec[i]->date() << "\t" | << "Amount: " << cfVec[i]->amount() << endl; | } | | } | | | | -- | Hell, there are no rules here - we're trying to accomplish something. | -- Thomas A. Edison | | | ------------------------------------------------------- | This SF.net email is sponsored by: Splunk Inc. Do you grep through log files | for problems? Stop! Download the new AJAX search engine that makes | searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! | http://sel.as-us.falkag.net/sel?cmd=lnk&kid=103432&bid=230486&dat=121642 | _______________________________________________ | Quantlib-users mailing list | [hidden email] | https://lists.sourceforge.net/lists/listinfo/quantlib-users -- Hell, there are no rules here - we're trying to accomplish something. -- Thomas A. Edison |
On 2/2/06, Dirk Eddelbuettel <[hidden email]> wrote:
> Nobody followed on the most-likely-a-bug report I made -- does anybody have > access to an alternate calculator to check simple, modified and macaulay > duration for a few securities? As indicated, I think what we have in > analysis.{cpp,hpp} is wrong. Yet another source of documentation is at > Wikipedia at http://en.wikipedia.org/wiki/Bond_duration I second the request. Anybody? Luigi |
Hi,
Check out the following towards the bottom of the page... http://www.fincad.com/support/developerfunc/mathref/lcb.htm You could also play with the 7-day demo as well... Toy out. >From: Luigi Ballabio <[hidden email]> >To: Dirk Eddelbuettel <[hidden email]> >CC: quantlib-users <[hidden email]> >Subject: Re: [Quantlib-users] Bond duration incorrect ? >Date: Thu, 2 Feb 2006 16:53:41 +0100 > >On 2/2/06, Dirk Eddelbuettel <[hidden email]> wrote: > > Nobody followed on the most-likely-a-bug report I made -- does anybody >have > > access to an alternate calculator to check simple, modified and macaulay > > duration for a few securities? As indicated, I think what we have in > > analysis.{cpp,hpp} is wrong. Yet another source of documentation is at > > Wikipedia at http://en.wikipedia.org/wiki/Bond_duration > >I second the request. Anybody? > >Luigi > > >------------------------------------------------------- >This SF.net email is sponsored by: Splunk Inc. Do you grep through log >files >for problems? Stop! Download the new AJAX search engine that makes >searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! ><a href="http://sel.as-us.falkag.net/sel?cmd=lnk&kid3432&bid#0486&dat1642">http://sel.as-us.falkag.net/sel?cmd=lnk&kid3432&bid#0486&dat1642 >_______________________________________________ >Quantlib-users mailing list >[hidden email] >https://lists.sourceforge.net/lists/listinfo/quantlib-users |
In reply to this post by Luigi Ballabio
Hi,
There actually is an implementation of building credit default curves and the pricing of credit default swaps. The library actually uses a cut down version of quantlib for most of the building blocks. However the default probability curves built does have the annoying assumption that defaults can only happen once a year and does not take into consideration accural payments. The math is sound and the coding pretty clean, however I don't like the recursion approach for the solving of probabilities (I prefer Quantlib's rateHelpers approach) coupled with a maximum length that a credit curve can occupy. What I do like is that they have a spreadsheet (creditCurveYann.xls) implementation of a credit default curve stripper using Excel alone (coupled with Excel's solver). Now this is a pretty good basis for a rateHelper approach The library happens to contain other financial building blocks currently not present within quantlib (ie volatility swaps...). The library, I believe, is LGPL. check it out at : http://terreneuve.sourceforge.net/ You may want to read the pdf first to get an idea of what the library is capable of : http://terreneuve.sourceforge.net/1.0/Report.pdf Very nice library. Toy out. |
Hi,
Oh... when I talk about rateHelpers for credit derivatives, I meant a new category of rateHelpers that can cater for deriving default probabilities instead of discout factors (ie - creditHelpers). These classes can probabliy be used within a new PiecewiseCreditCurve (similar to the current PiecewiseYieldCurve) As you may or may not know, you can derive default probabilities from credit default swaps, Bonds, Transition matrices etc... What do you think... Toy out. >From: "Toyin Akin" <[hidden email]> >To: [hidden email] >CC: [hidden email] >Subject: [Quantlib-users] Credit derivatives implementation... >Date: Thu, 02 Feb 2006 17:38:43 +0000 > > >Hi, > >There actually is an implementation of building credit default curves and >the pricing of credit default swaps. > >The library actually uses a cut down version of quantlib for most of the >building blocks. > >However the default probability curves built does have the annoying >assumption that defaults can only happen once a year and does not take into >consideration accural payments. > >The math is sound and the coding pretty clean, however I don't like the >recursion approach for the solving of probabilities (I prefer Quantlib's >rateHelpers approach) coupled with a maximum length that a credit curve can >occupy. > >What I do like is that they have a spreadsheet (creditCurveYann.xls) >implementation of a credit default curve stripper using Excel alone >(coupled with Excel's solver). Now this is a pretty good basis for a >rateHelper approach > >The library happens to contain other financial building blocks currently >not present within quantlib (ie volatility swaps...). > >The library, I believe, is LGPL. > >check it out at : http://terreneuve.sourceforge.net/ > >You may want to read the pdf first to get an idea of what the library is >capable of : > >http://terreneuve.sourceforge.net/1.0/Report.pdf > >Very nice library. > >Toy out. > > > > >------------------------------------------------------- >This SF.net email is sponsored by: Splunk Inc. Do you grep through log >files >for problems? Stop! Download the new AJAX search engine that makes >searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! >http://sel.as-us.falkag.net/sel?cmd=lnk&kid=103432&bid=230486&dat=121642 >_______________________________________________ >Quantlib-users mailing list >[hidden email] >https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Free forum by Nabble | Edit this page |