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