ConvertibleBonds.cpp

This example evaluates convertible bond prices.

00001 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 
00021 // the only header you need to use QuantLib
00022 #define BOOST_LIB_DIAGNOSTIC
00023 #  include <ql/quantlib.hpp>
00024 #undef BOOST_LIB_DIAGNOSTIC
00025 
00026 #ifdef BOOST_MSVC
00027 /* Uncomment the following lines to unmask floating-point
00028    exceptions. Warning: unpredictable results can arise...
00029 
00030    See http://www.wilmott.com/messageview.cfm?catid=10&threadid=9481
00031    Is there anyone with a definitive word about this?
00032 */
00033 // #include <float.h>
00034 // namespace { unsigned int u = _controlfp(_EM_INEXACT, _MCW_EM); }
00035 #endif
00036 
00037 #include <boost/timer.hpp>
00038 #include <iostream>
00039 #include <iomanip>
00040 
00041 #define LENGTH(a) (sizeof(a)/sizeof(a[0]))
00042 
00043 using namespace QuantLib;
00044 
00045 #if defined(QL_ENABLE_SESSIONS)
00046 namespace QuantLib {
00047 
00048     Integer sessionId() { return 0; }
00049 
00050 }
00051 #endif
00052 
00053 
00054 int main()
00055 {
00056     try {
00057 
00058         QL_IO_INIT
00059 
00060         boost::timer timer;
00061         std::cout << std::endl;
00062 
00063         Option::Type type(Option::Put);
00064         Real underlying = 36.0;
00065         Real spreadRate = 0.005;
00066 
00067         Spread dividendYield = 0.02;
00068         Rate riskFreeRate = 0.06;
00069         Volatility volatility = 0.20;
00070 
00071         Integer settlementDays = 3;
00072         Integer length = 5;
00073         Real redemption = 100.0;
00074         Real conversionRatio = redemption/underlying; // at the money
00075 
00076         // set up dates/schedules
00077         Calendar calendar = TARGET();
00078         Date today = calendar.adjust(Date::todaysDate());
00079 
00080         Settings::instance().evaluationDate() = today;
00081         Date settlementDate = calendar.advance(today, settlementDays, Days);
00082         Date exerciseDate = calendar.advance(settlementDate, length, Years);
00083         Date issueDate = calendar.advance(exerciseDate, -length, Years);
00084 
00085         BusinessDayConvention convention = ModifiedFollowing;
00086 
00087         Frequency frequency = Annual;
00088 
00089         Schedule schedule(issueDate,exerciseDate,Period(frequency),calendar,
00090                           convention, convention, true, false);
00091 
00092         DividendSchedule dividends;
00093         CallabilitySchedule callability;
00094 
00095         std::vector<Real> coupons(1, 0.05);
00096 
00097         DayCounter bondDayCount = Thirty360();
00098 
00099         Integer callLength[] = { 2, 4 };  // Call dates, years 2, 4.
00100         Integer putLength[] = { 3 }; // Put dates year 3
00101 
00102         Real callPrices[] = { 101.5, 100.85 };
00103         Real putPrices[]= { 105.0 };
00104 
00105         // Load call schedules
00106         for (Size i=0; i<LENGTH(callLength); i++) {
00107             callability.push_back(
00108                    boost::shared_ptr<Callability>(
00109                        new SoftCallability(Callability::Price(
00110                                                    callPrices[i],
00111                                                    Callability::Price::Clean),
00112                                            schedule.date(callLength[i]),
00113                                            1.20)));
00114         }
00115 
00116         for (Size j=0; j<LENGTH(putLength); j++) {
00117             callability.push_back(
00118                    boost::shared_ptr<Callability>(
00119                            new Callability(Callability::Price(
00120                                                    putPrices[j],
00121                                                    Callability::Price::Clean),
00122                                            Callability::Put,
00123                                            schedule.date(putLength[j]))));
00124         }
00125 
00126         // Assume dividends are paid every 6 months.
00127         for (Date d = today + 6*Months; d < exerciseDate; d += 6*Months) {
00128             dividends.push_back(
00129                       boost::shared_ptr<Dividend>(new FixedDividend(1.0, d)));
00130         }
00131 
00132         DayCounter dayCounter = Actual365Fixed();
00133         Time maturity = dayCounter.yearFraction(settlementDate,
00134                                                 exerciseDate);
00135 
00136         std::cout << "option type = "  << type << std::endl;
00137         std::cout << "Time to maturity = "        << maturity
00138                   << std::endl;
00139         std::cout << "Underlying price = "        << underlying
00140                   << std::endl;
00141         std::cout << "Risk-free interest rate = " << io::rate(riskFreeRate)
00142                   << std::endl;
00143         std::cout << "Dividend yield = " << io::rate(dividendYield)
00144                   << std::endl;
00145         std::cout << "Volatility = " << io::volatility(volatility)
00146                   << std::endl;
00147         std::cout << std::endl;
00148 
00149         std::string method;
00150         std::cout << std::endl ;
00151 
00152         // write column headings
00153         Size widths[] = { 35, 14, 14 };
00154         Size totalWidth = widths[0] + widths[1] + widths[2];
00155         std::string rule(totalWidth, '-'), dblrule(totalWidth, '=');
00156 
00157         std::cout << dblrule << std::endl;
00158         std::cout << "Tsiveriotis-Fernandes method" << std::endl;
00159         std::cout << dblrule << std::endl;
00160         std::cout << std::setw(widths[0]) << std::left << "Tree type"
00161                   << std::setw(widths[1]) << std::left << "European"
00162                   << std::setw(widths[1]) << std::left << "American"
00163                   << std::endl;
00164         std::cout << rule << std::endl;
00165 
00166         boost::shared_ptr<Exercise> exercise(
00167                                           new EuropeanExercise(exerciseDate));
00168         boost::shared_ptr<Exercise> amExercise(
00169                                           new AmericanExercise(settlementDate,
00170                                                                exerciseDate));
00171 
00172         Handle<Quote> underlyingH(
00173             boost::shared_ptr<Quote>(new SimpleQuote(underlying)));
00174 
00175         Handle<YieldTermStructure> flatTermStructure(
00176             boost::shared_ptr<YieldTermStructure>(
00177                 new FlatForward(settlementDate, riskFreeRate, dayCounter)));
00178 
00179         Handle<YieldTermStructure> flatDividendTS(
00180             boost::shared_ptr<YieldTermStructure>(
00181                 new FlatForward(settlementDate, dividendYield, dayCounter)));
00182 
00183         Handle<BlackVolTermStructure> flatVolTS(
00184             boost::shared_ptr<BlackVolTermStructure>(
00185                 new BlackConstantVol(settlementDate, volatility, dayCounter)));
00186 
00187 
00188         boost::shared_ptr<StochasticProcess> stochasticProcess(
00189                               new BlackScholesMertonProcess(underlyingH,
00190                                                             flatDividendTS,
00191                                                             flatTermStructure,
00192                                                             flatVolTS));
00193 
00194         Size timeSteps = 801;
00195 
00196         Handle<Quote> creditSpread(
00197                        boost::shared_ptr<Quote>(new SimpleQuote(spreadRate)));
00198 
00199         boost::shared_ptr<Quote> rate(new SimpleQuote(riskFreeRate));
00200 
00201         Handle<YieldTermStructure> discountCurve(
00202                 boost::shared_ptr<YieldTermStructure>(
00203                     new FlatForward(today, Handle<Quote>(rate), dayCounter)));
00204 
00205         boost::shared_ptr<PricingEngine> engine(
00206                  new BinomialConvertibleEngine<JarrowRudd>(timeSteps));
00207 
00208         ConvertibleFixedCouponBond europeanBond(
00209                                 stochasticProcess, exercise, engine,
00210                                 conversionRatio, dividends, callability,
00211                                 creditSpread, issueDate, settlementDays,
00212                                 coupons, bondDayCount, schedule, redemption);
00213 
00214         ConvertibleFixedCouponBond americanBond(
00215                                 stochasticProcess, amExercise, engine,
00216                                 conversionRatio, dividends, callability,
00217                                 creditSpread, issueDate, settlementDays,
00218                                 coupons, bondDayCount, schedule, redemption);
00219 
00220         method = "Jarrow-Rudd";
00221         europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00222                        new BinomialConvertibleEngine<JarrowRudd>(timeSteps)));
00223         americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00224                        new BinomialConvertibleEngine<JarrowRudd>(timeSteps)));
00225         std::cout << std::setw(widths[0]) << std::left << method
00226                   << std::fixed
00227                   << std::setw(widths[1]) << std::left << europeanBond.NPV()
00228                   << std::setw(widths[2]) << std::left << americanBond.NPV()
00229                   << std::endl;
00230 
00231         method = "Cox-Ross-Rubinstein";
00232         europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00233                 new BinomialConvertibleEngine<CoxRossRubinstein>(timeSteps)));
00234         americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00235                 new BinomialConvertibleEngine<CoxRossRubinstein>(timeSteps)));
00236         std::cout << std::setw(widths[0]) << std::left << method
00237                   << std::fixed
00238                   << std::setw(widths[1]) << std::left << europeanBond.NPV()
00239                   << std::setw(widths[2]) << std::left << americanBond.NPV()
00240                   << std::endl;
00241 
00242         method = "Additive equiprobabilities";
00243         europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00244           new BinomialConvertibleEngine<AdditiveEQPBinomialTree>(timeSteps)));
00245         americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00246           new BinomialConvertibleEngine<AdditiveEQPBinomialTree>(timeSteps)));
00247         std::cout << std::setw(widths[0]) << std::left << method
00248                   << std::fixed
00249                   << std::setw(widths[1]) << std::left << europeanBond.NPV()
00250                   << std::setw(widths[2]) << std::left << americanBond.NPV()
00251                   << std::endl;
00252 
00253         method = "Trigeorgis";
00254         europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00255                        new BinomialConvertibleEngine<Trigeorgis>(timeSteps)));
00256         americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00257                        new BinomialConvertibleEngine<Trigeorgis>(timeSteps)));
00258         std::cout << std::setw(widths[0]) << std::left << method
00259                   << std::fixed
00260                   << std::setw(widths[1]) << std::left << europeanBond.NPV()
00261                   << std::setw(widths[2]) << std::left << americanBond.NPV()
00262                   << std::endl;
00263 
00264         method = "Tian";
00265         europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00266                              new BinomialConvertibleEngine<Tian>(timeSteps)));
00267         americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00268                              new BinomialConvertibleEngine<Tian>(timeSteps)));
00269         std::cout << std::setw(widths[0]) << std::left << method
00270                   << std::fixed
00271                   << std::setw(widths[1]) << std::left << europeanBond.NPV()
00272                   << std::setw(widths[2]) << std::left << americanBond.NPV()
00273                   << std::endl;
00274 
00275         method = "Leisen-Reimer";
00276         europeanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00277                      new BinomialConvertibleEngine<LeisenReimer>(timeSteps)));
00278         americanBond.setPricingEngine(boost::shared_ptr<PricingEngine>(
00279                      new BinomialConvertibleEngine<LeisenReimer>(timeSteps)));
00280         std::cout << std::setw(widths[0]) << std::left << method
00281                   << std::fixed
00282                   << std::setw(widths[1]) << std::left << europeanBond.NPV()
00283                   << std::setw(widths[2]) << std::left << americanBond.NPV()
00284                   << std::endl;
00285 
00286         std::cout << dblrule << std::endl;
00287 
00288         Real seconds = timer.elapsed();
00289         Integer hours = int(seconds/3600);
00290         seconds -= hours * 3600;
00291         Integer minutes = int(seconds/60);
00292         seconds -= minutes * 60;
00293         std::cout << " \nRun completed in ";
00294         if (hours > 0)
00295             std::cout << hours << " h ";
00296         if (hours > 0 || minutes > 0)
00297             std::cout << minutes << " m ";
00298         std::cout << std::fixed << std::setprecision(0)
00299                   << seconds << " s\n" << std::endl;
00300 
00301         return 0;
00302     } catch (std::exception& e) {
00303         std::cout << e.what() << std::endl;
00304         return 1;
00305     } catch (...) {
00306         std::cout << "unknown error" << std::endl;
00307         return 1;
00308     }
00309 
00310 }
00311