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