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