23#include <ql/exercise.hpp>
24#include <ql/instruments/makevanillaswap.hpp>
25#include <ql/instruments/swaption.hpp>
26#include <ql/pricingengines/swap/discountingswapengine.hpp>
27#include <ql/pricingengines/swaption/blackswaptionengine.hpp>
28#include <ql/quotes/simplequote.hpp>
30#include <boost/make_shared.hpp>
39 const Date& asof,
const QuantLib::ext::shared_ptr<SwaptionVolatilityStructure>& svsIn,
40 const Handle<YieldTermStructure>& discount,
const Handle<YieldTermStructure>& shortDiscount,
41 const QuantLib::ext::shared_ptr<SwapConventions>& conventions,
const QuantLib::ext::shared_ptr<SwapConventions>& shortConventions,
42 const Period& conventionsTenor,
const Period& shortConventionsTenor,
const VolatilityType targetType,
43 const Matrix& targetShifts)
44 : asof_(asof), svsIn_(svsIn), discount_(discount), shortDiscount_(shortDiscount), conventions_(conventions),
45 shortConventions_(shortConventions), conventionsTenor_(conventionsTenor),
46 shortConventionsTenor_(shortConventionsTenor), targetType_(targetType), targetShifts_(targetShifts),
47 accuracy_(1.0e-5), maxEvaluations_(100) {
54 const QuantLib::ext::shared_ptr<SwaptionVolatilityStructure>& svsIn,
55 const QuantLib::ext::shared_ptr<SwapIndex>& swapIndex,
56 const QuantLib::ext::shared_ptr<SwapIndex>& shortSwapIndex,
57 const VolatilityType targetType,
const Matrix& targetShifts)
58 : asof_(asof), svsIn_(svsIn), discount_(swapIndex->discountingTermStructure()),
59 shortDiscount_(shortSwapIndex->discountingTermStructure()),
61 swapIndex->fixingCalendar(), swapIndex->fixedLegConvention(),
62 swapIndex->dayCounter(), swapIndex->iborIndex())),
64 shortSwapIndex->fixingDays(), shortSwapIndex->fixedLegTenor(), shortSwapIndex->fixingCalendar(),
65 shortSwapIndex->fixedLegConvention(), shortSwapIndex->dayCounter(), shortSwapIndex->iborIndex())),
66 conventionsTenor_(swapIndex->tenor()), shortConventionsTenor_(shortSwapIndex->tenor()), targetType_(targetType),
67 targetShifts_(targetShifts), accuracy_(1.0e-5), maxEvaluations_(100) {
71 discount_ = swapIndex->iborIndex()->forwardingTermStructure();
73 shortDiscount_ = shortSwapIndex->iborIndex()->forwardingTermStructure();
79 "SwaptionVolatilityConverter requires the asof date and reference date to align");
81 "SwaptionVolatilityConverter requires a valid discount curve with reference date equal to asof date");
82 Handle<YieldTermStructure> forwardCurve =
conventions_->floatIndex()->forwardingTermStructure();
83 QL_REQUIRE(!forwardCurve.empty() && forwardCurve->referenceDate() ==
asof_,
84 "SwaptionVolatilityConverter requires a valid forward curve with reference date equal to asof date");
89 QuantLib::ext::shared_ptr<SwaptionVolatilityDiscrete> svDisc;
94 vector<Real> strikeSpreads(1, 0.0);
95 QuantLib::ext::shared_ptr<SwapIndex> swapIndexBase, shortSwapIndexBase;
96 QuantLib::ext::shared_ptr<SwaptionVolatilityCube> cube;
97 if (QuantLib::ext::dynamic_pointer_cast<SwaptionVolCubeWithATM>(
svsIn_)) {
98 cube = QuantLib::ext::static_pointer_cast<SwaptionVolCubeWithATM>(
svsIn_)->cube();
100 if (QuantLib::ext::dynamic_pointer_cast<SwaptionVolatilityCube>(
svsIn_)) {
101 cube = QuantLib::ext::static_pointer_cast<SwaptionVolatilityCube>(
svsIn_);
105 strikeSpreads = cube->strikeSpreads();
106 swapIndexBase = cube->swapIndexBase();
107 shortSwapIndexBase = cube->shortSwapIndexBase();
108 }
else if (QuantLib::ext::dynamic_pointer_cast<SwaptionVolatilityDiscrete>(
svsIn_)) {
109 svDisc = QuantLib::ext::static_pointer_cast<SwaptionVolatilityDiscrete>(
svsIn_);
111 QL_FAIL(
"SwaptionVolatilityConverter: unknown input volatility structure");
115 DayCounter dayCounter = svDisc->dayCounter();
116 bool extrapolation = svDisc->allowsExtrapolation();
117 Calendar calendar = svDisc->calendar();
118 BusinessDayConvention bdc = svDisc->businessDayConvention();
120 const vector<Date>& optionDates = svDisc->optionDates();
121 const vector<Period>& optionTenors = svDisc->optionTenors();
122 const vector<Period>& swapTenors = svDisc->swapTenors();
123 const vector<Time>& optionTimes = svDisc->optionTimes();
124 const vector<Time>& swapLengths = svDisc->swapLengths();
125 Size nOptionTimes = optionTimes.size();
126 Size nSwapLengths = swapLengths.size();
127 Size nStrikeSpreads = strikeSpreads.size();
129 Real targetShift = 0.0;
134 "SwaptionVolatilityConverter: number of shift rows does not equal the number of option tenors");
136 "SwaptionVolatilityConverter: number of shift columns does not equal the number of swap tenors");
140 Matrix volatilities(nOptionTimes, nSwapLengths);
141 for (Size i = 0; i < nOptionTimes; ++i) {
142 for (Size j = 0; j < nSwapLengths; ++j) {
145 volatilities[i][j] =
convert(optionDates[i], swapTenors[j], 0.0, dayCounter,
targetType_, targetShift);
150 Handle<SwaptionVolatilityStructure> atmStructure;
151 if (calendar.empty() || optionTenors.empty()) {
153 atmStructure = Handle<SwaptionVolatilityStructure>(
154 QuantLib::ext::make_shared<SwaptionVolatilityMatrix>(
asof_, calendar, bdc, optionDates, swapTenors, volatilities,
157 atmStructure = Handle<SwaptionVolatilityStructure>(QuantLib::ext::shared_ptr<SwaptionVolatilityMatrix>(
158 new SwaptionVolatilityMatrix(
asof_, calendar, bdc, optionTenors, swapTenors, volatilities, Actual365Fixed(),
164 return *atmStructure;
168 std::vector<std::vector<Handle<Quote> > > volSpreads(nOptionTimes * nSwapLengths,
169 std::vector<Handle<Quote> >(nStrikeSpreads));
170 for (Size k = 0; k < nStrikeSpreads; ++k) {
171 for (Size i = 0; i < nOptionTimes; ++i) {
172 for (Size j = 0; j < nSwapLengths; ++j) {
176 convert(optionDates[i], swapTenors[j], strikeSpreads[k], dayCounter,
targetType_, targetShift);
177 volSpreads[i * nSwapLengths + j][k] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(outVol));
183 QuantLib::ext::shared_ptr<SwaptionVolatilityCube> cubeOut = QuantLib::ext::shared_ptr<QuantExt::SwaptionVolCube2>(
185 shortSwapIndexBase,
false,
true,
false));
186 cubeOut->enableExtrapolation(cube->allowsExtrapolation());
187 return QuantLib::ext::make_shared<SwaptionVolCubeWithATM>(cubeOut);
192 const DayCounter& volDayCounter, VolatilityType outType,
193 Real outShift)
const {
195 const QuantLib::ext::shared_ptr<SwapConventions> tmpConv =
201 Date effectiveDate = tmpConv->fixedCalendar().advance(expiry, tmpConv->settlementDays(), Days);
202 QuantLib::ext::shared_ptr<PricingEngine> engine = QuantLib::ext::make_shared<DiscountingSwapEngine>(tmpDiscount);
203 QuantLib::ext::shared_ptr<VanillaSwap> swap = MakeVanillaSwap(swapTenor, tmpConv->floatIndex())
204 .withType(strikeSpread < 0.0 ? VanillaSwap::Receiver : VanillaSwap::Payer)
205 .withEffectiveDate(effectiveDate)
206 .withFixedLegCalendar(tmpConv->fixedCalendar())
207 .withFixedLegDayCount(tmpConv->fixedDayCounter())
208 .withFixedLegTenor(tmpConv->fixedTenor())
209 .withFixedLegConvention(tmpConv->fixedConvention())
210 .withFixedLegTerminationDateConvention(tmpConv->fixedConvention())
211 .withFloatingLegSpread(0.0)
212 .withPricingEngine(engine);
214 Rate atmRate = swap->fairRate(), strike;
216 strike = atmRate + strikeSpread;
217 swap = MakeVanillaSwap(swapTenor, tmpConv->floatIndex(), strike)
218 .withEffectiveDate(effectiveDate)
219 .withFixedLegTenor(tmpConv->fixedTenor())
220 .withFixedLegDayCount(tmpConv->fixedDayCounter())
221 .withFloatingLegSpread(0.0)
222 .withPricingEngine(engine);
227 Real inShift =
svsIn_->shift(expiry, swapTenor);
228 VolatilityType inType =
svsIn_->volatilityType();
232 Real inMinStrike = inType == ShiftedLognormal ? -inShift : -QL_MAX_REAL;
233 Real outMinStrike = outType == ShiftedLognormal ? -outShift : -QL_MAX_REAL;
234 if (strike < inMinStrike || strike < outMinStrike)
237 Real inVol =
svsIn_->volatility(expiry, swapTenor, strike);
240 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiry);
241 QuantLib::ext::shared_ptr<Swaption> swaption = QuantLib::ext::make_shared<Swaption>(swap, exercise, Settlement::Physical);
244 QuantLib::ext::shared_ptr<PricingEngine> swaptionEngine;
245 if (inType == ShiftedLognormal) {
246 swaptionEngine = QuantLib::ext::make_shared<BlackSwaptionEngine>(
discount_, inVol, volDayCounter, inShift);
248 swaptionEngine = QuantLib::ext::make_shared<BachelierSwaptionEngine>(
discount_, inVol, volDayCounter);
250 swaption->setPricingEngine(swaptionEngine);
255 Real vega = swaption->result<Real>(
"vega");
259 Volatility impliedVol = 0.0;
261 Real npv = swaption->NPV();
265 if (outType == ShiftedLognormal) {
266 QL_REQUIRE(atmRate + outShift > 0.0,
"SwaptionVolatilityConverter: ATM rate + shift must be > 0.0");
267 if (inType == Normal)
268 guess = inVol / (atmRate + outShift);
270 guess = inVol * (atmRate + inShift) / (atmRate + outShift);
272 if (inType == Normal)
275 guess = inVol * (atmRate + inShift);
282 }
catch (std::exception& e) {
284 QL_FAIL(
"SwaptionVolatilityConverter: volatility conversion failed while trying to convert volatility"
286 << expiry <<
" and swap tenor " << swapTenor <<
". Error: " << e.what());
SwaptionVolatilityConverter(const Date &asof, const QuantLib::ext::shared_ptr< SwaptionVolatilityStructure > &svsIn, const Handle< YieldTermStructure > &discount, const Handle< YieldTermStructure > &shortDiscount, const QuantLib::ext::shared_ptr< SwapConventions > &conventions, const QuantLib::ext::shared_ptr< SwapConventions > &shortConventions, const Period &conventionsTenor, const Period &shortConventionsTenor, const VolatilityType targetType, const Matrix &targetShifts=Matrix())
Construct from SwapConventions.
Handle< YieldTermStructure > shortDiscount_
Handle< YieldTermStructure > discount_
const Matrix targetShifts_
const Period shortConventionsTenor_
const QuantLib::ext::shared_ptr< SwapConventions > conventions_
static const Volatility maxVol_
static const Real minVega_
QuantLib::ext::shared_ptr< SwaptionVolatilityStructure > convert() const
Method that returns the converted SwaptionVolatilityStructure
const QuantLib::ext::shared_ptr< SwaptionVolatilityStructure > svsIn_
static const Volatility minVol_
const QuantLib::ext::shared_ptr< SwapConventions > shortConventions_
const VolatilityType targetType_
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Convert swaption volatilities from one type to another.
Swaption volatility cube, fit-later-interpolate-early approach.
Wrapper class for a SwaptionVolatilityCube that easily and efficiently exposes ATM vols.