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