Proposed change to Convertible Bond model

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Proposed change to Convertible Bond model

John Maiden
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

Luigi Ballabio
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

John Maiden
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

Luigi Ballabio
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

John Maiden
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

John Maiden
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

Luigi Ballabio

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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

John Maiden
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

Luigi Ballabio
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

John Maiden
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
Reply | Threaded
Open this post in threaded view
|

Re: Proposed change to Convertible Bond model

Luigi Ballabio
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