Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
yoyinflationoptionletvolstripper.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
20
21#include <ql/experimental/inflation/interpolatedyoyoptionletstripper.hpp>
22#include <ql/instruments/makeyoyinflationcapfloor.hpp>
23#include <ql/math/interpolations/bilinearinterpolation.hpp>
24#include <ql/math/interpolations/linearinterpolation.hpp>
27
28#include <boost/make_shared.hpp>
29
30using namespace QuantLib;
31using QuantLib::ext::shared_ptr;
32
33namespace QuantExt {
34
36 const QuantLib::ext::shared_ptr<CapFloorTermVolSurface>& volSurface, const QuantLib::ext::shared_ptr<YoYInflationIndex>& index,
37 const Handle<YieldTermStructure>& nominalTs, VolatilityType type, Real displacement)
38 : volSurface_(volSurface), yoyIndex_(index), nominalTs_(nominalTs), type_(type), displacement_(displacement) {
39
41}
42
44
45 Calendar cal = yoyIndex_->yoyInflationTermStructure()->calendar();
46 Period obsLag = yoyIndex_->yoyInflationTermStructure()->observationLag();
47 Size settDays = volSurface_->settlementDays();
48 DayCounter dc = yoyIndex_->yoyInflationTermStructure()->dayCounter();
49 BusinessDayConvention bdc = volSurface_->businessDayConvention();
50
51 Frequency frequency = yoyIndex_->frequency();
52
53 std::vector<Rate> strikes = volSurface_->strikes();
54 std::vector<Period> terms = volSurface_->optionTenors();
55 std::vector<Time> times = volSurface_->optionTimes();
56
57 std::vector<Period> optionletTerms;
58 optionletTerms.push_back(terms.front());
59 while (optionletTerms.back() != terms.back()) {
60 optionletTerms.push_back(optionletTerms.back() + Period(1, Years));
61 }
62
63 Matrix cPrice(strikes.size(), strikes.size() == 0 ? 0 : optionletTerms.size(), Null<Real>()),
64 fPrice(strikes.size(), strikes.size() == 0 ? 0 : optionletTerms.size(), Null<Real>());
65
66 // populate cPrice
67 for (Size i = 0; i < optionletTerms.size(); i++) {
68 for (Size j = 0; j < strikes.size(); j++) {
69 Time t = volSurface_->timeFromReference(volSurface_->optionDateFromTenor(optionletTerms[i]));
70
71 Real vol = volSurface_->volatility(t, strikes[j]);
72 QuantLib::ext::shared_ptr<ConstantYoYOptionletVolatility> ovs(
73 new ConstantYoYOptionletVolatility(vol, settDays, cal, bdc, dc, obsLag, frequency, false, -1.0, 3.0));
74 QuantLib::ext::shared_ptr<PricingEngine> pe;
75 Handle<QuantLib::YoYOptionletVolatilitySurface> hovs(ovs);
76 if (type_ == ShiftedLognormal) {
77 if (displacement_ == 0.0) {
78 pe = QuantLib::ext::make_shared<YoYInflationBlackCapFloorEngine>(yoyIndex_, hovs, nominalTs_);
79 } else {
80 pe = QuantLib::ext::make_shared<YoYInflationUnitDisplacedBlackCapFloorEngine>(yoyIndex_, hovs, nominalTs_);
81 }
82 } else if (type_ == Normal) {
83 pe = QuantLib::ext::make_shared<YoYInflationBachelierCapFloorEngine>(yoyIndex_, hovs, nominalTs_);
84 } else {
85 QL_FAIL("unknown volatility type: " << type_);
86 }
87 // calculate the cap price
88 YoYInflationCapFloor cap = YoYInflationCapFloor(
89 MakeYoYInflationCapFloor(YoYInflationCapFloor::Cap, yoyIndex_, optionletTerms[i].length(), cal, obsLag)
90 .withStrike(strikes[j])
91 .withPricingEngine(pe)
92 .withNominal(10000));
93 cPrice[j][i] = cap.NPV();
94 // floor price
95 YoYInflationCapFloor floor =
96 YoYInflationCapFloor(MakeYoYInflationCapFloor(YoYInflationCapFloor::Floor, yoyIndex_,
97 optionletTerms[i].length(), cal, obsLag)
98 .withStrike(strikes[j])
99 .withPricingEngine(pe)
100 .withNominal(10000));
101 fPrice[j][i] = floor.NPV();
102 }
103 }
104
105 // switch between floors and caps using the last option maturity, but keep one floor and one cap strike at least
106 // this is the best we can do to use OTM instruments with the original QL yoy vol bootstrapper
107 int jCritical = 0;
108 while (jCritical < static_cast<int>(strikes.size()) &&
109 fPrice[jCritical][optionletTerms.size() - 1] < cPrice[jCritical][optionletTerms.size() - 1])
110 ++jCritical;
111 int numberOfFloors = std::max(1, jCritical - 1);
112 int numberOfCaps = std::max(1, static_cast<int>(strikes.size()) - jCritical + 1);
113 Matrix cPriceFinal(numberOfCaps, strikes.size() == 0 ? 0 : optionletTerms.size());
114 Matrix fPriceFinal(numberOfFloors, strikes.size() == 0 ? 0 : optionletTerms.size());
115 std::vector<Real> fStrikes, cStrikes;
116 for (int j = 0; j < numberOfCaps; ++j) {
117 for (int i = 0; i < static_cast<int>(optionletTerms.size()); ++i) {
118 cPriceFinal(j, i) = cPrice[strikes.size() - numberOfCaps + j][i];
119 }
120 cStrikes.push_back(strikes[strikes.size() - numberOfCaps + j]);
121 }
122 for (int j = 0; j < numberOfFloors; ++j) {
123 for (int i = 0; i < static_cast<int>(optionletTerms.size()); ++i) {
124 fPriceFinal(j, i) = fPrice[j][i];
125 }
126 fStrikes.push_back(strikes[j]);
127 }
128
129 Rate baseRate = yoyIndex_->yoyInflationTermStructure()->baseRate();
131 nominalTs_, dc, cal, bdc, cStrikes, fStrikes,
132 optionletTerms, cPriceFinal, fPriceFinal);
133
134 QuantLib::ext::shared_ptr<QuantExt::InterpolatedYoYCapFloorTermPriceSurface<Bilinear, Linear>> yoySurface =
135 QuantLib::ext::make_shared<QuantExt::InterpolatedYoYCapFloorTermPriceSurface<Bilinear, Linear>>(ys);
136 yoySurface->enableExtrapolation();
137
138 QuantLib::ext::shared_ptr<InterpolatedYoYOptionletStripper<Linear>> yoyStripper =
139 QuantLib::ext::make_shared<InterpolatedYoYOptionletStripper<Linear>>();
140
141 // Create an empty volatility surface to pass to the engine
142 QuantLib::ext::shared_ptr<QuantLib::YoYOptionletVolatilitySurface> ovs =
143 QuantLib::ext::dynamic_pointer_cast<QuantLib::YoYOptionletVolatilitySurface>(
144 QuantLib::ext::make_shared<QuantLib::ConstantYoYOptionletVolatility>(0.0, settDays, cal, bdc, dc, obsLag, frequency,
145 yoySurface->indexIsInterpolated()));
146 Handle<QuantLib::YoYOptionletVolatilitySurface> hovs(ovs);
147
148 QuantLib::ext::shared_ptr<YoYInflationBachelierCapFloorEngine> cfEngine =
149 QuantLib::ext::make_shared<YoYInflationBachelierCapFloorEngine>(yoyIndex_, hovs, nominalTs_);
150
151 yoyOptionletVolSurface_ = QuantLib::ext::make_shared<QuantExt::KInterpolatedYoYOptionletVolatilitySurface<Linear>>(
152 settDays, cal, bdc, dc, obsLag, yoySurface, cfEngine, yoyStripper, 0, Linear(), type_, displacement_);
153 yoyOptionletVolSurface_->enableExtrapolation();
154}
155
156} // namespace QuantExt
Interpolated YoY Inflation Cap floor term price surface.
QuantLib::ext::shared_ptr< QuantLib::CapFloorTermVolSurface > volSurface_
QuantLib::ext::shared_ptr< QuantExt::YoYOptionletVolatilitySurface > yoyOptionletVolSurface_
QuantLib::ext::shared_ptr< YoYInflationIndex > yoyIndex_
YoYInflationOptionletVolStripper(const QuantLib::ext::shared_ptr< QuantLib::CapFloorTermVolSurface > &volSurface, const QuantLib::ext::shared_ptr< YoYInflationIndex > &index, const Handle< YieldTermStructure > &nominalTs, VolatilityType type=ShiftedLognormal, Real displacement=0.0)
Interpolated YoY Inflation Cap floor term price surface - extends QuantLib InterpolatedYoYCapFloorTer...
fixed version of ql class (see patch 1,2,3 in the comments below)
vector< Real > strikes
YoY Inflation Optionlet (caplet/floorlet) volatility strippers.