Working through and trying to understand the convertible bond model, and came up
with a proposed change. At the moment the model requires fixed cash dividends. Proposed change to code would allow user to either choose a fixed cash dividend (through using a FixedDividend) or a fixed percent dividend (through using a FractionalDividend). Changes would be made to discretizedconvertible.cpp and binomialconvertibleengine.hpp. Besides changes to the code below, an additional change might have to be made to DiscretizedConvertible::DiscretizedConvertible through its initialization of the Array dividendValues_, though I'm not sure where else (or how) in the program this array is used. The code (changes are marked): //Proposed change to dividends in DiscretizedConvertible.cpp Disposable<Array> DiscretizedConvertible::adjustedGrid() const { Time t = time(); Array grid = method()->grid(t); // add back all dividend amounts in the future for (Size i=0; i<arguments_.dividends.size(); i++) { Time dividendTime = arguments_.dividendTimes[i]; if (dividendTime >= t || close(dividendTime,t)) { const boost::shared_ptr<Dividend>& d = arguments_.dividends[i]; //begin proposed change boost::shared_ptr<Dividend> testdiv = boost::dynamic_pointer_cast<FixedDividend>(arguments_.dividends[i]); if(testdiv){ for (Size j=0; j<grid.size(); j++) grid[j] += d->amount(grid[j]); } else { for (Size j=0; j<grid.size(); j++) grid[j] *= (1 + d->amount(grid[j])); } //end change //begin original code /* for (Size j=0; j<grid.size(); j++) grid[j] += d->amount(grid[j]); */ //end original code } } return grid; } //Proposed change to dividends in BinomialConvertibleEngine.hpp template <class T> void BinomialConvertibleEngine<T>::calculate() const { boost::shared_ptr<GeneralizedBlackScholesProcess> process = boost::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( this->arguments_.stochasticProcess); QL_REQUIRE(process, "Black-Scholes process required"); DayCounter rfdc = process->riskFreeRate()->dayCounter(); DayCounter divdc = process->dividendYield()->dayCounter(); DayCounter voldc = process->blackVolatility()->dayCounter(); Real s0 = process->stateVariable()->value(); Volatility v = process->blackVolatility()->blackVol( arguments_.exercise->lastDate(), s0); Date maturityDate = arguments_.exercise->lastDate(); Rate riskFreeRate = process->riskFreeRate()->zeroRate( maturityDate, rfdc, Continuous, NoFrequency); Rate q = process->dividendYield()->zeroRate( maturityDate, divdc, Continuous, NoFrequency); Date referenceDate = process->riskFreeRate()->referenceDate(); // subtract dividends Size i; for (i=0; i<arguments_.dividends.size(); i++) { boost::shared_ptr<Dividend> testdiv = boost::dynamic_pointer_cast<FixedDividend>(arguments_.dividends[i]); // begin proposed change if(testdiv){ if (arguments_.dividends[i]->date() >= referenceDate) s0 -= arguments_.dividends[i]->amount() * process->riskFreeRate()->discount( arguments_.dividends[i]->date()); } else { if (arguments_.dividends[i]->date() >= referenceDate) s0 /= (1 + arguments_.dividends[i]->amount()) * process->riskFreeRate()->discount( arguments_.dividends[i]->date()); } //end proposed change //begin original code /* if (arguments_.dividends[i]->date() >= referenceDate) s0 -= arguments_.dividends[i]->amount() * process->riskFreeRate()->discount( arguments_.dividends[i]->date()); */ //end original code } QL_REQUIRE(s0 > 0.0, "negative value after subtracting dividends"); // binomial trees with constant coefficient Handle<Quote> underlying( boost::shared_ptr<Quote>(new SimpleQuote(s0))); Handle<YieldTermStructure> flatRiskFree( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, riskFreeRate, rfdc))); Handle<YieldTermStructure> flatDividends( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, q, divdc))); Handle<BlackVolTermStructure> flatVol( boost::shared_ptr<BlackVolTermStructure>( new BlackConstantVol(referenceDate, v, voldc))); boost::shared_ptr<PlainVanillaPayoff> payoff = boost::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff); QL_REQUIRE(payoff, "non-plain payoff given"); Time maturity = rfdc.yearFraction(arguments_.settlementDate, maturityDate); boost::shared_ptr<StochasticProcess1D> bs( new GeneralizedBlackScholesProcess(underlying, flatDividends, flatRiskFree, flatVol)); boost::shared_ptr<T> tree(new T(bs, maturity, timeSteps_, payoff->strike())); Real creditSpread = arguments_.creditSpread->value(); boost::shared_ptr<NumericalMethod> lattice( new TsiveriotisFernandesLattice<T>(tree,riskFreeRate,maturity, timeSteps_,creditSpread,v,q)); // adjust times to grid TimeGrid grid(maturity, timeSteps_); for (i=0; i<arguments_.couponTimes.size(); i++) arguments_.couponTimes[i] = grid.closestTime(arguments_.couponTimes[i]); for (i=0; i<arguments_.stoppingTimes.size(); i++) arguments_.stoppingTimes[i] = grid.closestTime(arguments_.stoppingTimes[i]); for (i=0; i<arguments_.callabilityTimes.size(); i++) arguments_.callabilityTimes[i] = grid.closestTime(arguments_.callabilityTimes[i]); for (i=0; i<arguments_.dividendTimes.size(); i++) arguments_.dividendTimes[i] = grid.closestTime(arguments_.dividendTimes[i]); DiscretizedConvertible convertible(arguments_); convertible.initialize(lattice, maturity); convertible.rollback(0.0); results_.value = convertible.presentValue(); } ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
On Thu, 2007-05-24 at 23:27 +0000, John Maiden wrote:
> Working through and trying to understand the convertible bond model... Yes---apologies for the delay. With regard to your question about how the instrument drives the calculate() method of the engine, see the draft documentation I've made available at <http://www.compplusplus.com/2007/04/luigi_ballabio__2.html>. > ...and came up > with a proposed change. At the moment the model requires fixed cash dividends. > Proposed change to code would allow user to either choose a fixed cash dividend > (through using a FixedDividend) or a fixed percent dividend (through using a > FractionalDividend). Changes would be made to discretizedconvertible.cpp and > binomialconvertibleengine.hpp. Unfortunately, it's not so simple. Shifting the grid points by the amount of the fractional dividends causes the tree to no longer recombine. Actually, I remember we discussed the issue on the list at some point, but I don't seem to be able to retrieve the relevant posts. Does anyone happen to have records of the discussion? Later, Luigi ---------------------------------------- feature, n: A surprising property of a program. Occasionally documented. To call a property a feature sometimes means the author did not consider that case, and the program makes an unexpected, though not necessarily wrong response. See BUG. "That's not a bug, it's a feature!" A bug can be changed to a feature by documenting it. ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
In reply to this post by John Maiden
Does anyone know the purpose of the Soft Callability class? It's defined in
convertiblebond.hpp and implemented in discretizedconvertible.cpp. I'm asking because as far as I know, call triggers are typically tied to a period of time, e.g. stock price above 120% for 20 out of 30 days. In its implementation in QuantLib, it simply acts as a potential additional call at each node, and thus inflates the overall price of the bond. ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
On Thu, 2007-05-31 at 11:30 +0000, John Maiden wrote:
> Does anyone know the purpose of the Soft Callability class? It's defined in > convertiblebond.hpp and implemented in discretizedconvertible.cpp. I'm asking > because as far as I know, call triggers are typically tied to a period of time, > e.g. stock price above 120% for 20 out of 30 days. In its implementation in > QuantLib, it simply acts as a potential additional call at each node, and thus > inflates the overall price of the bond. At this time, there's no time period where the trigger condition has to hold; it's just checked at the callability date. I agree it should be fixed. However, the price increase might not be as high as you make it; unless I'm mistaken, the additional call is not at each node, but only at the node corresponding to the callability date. Later, Luigi ---------------------------------------- Present to inform, not to impress; if you inform, you will impress. -- Fred Brooks ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
Sorry, I meant that it only happens at each call date. I played with values
between 1.2 and 1, as well as using a standard call. For a specific call schedule and inputs (though this worked with other call schedules), the trigger at 1.2 significantly increased the result (way beyond expected values), while using no trigger was much lower (lower than expected). The difference in price was around ~15%. ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
In reply to this post by John Maiden
Two things I noticed about the existing convertible bond model that I think
needs to be changed: 1. All the dividends that are added back to the stock price in DiscretizedConvertible are the clean price, and need to be adjusted back at the risk free rate. Changes would be: - In class DiscretizedConvertible (DiscretizedConvertible.hpp), add a new DividendSchedule (I call it dirtyDividends_) - In Disposable<Array> ExtendedDiscretizedConvertible::adjustedGrid() const (DiscretizedConvertible.cpp), the pointer d is now const boost::shared_ptr<Dividend>& d = dirtyDividends_[i]; I've checked this, and the effect on the price in minimal, but there is a definite change. 2. Probabilities in the Tsiveriotis-Fernandes Lattice (tflattice.hpp) that are used to weigh the lattice values are fixed, and independent of the tree used. For some reason pu_ and pd_ are set to Cox-Ross-Rubinstein probabilities. The constructor for the TFLattice should now have the following code: dt_ = end/steps; pd_ = tree->probability(0,0,0); pu_ = tree->probability(0,0,1); riskFreeRate_ = riskFreeRate; creditSpread_ = creditSpread; QL_REQUIRE(pu_<=1.0, "negative probability"); QL_REQUIRE(pu_>=0.0, "negative probability"); This has a major effect on the prices. Before, using the example provided, there was a huge spread between values for different trees. Now the different trees produce much less spread (the difference is around 0.10 instead of the previous 10.00). ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
John, first of all, thanks for the effort you're putting into this review. On Fri, 2007-06-22 at 13:49 +0000, John Maiden wrote: > Two things I noticed about the existing convertible bond model that I think > needs to be changed: > > 1. All the dividends that are added back to the stock price in > DiscretizedConvertible are the clean price, and need to be adjusted back at the > risk free rate. Changes would be: > - In class DiscretizedConvertible (DiscretizedConvertible.hpp), add a new > DividendSchedule (I call it dirtyDividends_) > - In Disposable<Array> ExtendedDiscretizedConvertible::adjustedGrid() const > (DiscretizedConvertible.cpp), the pointer d is now const > boost::shared_ptr<Dividend>& d = dirtyDividends_[i]; I'm not sure i follow. Can you send a patch for the above? > 2. Probabilities in the Tsiveriotis-Fernandes Lattice (tflattice.hpp) that are > used to weigh the lattice values are fixed, and independent of the tree used. True---I just applied your fix to the repository. Later, Luigi -- The first rule of intelligent tinkering is to save all the parts. -- Paul Erlich ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
Luigi-
In DiscreteConvertible there is a protected array called dividendValues_. It's used once to compute the present value of the dividends, but is not used again. The code below goes into the constructor for DiscreteConvertible: //existing code dividendValues_ = Array(arguments_.dividends.size(), 0.0); boost::shared_ptr<GeneralizedBlackScholesProcess> process = boost::dynamic_pointer_cast<GeneralizedBlackScholesProcess>( arguments_.stochasticProcess); QL_REQUIRE(process, "Black-Scholes process required"); Date settlementDate = process->riskFreeRate()->referenceDate(); for (Size i=0; i<arguments_.dividends.size(); i++) { if (arguments_.dividends[i]->date() >= settlementDate) { dividendValues_[i] = arguments_.dividends[i]->amount() * process->riskFreeRate()->discount( arguments_.dividends[i]->date()); } } //load in a schedule of dirty dividend prices for (Size i=0; i<arguments_.dividends.size(); i++) { dirtyDividends_.push_back( boost::shared_ptr<Dividend>(new FixedDividend(dividendValues_[i], arguments_.dividends[i]->date()))); } ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
On Thu, 2007-06-28 at 12:32 +0000, John Maiden wrote:
> In DiscreteConvertible there is a protected array called dividendValues_. > It's used once to compute the present value of the dividends, but is not used > again. The code below goes into the constructor for DiscreteConvertible: John, are you applying your changes to a released tarball or to a Subversion checkout? Later, Luigi -- Never mistake motion for action. -- Ernest Hemingway ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
Luigi-
Version 0.8.0, the version that was on SourceForge a couple of weeks ago. ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
On Thu, 2007-06-28 at 17:46 +0000, John Maiden wrote:
> Luigi- > > Version 0.8.0, the version that was on SourceForge a couple of weeks ago. Ok, I just wanted to figure out the way you can produce a patch. If you have diff installed on your system, uncompress the original tarball besides your modified one (with a different name, of course,) run diff -r -b -C 3 QuantLib-0.8.0 QuantLib-0.8.0-modified > ql.diff (or whatever your directory names are) and send me the generated ql.diff. If you don't have diff, just send me the modified files and I'll try and figure out the changes. Later, Luigi -- I've finally learned what `upward compatible' means. It means we get to keep all our old mistakes. -- Dennie van Tassel ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ QuantLib-dev mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-dev |
Free forum by Nabble | Edit this page |