BermudanSwaption.cpp
This is an example of using the QuantLib short rate models.
00001 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 00002 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 using namespace QuantLib; 00042 00043 #if defined(QL_ENABLE_SESSIONS) 00044 namespace QuantLib { 00045 00046 Integer sessionId() { return 0; } 00047 00048 } 00049 #endif 00050 00051 00052 //Number of swaptions to be calibrated to... 00053 00054 Size numRows = 5; 00055 Size numCols = 5; 00056 00057 Integer swapLenghts[] = { 00058 1, 2, 3, 4, 5}; 00059 Volatility swaptionVols[] = { 00060 0.1490, 0.1340, 0.1228, 0.1189, 0.1148, 00061 0.1290, 0.1201, 0.1146, 0.1108, 0.1040, 00062 0.1149, 0.1112, 0.1070, 0.1010, 0.0957, 00063 0.1047, 0.1021, 0.0980, 0.0951, 0.1270, 00064 0.1000, 0.0950, 0.0900, 0.1230, 0.1160}; 00065 00066 void calibrateModel( 00067 const boost::shared_ptr<ShortRateModel>& model, 00068 const std::vector<boost::shared_ptr<CalibrationHelper> >& helpers) { 00069 00070 LevenbergMarquardt om; 00071 model->calibrate(helpers, om, 00072 EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8)); 00073 00074 // Output the implied Black volatilities 00075 for (Size i=0; i<numRows; i++) { 00076 Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1 00077 Size k = i*numCols + j; 00078 Real npv = helpers[i]->modelValue(); 00079 Volatility implied = helpers[i]->impliedVolatility(npv, 1e-4, 00080 1000, 0.05, 0.50); 00081 Volatility diff = implied - swaptionVols[k]; 00082 00083 std::cout << i+1 << "x" << swapLenghts[j] 00084 << std::setprecision(5) << std::noshowpos 00085 << ": model " << std::setw(7) << io::volatility(implied) 00086 << ", market " << std::setw(7) 00087 << io::volatility(swaptionVols[k]) 00088 << " (" << std::setw(7) << std::showpos 00089 << io::volatility(diff) << std::noshowpos << ")\n"; 00090 } 00091 } 00092 00093 int main(int, char* []) { 00094 00095 try { 00096 00097 boost::timer timer; 00098 std::cout << std::endl; 00099 00100 Date todaysDate(15, February, 2002); 00101 Calendar calendar = TARGET(); 00102 Date settlementDate(19, February, 2002); 00103 Settings::instance().evaluationDate() = todaysDate; 00104 00105 // flat yield term structure impling 1x5 swap at 5% 00106 boost::shared_ptr<Quote> flatRate(new SimpleQuote(0.04875825)); 00107 Handle<YieldTermStructure> rhTermStructure( 00108 boost::shared_ptr<FlatForward>( 00109 new FlatForward(settlementDate, Handle<Quote>(flatRate), 00110 Actual365Fixed()))); 00111 00112 // Define the ATM/OTM/ITM swaps 00113 Frequency fixedLegFrequency = Annual; 00114 BusinessDayConvention fixedLegConvention = Unadjusted; 00115 BusinessDayConvention floatingLegConvention = ModifiedFollowing; 00116 DayCounter fixedLegDayCounter = Thirty360(Thirty360::European); 00117 Frequency floatingLegFrequency = Semiannual; 00118 VanillaSwap::Type type = VanillaSwap::Payer; 00119 Rate dummyFixedRate = 0.03; 00120 boost::shared_ptr<IborIndex> indexSixMonths(new 00121 Euribor6M(rhTermStructure)); 00122 00123 Date startDate = calendar.advance(settlementDate,1,Years, 00124 floatingLegConvention); 00125 Date maturity = calendar.advance(startDate,5,Years, 00126 floatingLegConvention); 00127 Schedule fixedSchedule(startDate,maturity,Period(fixedLegFrequency), 00128 calendar,fixedLegConvention,fixedLegConvention, 00129 false,false); 00130 Schedule floatSchedule(startDate,maturity,Period(floatingLegFrequency), 00131 calendar,floatingLegConvention,floatingLegConvention, 00132 false,false); 00133 00134 boost::shared_ptr<VanillaSwap> swap(new VanillaSwap( 00135 type, 1000.0, 00136 fixedSchedule, dummyFixedRate, fixedLegDayCounter, 00137 floatSchedule, indexSixMonths, 0.0, 00138 indexSixMonths->dayCounter(), rhTermStructure)); 00139 Rate fixedATMRate = swap->fairRate(); 00140 Rate fixedOTMRate = fixedATMRate * 1.2; 00141 Rate fixedITMRate = fixedATMRate * 0.8; 00142 00143 boost::shared_ptr<VanillaSwap> atmSwap(new VanillaSwap( 00144 type, 1000.0, 00145 fixedSchedule, fixedATMRate, fixedLegDayCounter, 00146 floatSchedule, indexSixMonths, 0.0, 00147 indexSixMonths->dayCounter(), rhTermStructure)); 00148 boost::shared_ptr<VanillaSwap> otmSwap(new VanillaSwap( 00149 type, 1000.0, 00150 fixedSchedule, fixedOTMRate, fixedLegDayCounter, 00151 floatSchedule, indexSixMonths, 0.0, 00152 indexSixMonths->dayCounter(), rhTermStructure)); 00153 boost::shared_ptr<VanillaSwap> itmSwap(new VanillaSwap( 00154 type, 1000.0, 00155 fixedSchedule, fixedITMRate, fixedLegDayCounter, 00156 floatSchedule, indexSixMonths, 0.0, 00157 indexSixMonths->dayCounter(), rhTermStructure)); 00158 00159 // defining the swaptions to be used in model calibration 00160 std::vector<Period> swaptionMaturities; 00161 swaptionMaturities.push_back(Period(1, Years)); 00162 swaptionMaturities.push_back(Period(2, Years)); 00163 swaptionMaturities.push_back(Period(3, Years)); 00164 swaptionMaturities.push_back(Period(4, Years)); 00165 swaptionMaturities.push_back(Period(5, Years)); 00166 00167 std::vector<boost::shared_ptr<CalibrationHelper> > swaptions; 00168 00169 // List of times that have to be included in the timegrid 00170 std::list<Time> times; 00171 00172 Size i; 00173 for (i=0; i<numRows; i++) { 00174 Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1 00175 Size k = i*numCols + j; 00176 boost::shared_ptr<Quote> vol(new SimpleQuote(swaptionVols[k])); 00177 swaptions.push_back(boost::shared_ptr<CalibrationHelper>(new 00178 SwaptionHelper(swaptionMaturities[i], 00179 Period(swapLenghts[j], Years), 00180 Handle<Quote>(vol), 00181 indexSixMonths, 00182 indexSixMonths->tenor(), 00183 indexSixMonths->dayCounter(), 00184 indexSixMonths->dayCounter(), 00185 rhTermStructure))); 00186 swaptions.back()->addTimesTo(times); 00187 } 00188 00189 // Building time-grid 00190 TimeGrid grid(times.begin(), times.end(), 30); 00191 00192 00193 // defining the models 00194 boost::shared_ptr<G2> modelG2(new G2(rhTermStructure)); 00195 boost::shared_ptr<HullWhite> modelHW(new HullWhite(rhTermStructure)); 00196 boost::shared_ptr<HullWhite> modelHW2(new HullWhite(rhTermStructure)); 00197 boost::shared_ptr<BlackKarasinski> modelBK( 00198 new BlackKarasinski(rhTermStructure)); 00199 00200 00201 // model calibrations 00202 00203 std::cout << "G2 (analytic formulae) calibration" << std::endl; 00204 for (i=0; i<swaptions.size(); i++) 00205 swaptions[i]->setPricingEngine(boost::shared_ptr<PricingEngine>( 00206 new G2SwaptionEngine(modelG2, 6.0, 16))); 00207 00208 calibrateModel(modelG2, swaptions); 00209 std::cout << "calibrated to:\n" 00210 << "a = " << modelG2->params()[0] << ", " 00211 << "sigma = " << modelG2->params()[1] << "\n" 00212 << "b = " << modelG2->params()[2] << ", " 00213 << "eta = " << modelG2->params()[3] << "\n" 00214 << "rho = " << modelG2->params()[4] 00215 << std::endl << std::endl; 00216 00217 00218 00219 std::cout << "Hull-White (analytic formulae) calibration" << std::endl; 00220 for (i=0; i<swaptions.size(); i++) 00221 swaptions[i]->setPricingEngine(boost::shared_ptr<PricingEngine>( 00222 new JamshidianSwaptionEngine(modelHW))); 00223 00224 calibrateModel(modelHW, swaptions); 00225 std::cout << "calibrated to:\n" 00226 << "a = " << modelHW->params()[0] << ", " 00227 << "sigma = " << modelHW->params()[1] 00228 << std::endl << std::endl; 00229 00230 std::cout << "Hull-White (numerical) calibration" << std::endl; 00231 for (i=0; i<swaptions.size(); i++) 00232 swaptions[i]->setPricingEngine(boost::shared_ptr<PricingEngine>( 00233 new TreeSwaptionEngine(modelHW2,grid))); 00234 00235 calibrateModel(modelHW2, swaptions); 00236 std::cout << "calibrated to:\n" 00237 << "a = " << modelHW2->params()[0] << ", " 00238 << "sigma = " << modelHW2->params()[1] 00239 << std::endl << std::endl; 00240 00241 std::cout << "Black-Karasinski (numerical) calibration" << std::endl; 00242 for (i=0; i<swaptions.size(); i++) 00243 swaptions[i]->setPricingEngine(boost::shared_ptr<PricingEngine>( 00244 new TreeSwaptionEngine(modelBK,grid))); 00245 00246 calibrateModel(modelBK, swaptions); 00247 std::cout << "calibrated to:\n" 00248 << "a = " << modelBK->params()[0] << ", " 00249 << "sigma = " << modelBK->params()[1] 00250 << std::endl << std::endl; 00251 00252 00253 // ATM Bermudan swaption pricing 00254 00255 std::cout << "Payer bermudan swaption " 00256 << "struck at " << io::rate(fixedATMRate) 00257 << " (ATM)" << std::endl; 00258 00259 std::vector<Date> bermudanDates; 00260 const std::vector<boost::shared_ptr<CashFlow> >& leg = 00261 swap->fixedLeg(); 00262 for (i=0; i<leg.size(); i++) { 00263 boost::shared_ptr<Coupon> coupon = 00264 boost::dynamic_pointer_cast<Coupon>(leg[i]); 00265 bermudanDates.push_back(coupon->accrualStartDate()); 00266 } 00267 00268 boost::shared_ptr<Exercise> bermudanExercise( 00269 new BermudanExercise(bermudanDates)); 00270 00271 Swaption bermudanSwaption(atmSwap, bermudanExercise, rhTermStructure, 00272 boost::shared_ptr<PricingEngine>()); 00273 00274 // Do the pricing for each model 00275 00276 // G2 price the European swaption here, it should switch to bermudan 00277 bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>(new 00278 TreeSwaptionEngine(modelG2, 50))); 00279 std::cout << "G2: " << bermudanSwaption.NPV() << std::endl; 00280 00281 bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00282 new TreeSwaptionEngine(modelHW, 50))); 00283 std::cout << "HW: " << bermudanSwaption.NPV() << std::endl; 00284 00285 bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>(new 00286 TreeSwaptionEngine(modelHW2, 50))); 00287 std::cout << "HW (num): " << bermudanSwaption.NPV() << std::endl; 00288 00289 bermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>(new 00290 TreeSwaptionEngine(modelBK, 50))); 00291 std::cout << "BK: " << bermudanSwaption.NPV() << std::endl; 00292 00293 00294 // OTM Bermudan swaption pricing 00295 00296 std::cout << "Payer bermudan swaption " 00297 << "struck at " << io::rate(fixedOTMRate) 00298 << " (OTM)" << std::endl; 00299 00300 Swaption otmBermudanSwaption(otmSwap,bermudanExercise,rhTermStructure, 00301 boost::shared_ptr<PricingEngine>()); 00302 00303 // Do the pricing for each model 00304 otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00305 new TreeSwaptionEngine(modelG2, 50))); 00306 std::cout << "G2: " << otmBermudanSwaption.NPV() << std::endl; 00307 00308 otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00309 new TreeSwaptionEngine(modelHW, 50))); 00310 std::cout << "HW: " << otmBermudanSwaption.NPV() << std::endl; 00311 00312 otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00313 new TreeSwaptionEngine(modelHW2, 50))); 00314 std::cout << "HW (num): " << otmBermudanSwaption.NPV() << std::endl; 00315 00316 otmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00317 new TreeSwaptionEngine(modelBK, 50))); 00318 std::cout << "BK: " << otmBermudanSwaption.NPV() << std::endl; 00319 00320 00321 // ITM Bermudan swaption pricing 00322 00323 std::cout << "Payer bermudan swaption " 00324 << "struck at " << io::rate(fixedITMRate) 00325 << " (ITM)" << std::endl; 00326 00327 Swaption itmBermudanSwaption(itmSwap,bermudanExercise,rhTermStructure, 00328 boost::shared_ptr<PricingEngine>()); 00329 00330 // Do the pricing for each model 00331 itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00332 new TreeSwaptionEngine(modelG2, 50))); 00333 std::cout << "G2: " << itmBermudanSwaption.NPV() << std::endl; 00334 00335 itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00336 new TreeSwaptionEngine(modelHW, 50))); 00337 std::cout << "HW: " << itmBermudanSwaption.NPV() << std::endl; 00338 00339 itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00340 new TreeSwaptionEngine(modelHW2, 50))); 00341 std::cout << "HW (num): " << itmBermudanSwaption.NPV() << std::endl; 00342 00343 itmBermudanSwaption.setPricingEngine(boost::shared_ptr<PricingEngine>( 00344 new TreeSwaptionEngine(modelBK, 50))); 00345 std::cout << "BK: " << itmBermudanSwaption.NPV() << std::endl; 00346 00347 Real seconds = timer.elapsed(); 00348 Integer hours = int(seconds/3600); 00349 seconds -= hours * 3600; 00350 Integer minutes = int(seconds/60); 00351 seconds -= minutes * 60; 00352 std::cout << " \nRun completed in "; 00353 if (hours > 0) 00354 std::cout << hours << " h "; 00355 if (hours > 0 || minutes > 0) 00356 std::cout << minutes << " m "; 00357 std::cout << std::fixed << std::setprecision(0) 00358 << seconds << " s\n" << std::endl; 00359 00360 return 0; 00361 } catch (std::exception& e) { 00362 std::cout << e.what() << std::endl; 00363 return 1; 00364 } catch (...) { 00365 std::cout << "unknown error" << std::endl; 00366 return 1; 00367 } 00368 } 00369