QuantLib: BermudanSwaption.cpp

A free/open-source library for quantitative finance Reference manual - version 1.20

BermudanSwaption.cpp

This example prices a bermudan swaption using different models calibrated to market swaptions. The calibration examples include Hull and White's using both an analytic formula as well as numerically, and Black and Karasinski's model. Using these three calibrations, Bermudan swaptions are priced for at-the-money, out-of-the-money and in-the-money volatilities.

/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <ql/qldefines.hpp>
#ifdef BOOST_MSVC
# include <ql/auto_link.hpp>
#endif
#include <ql/instruments/swaption.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
#include <ql/pricingengines/swaption/treeswaptionengine.hpp>
#include <ql/pricingengines/swaption/jamshidianswaptionengine.hpp>
#include <ql/pricingengines/swaption/g2swaptionengine.hpp>
#include <ql/pricingengines/swaption/fdhullwhiteswaptionengine.hpp>
#include <ql/pricingengines/swaption/fdg2swaptionengine.hpp>
#include <ql/models/shortrate/calibrationhelpers/swaptionhelper.hpp>
#include <ql/models/shortrate/onefactormodels/blackkarasinski.hpp>
#include <ql/math/optimization/levenbergmarquardt.hpp>
#include <ql/indexes/ibor/euribor.hpp>
#include <ql/cashflows/coupon.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <ql/utilities/dataformatters.hpp>
#include <iostream>
#include <iomanip>
using namespace QuantLib;
#if defined(QL_ENABLE_SESSIONS)
namespace QuantLib {
ThreadKey sessionId() { return 0; }
}
#endif
//Number of swaptions to be calibrated to...
Size numRows = 5;
Size numCols = 5;
Integer swapLengths[] = {
1, 2, 3, 4, 5};
Volatility swaptionVols[] = {
0.1490, 0.1340, 0.1228, 0.1189, 0.1148,
0.1290, 0.1201, 0.1146, 0.1108, 0.1040,
0.1149, 0.1112, 0.1070, 0.1010, 0.0957,
0.1047, 0.1021, 0.0980, 0.0951, 0.1270,
0.1000, 0.0950, 0.0900, 0.1230, 0.1160};
void calibrateModel(
const ext::shared_ptr<ShortRateModel>& model,
const std::vector<ext::shared_ptr<BlackCalibrationHelper> >& swaptions) {
std::vector<ext::shared_ptr<CalibrationHelper> > helpers(swaptions.begin(), swaptions.end());
LevenbergMarquardt om;
model->calibrate(helpers, om,
EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8));
// Output the implied Black volatilities
for (Size i=0; i<numRows; i++) {
Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1
Size k = i*numCols + j;
Real npv = swaptions[i]->modelValue();
Volatility implied = swaptions[i]->impliedVolatility(npv, 1e-4,
1000, 0.05, 0.50);
Volatility diff = implied - swaptionVols[k];
std::cout << i+1 << "x" << swapLengths[j]
<< std::setprecision(5) << std::noshowpos
<< ": model " << std::setw(7) << io::volatility(implied)
<< ", market " << std::setw(7)
<< io::volatility(swaptionVols[k])
<< " (" << std::setw(7) << std::showpos
<< io::volatility(diff) << std::noshowpos << ")\n";
}
}
int main(int, char* []) {
try {
std::cout << std::endl;
Date todaysDate(15, February, 2002);
Calendar calendar = TARGET();
Date settlementDate(19, February, 2002);
Settings::instance().evaluationDate() = todaysDate;
// flat yield term structure impling 1x5 swap at 5%
ext::shared_ptr<Quote> flatRate(new SimpleQuote(0.04875825));
Handle<YieldTermStructure> rhTermStructure(
ext::make_shared<FlatForward>(
settlementDate, Handle<Quote>(flatRate),
Actual365Fixed()));
// Define the ATM/OTM/ITM swaps
Frequency fixedLegFrequency = Annual;
BusinessDayConvention fixedLegConvention = Unadjusted;
BusinessDayConvention floatingLegConvention = ModifiedFollowing;
DayCounter fixedLegDayCounter = Thirty360(Thirty360::European);
Frequency floatingLegFrequency = Semiannual;
VanillaSwap::Type type = VanillaSwap::Payer;
Rate dummyFixedRate = 0.03;
ext::shared_ptr<IborIndex> indexSixMonths(new
Euribor6M(rhTermStructure));
Date startDate = calendar. advance(settlementDate,1,Years,
floatingLegConvention);
Date maturity = calendar.advance(startDate,5,Years,
floatingLegConvention);
Schedule fixedSchedule(startDate,maturity, Period(fixedLegFrequency),
calendar,fixedLegConvention,fixedLegConvention,
DateGeneration::Forward,false);
Schedule floatSchedule(startDate,maturity,Period(floatingLegFrequency),
calendar,floatingLegConvention,floatingLegConvention,
DateGeneration::Forward,false);
ext::shared_ptr<VanillaSwap> swap(new VanillaSwap(
type, 1000.0,
fixedSchedule, dummyFixedRate, fixedLegDayCounter,
floatSchedule, indexSixMonths, 0.0,
indexSixMonths->dayCounter()));
swap->setPricingEngine(ext::shared_ptr<PricingEngine>(
new DiscountingSwapEngine(rhTermStructure)));
Rate fixedATMRate = swap->fairRate();
Rate fixedOTMRate = fixedATMRate * 1.2;
Rate fixedITMRate = fixedATMRate * 0.8;
ext::shared_ptr<VanillaSwap> atmSwap(new VanillaSwap(
type, 1000.0,
fixedSchedule, fixedATMRate, fixedLegDayCounter,
floatSchedule, indexSixMonths, 0.0,
indexSixMonths->dayCounter()));
ext::shared_ptr<VanillaSwap> otmSwap(new VanillaSwap(
type, 1000.0,
fixedSchedule, fixedOTMRate, fixedLegDayCounter,
floatSchedule, indexSixMonths, 0.0,
indexSixMonths->dayCounter()));
ext::shared_ptr<VanillaSwap> itmSwap(new VanillaSwap(
type, 1000.0,
fixedSchedule, fixedITMRate, fixedLegDayCounter,
floatSchedule, indexSixMonths, 0.0,
indexSixMonths->dayCounter()));
// defining the swaptions to be used in model calibration
std::vector<Period> swaptionMaturities;
swaptionMaturities.push_back(Period(1, Years));
swaptionMaturities.push_back(Period(2, Years));
swaptionMaturities.push_back(Period(3, Years));
swaptionMaturities.push_back(Period(4, Years));
swaptionMaturities.push_back(Period(5, Years));
std::vector<ext::shared_ptr<BlackCalibrationHelper> > swaptions;
// List of times that have to be included in the timegrid
std::list<Time> times;
Size i;
for (i=0; i<numRows; i++) {
Size j = numCols - i -1; // 1x5, 2x4, 3x3, 4x2, 5x1
Size k = i*numCols + j;
ext::shared_ptr<Quote> vol(new SimpleQuote(swaptionVols[k]));
swaptions.push_back(ext::shared_ptr<BlackCalibrationHelper>(new
SwaptionHelper(swaptionMaturities[i],
Period(swapLengths[j], Years),
Handle<Quote>(vol),
indexSixMonths,
indexSixMonths->tenor(),
indexSixMonths->dayCounter(),
indexSixMonths->dayCounter(),
rhTermStructure)));
swaptions.back()->addTimesTo(times);
}
// Building time-grid
TimeGrid grid(times.begin(), times.end(), 30);
// defining the models
ext::shared_ptr<G2> modelG2(new G2(rhTermStructure));
ext::shared_ptr<HullWhite> modelHW(new HullWhite(rhTermStructure));
ext::shared_ptr<HullWhite> modelHW2(new HullWhite(rhTermStructure));
ext::shared_ptr<BlackKarasinski> modelBK(
new BlackKarasinski(rhTermStructure));
// model calibrations
std::cout << "G2 (analytic formulae) calibration" << std::endl;
for (i=0; i<swaptions.size(); i++)
swaptions[i]->setPricingEngine(ext::shared_ptr<PricingEngine>(
new G2SwaptionEngine(modelG2, 6.0, 16)));
calibrateModel(modelG2, swaptions);
std::cout << "calibrated to:\n"
<< "a = " << modelG2->params()[0] << ", "
<< "sigma = " << modelG2->params()[1] << "\n"
<< "b = " << modelG2->params()[2] << ", "
<< "eta = " << modelG2->params()[3] << "\n"
<< "rho = " << modelG2->params()[4]
<< std::endl << std::endl;
std::cout << "Hull-White (analytic formulae) calibration" << std::endl;
for (i=0; i<swaptions.size(); i++)
swaptions[i]->setPricingEngine(ext::shared_ptr<PricingEngine>(
new JamshidianSwaptionEngine(modelHW)));
calibrateModel(modelHW, swaptions);
std::cout << "calibrated to:\n"
<< "a = " << modelHW->params()[0] << ", "
<< "sigma = " << modelHW->params()[1]
<< std::endl << std::endl;
std::cout << "Hull-White (numerical) calibration" << std::endl;
for (i=0; i<swaptions.size(); i++)
swaptions[i]->setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelHW2, grid)));
calibrateModel(modelHW2, swaptions);
std::cout << "calibrated to:\n"
<< "a = " << modelHW2->params()[0] << ", "
<< "sigma = " << modelHW2->params()[1]
<< std::endl << std::endl;
std::cout << "Black-Karasinski (numerical) calibration" << std::endl;
for (i=0; i<swaptions.size(); i++)
swaptions[i]->setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelBK, grid)));
calibrateModel(modelBK, swaptions);
std::cout << "calibrated to:\n"
<< "a = " << modelBK->params()[0] << ", "
<< "sigma = " << modelBK->params()[1]
<< std::endl << std::endl;
// ATM Bermudan swaption pricing
std::cout << "Payer bermudan swaption "
<< "struck at " << io::rate(fixedATMRate)
<< " (ATM)" << std::endl;
std::vector<Date> bermudanDates;
const std::vector<ext::shared_ptr<CashFlow> >& leg =
swap->fixedLeg();
for (i=0; i<leg.size(); i++) {
ext::shared_ptr<Coupon> coupon =
ext::dynamic_pointer_cast<Coupon>(leg[i]);
bermudanDates.push_back(coupon->accrualStartDate());
}
ext::shared_ptr<Exercise> bermudanExercise(
new BermudanExercise(bermudanDates));
Swaption bermudanSwaption(atmSwap, bermudanExercise);
// Do the pricing for each model
// G2 price the European swaption here, it should switch to bermudan
bermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelG2, 50)));
std::cout << "G2 (tree): " << bermudanSwaption.NPV() << std::endl;
bermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdG2SwaptionEngine(modelG2)));
std::cout << "G2 (fdm) : " << bermudanSwaption.NPV() << std::endl;
bermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelHW, 50)));
std::cout << "HW (tree): " << bermudanSwaption.NPV() << std::endl;
bermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdHullWhiteSwaptionEngine(modelHW)));
std::cout << "HW (fdm) : " << bermudanSwaption.NPV() << std::endl;
bermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelHW2, 50)));
std::cout << "HW (num, tree): " << bermudanSwaption.NPV() << std::endl;
bermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdHullWhiteSwaptionEngine(modelHW2)));
std::cout << "HW (num, fdm) : " << bermudanSwaption.NPV() << std::endl;
bermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelBK, 50)));
std::cout << "BK: " << bermudanSwaption.NPV() << std::endl;
// OTM Bermudan swaption pricing
std::cout << "Payer bermudan swaption "
<< "struck at " << io::rate(fixedOTMRate)
<< " (OTM)" << std::endl;
Swaption otmBermudanSwaption(otmSwap,bermudanExercise);
// Do the pricing for each model
otmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelG2, 300)));
std::cout << "G2 (tree): " << otmBermudanSwaption.NPV()
<< std::endl;
otmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdG2SwaptionEngine(modelG2)));
std::cout << "G2 (fdm) : " << otmBermudanSwaption.NPV()
<< std::endl;
otmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelHW, 50)));
std::cout << "HW (tree): " << otmBermudanSwaption.NPV()
<< std::endl;
otmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdHullWhiteSwaptionEngine(modelHW)));
std::cout << "HW (fdm) : " << otmBermudanSwaption.NPV()
<< std::endl;
otmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelHW2, 50)));
std::cout << "HW (num, tree): " << otmBermudanSwaption.NPV()
<< std::endl;
otmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdHullWhiteSwaptionEngine(modelHW2)));
std::cout << "HW (num, fdm): " << otmBermudanSwaption.NPV()
<< std::endl;
otmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelBK, 50)));
std::cout << "BK: " << otmBermudanSwaption.NPV()
<< std::endl;
// ITM Bermudan swaption pricing
std::cout << "Payer bermudan swaption "
<< "struck at " << io::rate(fixedITMRate)
<< " (ITM)" << std::endl;
Swaption itmBermudanSwaption(itmSwap,bermudanExercise);
// Do the pricing for each model
itmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelG2, 50)));
std::cout << "G2 (tree): " << itmBermudanSwaption.NPV()
<< std::endl;
itmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdG2SwaptionEngine(modelG2)));
std::cout << "G2 (fdm) : " << itmBermudanSwaption.NPV()
<< std::endl;
itmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelHW, 50)));
std::cout << "HW (tree): " << itmBermudanSwaption.NPV()
<< std::endl;
itmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdHullWhiteSwaptionEngine(modelHW)));
std::cout << "HW (fdm) : " << itmBermudanSwaption.NPV()
<< std::endl;
itmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelHW2, 50)));
std::cout << "HW (num, tree): " << itmBermudanSwaption.NPV()
<< std::endl;
itmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new FdHullWhiteSwaptionEngine(modelHW2)));
std::cout << "HW (num, fdm) : " << itmBermudanSwaption.NPV()
<< std::endl;
itmBermudanSwaption.setPricingEngine(ext::shared_ptr<PricingEngine>(
new TreeSwaptionEngine(modelBK, 50)));
std::cout << "BK: " << itmBermudanSwaption.NPV()
<< std::endl;
return 0;
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
return 1;
} catch (...) {
std::cerr << "unknown error" << std::endl;
return 1;
}
}