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