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