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