QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
vannavolgabarrierengine.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2013 Yue Tian
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <ql/experimental/barrieroption/vannavolgabarrierengine.hpp>
21#include <ql/experimental/barrieroption/vannavolgainterpolation.hpp>
22#include <ql/experimental/fx/blackdeltacalculator.hpp>
23#include <ql/math/matrix.hpp>
24#include <ql/pricingengines/barrier/analyticbarrierengine.hpp>
25#include <ql/pricingengines/blackformula.hpp>
26#include <ql/quotes/simplequote.hpp>
27#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
28#include <ql/time/calendars/nullcalendar.hpp>
29#include <utility>
30
31using std::pow;
32using std::log;
33using std::sqrt;
34
35namespace QuantLib {
36
38 Handle<DeltaVolQuote> vol25Put,
39 Handle<DeltaVolQuote> vol25Call,
40 Handle<Quote> spotFX,
43 const bool adaptVanDelta,
44 const Real bsPriceWithSmile)
45 : atmVol_(std::move(atmVol)), vol25Put_(std::move(vol25Put)), vol25Call_(std::move(vol25Call)),
46 T_(atmVol_->maturity()), spotFX_(std::move(spotFX)), domesticTS_(std::move(domesticTS)),
47 foreignTS_(std::move(foreignTS)), adaptVanDelta_(adaptVanDelta),
48 bsPriceWithSmile_(bsPriceWithSmile) {
49 QL_REQUIRE(vol25Put_->delta() == -0.25, "25 delta put is required by vanna volga method");
50 QL_REQUIRE(vol25Call_->delta() == 0.25, "25 delta call is required by vanna volga method");
51
52 QL_REQUIRE(vol25Put_->maturity() == vol25Call_->maturity() &&
53 vol25Put_->maturity() == atmVol_->maturity(),
54 "Maturity of 3 vols are not the same");
55
56 QL_REQUIRE(!domesticTS_.empty(), "domestic yield curve is not defined");
57 QL_REQUIRE(!foreignTS_.empty(), "foreign yield curve is not defined");
58
65 }
66
68
71 "Invalid barrier type");
72
73 const Real sigmaShift_vega = 0.0001;
74 const Real sigmaShift_volga = 0.0001;
75 const Real spotShift_delta = 0.0001 * spotFX_->value();
76 const Real sigmaShift_vanna = 0.0001;
77
78 Handle<Quote> x0Quote(
79 ext::make_shared<SimpleQuote>(spotFX_->value())); //used for shift
80 Handle<Quote> atmVolQuote(
81 ext::make_shared<SimpleQuote>(atmVol_->value())); //used for shift
82
83 ext::shared_ptr<BlackVolTermStructure> blackVolTS =
84 ext::make_shared<BlackConstantVol>(
85 Settings::instance().evaluationDate(),
86 NullCalendar(), atmVolQuote, Actual365Fixed());
87 ext::shared_ptr<BlackScholesMertonProcess> stochProcess =
88 ext::make_shared<BlackScholesMertonProcess>(
89 x0Quote,
93
94 ext::shared_ptr<PricingEngine> engineBS =
95 ext::make_shared<AnalyticBarrierEngine>(stochProcess);
96
97 BlackDeltaCalculator blackDeltaCalculatorAtm(
98 Option::Call, atmVol_->deltaType(), x0Quote->value(),
99 domesticTS_->discount(T_), foreignTS_->discount(T_),
100 atmVol_->value() * sqrt(T_));
101 Real atmStrike = blackDeltaCalculatorAtm.atmStrike(atmVol_->atmType());
102
103 Real call25Vol = vol25Call_->value();
104 Real put25Vol = vol25Put_->value();
105
106 BlackDeltaCalculator blackDeltaCalculatorPut25(Option::Put, vol25Put_->deltaType(), x0Quote->value(),
107 domesticTS_->discount(T_), foreignTS_->discount(T_),
108 put25Vol * sqrt(T_));
109 Real put25Strike = blackDeltaCalculatorPut25.strikeFromDelta(-0.25);
110 BlackDeltaCalculator blackDeltaCalculatorCall25(Option::Call, vol25Call_->deltaType(), x0Quote->value(),
111 domesticTS_->discount(T_), foreignTS_->discount(T_),
112 call25Vol * sqrt(T_));
113 Real call25Strike = blackDeltaCalculatorCall25.strikeFromDelta(0.25);
114
115
116 //here use vanna volga interpolated smile to price vanilla
117 std::vector<Real> strikes;
118 std::vector<Real> vols;
119 strikes.push_back(put25Strike);
120 vols.push_back(put25Vol);
121 strikes.push_back(atmStrike);
122 vols.push_back(atmVol_->value());
123 strikes.push_back(call25Strike);
124 vols.push_back(call25Vol);
125 VannaVolga vannaVolga(x0Quote->value(), domesticTS_->discount(T_), foreignTS_->discount(T_), T_);
126 Interpolation interpolation = vannaVolga.interpolate(strikes.begin(), strikes.end(), vols.begin());
127 interpolation.enableExtrapolation();
128 const ext::shared_ptr<StrikedTypePayoff> payoff =
129 ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
130 Real strikeVol = interpolation(payoff->strike());
131
132 //vanilla option price
133 Real forward = x0Quote->value() * foreignTS_->discount(T_) / domesticTS_->discount(T_);
134 Real vanillaOption = blackFormula(payoff->optionType(), payoff->strike(),
135 forward,
136 strikeVol * sqrt(T_),
137 domesticTS_->discount(T_));
138 results_.additionalResults["Forward"] = forward;
139 results_.additionalResults["StrikeVol"] = strikeVol;
140
141 //spot > barrier up&out 0
142 if(x0Quote->value() >= arguments_.barrier && arguments_.barrierType == Barrier::UpOut){
143 results_.value = 0.0;
144 results_.additionalResults["VanillaPrice"] = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
145 results_.additionalResults["BarrierInPrice"] = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
146 results_.additionalResults["BarrierOutPrice"] = Real(0.0);
147 }
148 //spot > barrier up&in vanilla
149 else if(x0Quote->value() >= arguments_.barrier && arguments_.barrierType == Barrier::UpIn){
151 results_.additionalResults["VanillaPrice"] = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
152 results_.additionalResults["BarrierInPrice"] = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
153 results_.additionalResults["BarrierOutPrice"] = Real(0.0);
154 }
155 //spot < barrier down&out 0
156 else if(x0Quote->value() <= arguments_.barrier && arguments_.barrierType == Barrier::DownOut){
157 results_.value = 0.0;
158 results_.additionalResults["VanillaPrice"] = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
159 results_.additionalResults["BarrierInPrice"] = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
160 results_.additionalResults["BarrierOutPrice"] = Real(0.0);
161 }
162 //spot < barrier down&in vanilla
163 else if(x0Quote->value() <= arguments_.barrier && arguments_.barrierType == Barrier::DownIn){
165 results_.additionalResults["VanillaPrice"] = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
166 results_.additionalResults["BarrierInPrice"] = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
167 results_.additionalResults["BarrierOutPrice"] = Real(0.0);
168 }
169 else{
170
171 //set up BS barrier option pricing
172 //only calculate out barrier option price
173 // in barrier price = vanilla - out barrier
174 Barrier::Type barrierType;
176 barrierType = arguments_.barrierType;
178 barrierType = Barrier::UpOut;
180 barrierType = arguments_.barrierType;
181 else
182 barrierType = Barrier::DownOut;
183
184 BarrierOption barrierOption(barrierType,
187 ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff),
188 arguments_.exercise);
189
190 barrierOption.setPricingEngine(engineBS);
191
192 //BS price with atm vol
193 Real priceBS = barrierOption.NPV();
194
195 Real priceAtmCallBS = blackFormula(Option::Call,atmStrike,
196 forward,
197 atmVol_->value() * sqrt(T_),
198 domesticTS_->discount(T_));
199 Real price25CallBS = blackFormula(Option::Call,call25Strike,
200 forward,
201 atmVol_->value() * sqrt(T_),
202 domesticTS_->discount(T_));
203 Real price25PutBS = blackFormula(Option::Put,put25Strike,
204 forward,
205 atmVol_->value() * sqrt(T_),
206 domesticTS_->discount(T_));
207
208 //market price
209 Real priceAtmCallMkt = blackFormula(Option::Call,atmStrike,
210 forward,
211 atmVol_->value() * sqrt(T_),
212 domesticTS_->discount(T_));
213
214 Real price25CallMkt = blackFormula(Option::Call,call25Strike,
215 forward,
216 call25Vol * sqrt(T_),
217 domesticTS_->discount(T_));
218 Real price25PutMkt = blackFormula(Option::Put,put25Strike,
219 forward,
220 put25Vol * sqrt(T_),
221 domesticTS_->discount(T_));
222
223
224 //Analytical Black Scholes formula for vanilla option
226 Real d1atm = (std::log(forward/atmStrike)
227 + 0.5*std::pow(atmVolQuote->value(),2.0) * T_)/(atmVolQuote->value() * sqrt(T_));
228 Real vegaAtm_Analytical = x0Quote->value() * norm(d1atm) * sqrt(T_) * foreignTS_->discount(T_);
229 Real vannaAtm_Analytical = vegaAtm_Analytical/x0Quote->value() *(1.0 - d1atm/(atmVolQuote->value()*sqrt(T_)));
230 Real volgaAtm_Analytical = vegaAtm_Analytical * d1atm * (d1atm - atmVolQuote->value() * sqrt(T_))/atmVolQuote->value();
231
232 Real d125call = (std::log(forward/call25Strike)
233 + 0.5*std::pow(atmVolQuote->value(),2.0) * T_)/(atmVolQuote->value() * sqrt(T_));
234 Real vega25Call_Analytical = x0Quote->value() * norm(d125call) * sqrt(T_) * foreignTS_->discount(T_);
235 Real vanna25Call_Analytical = vega25Call_Analytical/x0Quote->value() *(1.0 - d125call/(atmVolQuote->value()*sqrt(T_)));
236 Real volga25Call_Analytical = vega25Call_Analytical * d125call * (d125call - atmVolQuote->value() * sqrt(T_))/atmVolQuote->value();
237
238 Real d125Put = (std::log(forward/put25Strike)
239 + 0.5*std::pow(atmVolQuote->value(),2.0) * T_)/(atmVolQuote->value() * sqrt(T_));
240 Real vega25Put_Analytical = x0Quote->value() * norm(d125Put) * sqrt(T_) * foreignTS_->discount(T_);
241 Real vanna25Put_Analytical = vega25Put_Analytical/x0Quote->value() *(1.0 - d125Put/(atmVolQuote->value()*sqrt(T_)));
242 Real volga25Put_Analytical = vega25Put_Analytical * d125Put * (d125Put - atmVolQuote->value() * sqrt(T_))/atmVolQuote->value();
243
244
245 //BS vega
246 ext::static_pointer_cast<SimpleQuote> (atmVolQuote.currentLink())->setValue(atmVolQuote->value() + sigmaShift_vega);
247 barrierOption.recalculate();
248 Real vegaBarBS = (barrierOption.NPV() - priceBS)/sigmaShift_vega;
249
250 ext::static_pointer_cast<SimpleQuote> (atmVolQuote.currentLink())->setValue(atmVolQuote->value() - sigmaShift_vega);//setback
251
252 //BS volga
253
254 //vegaBar2
255 //base NPV
256 ext::static_pointer_cast<SimpleQuote> (atmVolQuote.currentLink())->setValue(atmVolQuote->value() + sigmaShift_volga);
257 barrierOption.recalculate();
258 Real priceBS2 = barrierOption.NPV();
259
260 //shifted npv
261 ext::static_pointer_cast<SimpleQuote> (atmVolQuote.currentLink())->setValue(atmVolQuote->value() + sigmaShift_vega);
262 barrierOption.recalculate();
263 Real vegaBarBS2 = (barrierOption.NPV() - priceBS2)/sigmaShift_vega;
264 Real volgaBarBS = (vegaBarBS2 - vegaBarBS)/sigmaShift_volga;
265
266 ext::static_pointer_cast<SimpleQuote> (atmVolQuote.currentLink())->setValue(atmVolQuote->value()
267 - sigmaShift_volga
268 - sigmaShift_vega);//setback
269
270 //BS Delta
271 //base delta
272 ext::static_pointer_cast<SimpleQuote> (x0Quote.currentLink())->setValue(x0Quote->value() + spotShift_delta);//shift forth
273 barrierOption.recalculate();
274 Real priceBS_delta1 = barrierOption.NPV();
275
276 ext::static_pointer_cast<SimpleQuote> (x0Quote.currentLink())->setValue(x0Quote->value() - 2 * spotShift_delta);//shift back
277 barrierOption.recalculate();
278 Real priceBS_delta2 = barrierOption.NPV();
279
280 ext::static_pointer_cast<SimpleQuote> (x0Quote.currentLink())->setValue(x0Quote->value() + spotShift_delta);//set back
281 Real deltaBar1 = (priceBS_delta1 - priceBS_delta2)/(2.0*spotShift_delta);
282
283 //shifted delta
284 ext::static_pointer_cast<SimpleQuote> (atmVolQuote.currentLink())->setValue(atmVolQuote->value() + sigmaShift_vanna);//shift sigma
285 ext::static_pointer_cast<SimpleQuote> (x0Quote.currentLink())->setValue(x0Quote->value() + spotShift_delta);//shift forth
286 barrierOption.recalculate();
287 priceBS_delta1 = barrierOption.NPV();
288
289 ext::static_pointer_cast<SimpleQuote> (x0Quote.currentLink())->setValue(x0Quote->value() - 2 * spotShift_delta);//shift back
290 barrierOption.recalculate();
291 priceBS_delta2 = barrierOption.NPV();
292
293 ext::static_pointer_cast<SimpleQuote> (x0Quote.currentLink())->setValue(x0Quote->value() + spotShift_delta);//set back
294 Real deltaBar2 = (priceBS_delta1 - priceBS_delta2)/(2.0*spotShift_delta);
295
296 Real vannaBarBS = (deltaBar2 - deltaBar1)/sigmaShift_vanna;
297
298 ext::static_pointer_cast<SimpleQuote> (atmVolQuote.currentLink())->setValue(atmVolQuote->value() - sigmaShift_vanna);//set back
299
300 //Matrix
301 Matrix A(3,3,0.0);
302
303 //analytical
304 A[0][0] = vegaAtm_Analytical;
305 A[0][1] = vega25Call_Analytical;
306 A[0][2] = vega25Put_Analytical;
307 A[1][0] = vannaAtm_Analytical;
308 A[1][1] = vanna25Call_Analytical;
309 A[1][2] = vanna25Put_Analytical;
310 A[2][0] = volgaAtm_Analytical;
311 A[2][1] = volga25Call_Analytical;
312 A[2][2] = volga25Put_Analytical;
313
314 Array b(3,0.0);
315 b[0] = vegaBarBS;
316 b[1] = vannaBarBS;
317 b[2] = volgaBarBS;
318
319 Array q = inverse(A) * b;
320
321 //touch probability
323 Real mu = domesticTS_->zeroRate(T_, Continuous).rate() - foreignTS_->zeroRate(T_, Continuous).rate() - pow(atmVol_->value(), 2.0)/2.0;
324 Real h2 = (log(arguments_.barrier/x0Quote->value()) + mu*T_)/(atmVol_->value()*sqrt(T_));
325 Real h2Prime = (log(x0Quote->value()/arguments_.barrier) + mu*T_)/(atmVol_->value()*sqrt(T_));
326 Real probTouch = 0.0;
328 probTouch = cnd(h2Prime) + pow(arguments_.barrier/x0Quote->value(), 2.0*mu/pow(atmVol_->value(), 2.0))*cnd(-h2);
329 else
330 probTouch = cnd(-h2Prime) + pow(arguments_.barrier/x0Quote->value(), 2.0*mu/pow(atmVol_->value(), 2.0))*cnd(h2);
331 Real p_survival = 1.0 - probTouch;
332
333 Real lambda = p_survival ;
334 Real adjust = q[0]*(priceAtmCallMkt - priceAtmCallBS)
335 + q[1]*(price25CallMkt - price25CallBS)
336 + q[2]*(price25PutMkt - price25PutBS);
337 Real outPrice = priceBS + lambda*adjust;//
338 Real inPrice;
339
340 //adapt Vanilla delta
341 if (adaptVanDelta_) {
342 outPrice += lambda*(bsPriceWithSmile_ - vanillaOption);
343 //capfloored by (0, vanilla)
344 outPrice = std::max(0.0, std::min(bsPriceWithSmile_, outPrice));
345 inPrice = bsPriceWithSmile_ - outPrice;
346 }
347 else{
348 //capfloored by (0, vanilla)
349 outPrice = std::max(0.0, std::min(vanillaOption, outPrice));
350 inPrice = vanillaOption - outPrice;
351 }
352
354 results_.value = outPrice;
355 else
356 results_.value = inPrice;
357 results_.additionalResults["VanillaPrice"] = vanillaOption;
358 results_.additionalResults["BarrierInPrice"] = inPrice;
359 results_.additionalResults["BarrierOutPrice"] = outPrice;
360 results_.additionalResults["lambda"] = lambda;
361 }
362 }
363}
Actual/365 (Fixed) day count convention.
1-D array used in linear algebra.
Definition: array.hpp:52
Barrier option on a single asset.
Black delta calculator class.
Real atmStrike(DeltaVolQuote::AtmType atmT) const
Real strikeFromDelta(Real delta) const
Cumulative normal distribution function.
void enableExtrapolation(bool b=true)
enable extrapolation in subsequent calls
Shared handle to an observable.
Definition: handle.hpp:41
const ext::shared_ptr< T > & currentLink() const
dereferencing
Definition: handle.hpp:148
std::map< std::string, ext::any > additionalResults
Definition: instrument.hpp:123
Real NPV() const
returns the net present value of the instrument.
Definition: instrument.hpp:167
void setPricingEngine(const ext::shared_ptr< PricingEngine > &)
set the pricing engine to be used.
Definition: instrument.cpp:35
base class for 1-D interpolations.
Matrix used in linear algebra.
Definition: matrix.hpp:41
Normal distribution function.
Calendar for reproducing theoretical calculations.
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
static Settings & instance()
access to the unique instance
Definition: singleton.hpp:104
const Handle< YieldTermStructure > foreignTS_
const Handle< DeltaVolQuote > vol25Put_
const Handle< DeltaVolQuote > vol25Call_
VannaVolgaBarrierEngine(Handle< DeltaVolQuote > atmVol, Handle< DeltaVolQuote > vol25Put, Handle< DeltaVolQuote > vol25Call, Handle< Quote > spotFX, Handle< YieldTermStructure > domesticTS, Handle< YieldTermStructure > foreignTS, bool adaptVanDelta=false, Real bsPriceWithSmile=0.0)
const Handle< YieldTermStructure > domesticTS_
const Handle< DeltaVolQuote > atmVol_
VannaVolga-interpolation factory and traits
Interpolation interpolate(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin) const
QL_REAL Real
real number
Definition: types.hpp:50
Definition: any.hpp:35
Real blackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount, Real displacement)
Matrix inverse(const Matrix &m)
Definition: matrix.cpp:44
STL namespace.