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