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