ConvertibleBonds.cpp

This example evaluates convertible bond prices.

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