Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
parametricvolatility.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2024 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
21
22#include <ql/math/comparison.hpp>
23
24namespace QuantExt {
25
26using namespace QuantLib;
27
28ParametricVolatility::ParametricVolatility(const std::vector<MarketSmile> marketSmiles,
29 const MarketModelType marketModelType,
30 const MarketQuoteType inputMarketQuoteType,
31 const Handle<YieldTermStructure> discountCurve)
32 : marketSmiles_(std::move(marketSmiles)), marketModelType_(marketModelType),
33 inputMarketQuoteType_(inputMarketQuoteType), discountCurve_(std::move(discountCurve)) {}
34
35Real ParametricVolatility::convert(const Real inputQuote, const MarketQuoteType inputMarketQuoteType,
36 const Real inputLognormalShift,
37 const boost::optional<Option::Type> inputOptionTypeOpt, const Real timeToExpiry,
38 const Real strike, const Real forward, const MarketQuoteType outputMarketQuoteType,
39 const Real outputLognormalShift,
40 const boost::optional<Option::Type> outputOptionTypeOpt) const {
41
42 // determine the input and output option types
43
44 Option::Type otmOptionType = strike < forward ? Option::Put : Option::Call;
45 Option::Type inputOptionType = inputOptionTypeOpt ? *inputOptionTypeOpt : otmOptionType;
46 Option::Type outputOptionType = outputOptionTypeOpt ? *outputOptionTypeOpt : otmOptionType;
47
48 // check if there is nothing to convert
49
50 if (inputMarketQuoteType == outputMarketQuoteType && close_enough(inputLognormalShift, outputLognormalShift) &&
51 inputOptionType == outputOptionType) {
52 return inputQuote;
53 }
54
55 // otherwise compute the forward premium
56
57 Real forwardPremium;
58 switch (marketModelType_) {
60 if (inputMarketQuoteType == MarketQuoteType::Price) {
61 forwardPremium = inputQuote / (discountCurve_.empty() ? 1.0 : discountCurve_->discount(timeToExpiry));
62 } else if (inputMarketQuoteType == MarketQuoteType::NormalVolatility) {
63 forwardPremium =
64 bachelierBlackFormula(inputOptionType, strike, forward, inputQuote * std::sqrt(timeToExpiry));
65 } else if (inputMarketQuoteType == MarketQuoteType::ShiftedLognormalVolatility) {
66 if (strike < -inputLognormalShift)
67 forwardPremium = inputOptionType == Option::Call ? forward - strike : 0.0;
68 else {
69 forwardPremium = blackFormula(inputOptionType, strike, forward, inputQuote * std::sqrt(timeToExpiry),
70 1.0, inputLognormalShift);
71 }
72 } else {
73 QL_FAIL("ParametricVolatility::convert(): MarketQuoteType ("
74 << static_cast<int>(inputMarketQuoteType) << ") not handled. Internal error, contact dev.");
75 }
76 break;
77 default:
78 QL_FAIL("ParametricVolatility::convert(): MarketModelType (" << static_cast<int>(marketModelType_)
79 << ") not handled. Internal error, contact dev.");
80 }
81
82 // ... and compute the result from the forward premium
83
84 switch (marketModelType_) {
86 if (outputMarketQuoteType == MarketQuoteType::Price) {
87 return forwardPremium * (discountCurve_.empty() ? 1.0 : discountCurve_->discount(timeToExpiry));
88 } else if (outputMarketQuoteType == MarketQuoteType::NormalVolatility) {
89 return exactBachelierImpliedVolatility(outputOptionType, strike, forward, timeToExpiry, forwardPremium);
90 } else if (outputMarketQuoteType == MarketQuoteType::ShiftedLognormalVolatility) {
91 if (strike > -outputLognormalShift)
92 return blackFormulaImpliedStdDev(outputOptionType, strike, forward, forwardPremium, 1.0,
93 outputLognormalShift);
94 else
95 return 0.0;
96 } else {
97 QL_FAIL("ParametricVolatility::convert(): MarketQuoteType ("
98 << static_cast<int>(outputMarketQuoteType) << ") not handled. Internal error, contact dev.");
99 }
100 break;
101 }
102 default:
103 QL_FAIL("ParametricVolatility::convert(): MarketModelType (" << static_cast<int>(marketModelType_)
104 << ") not handled. Internal error, contact dev.");
105 }
106}
107
109 if (s.timeToExpiry < t.timeToExpiry)
110 return true;
111 if (s.timeToExpiry > t.timeToExpiry)
112 return false;
114 return true;
116 return false;
117 return false;
118}
119
120} // namespace QuantExt
Real convert(const Real inputQuote, const MarketQuoteType inputMarketQuoteType, const QuantLib::Real inputLognormalShift, const boost::optional< QuantLib::Option::Type > inputOptionType, const QuantLib::Real timeToExpiry, const QuantLib::Real strike, const QuantLib::Real forward, const MarketQuoteType outputMarketQuoteType, const QuantLib::Real outputLognormalShift, const boost::optional< QuantLib::Option::Type > outputOptionType=boost::none) const
QuantLib::Handle< QuantLib::YieldTermStructure > discountCurve_
ParametricVolatility(const std::vector< MarketSmile > marketSmiles, const MarketModelType marketModelType, const MarketQuoteType inputMarketQuoteType, const QuantLib::Handle< QuantLib::YieldTermStructure > discountCurve)
implied bachelier volatility based on Jaeckel, Implied Normal Volatility, 2017
bool operator<(const Dividend &d1, const Dividend &d2)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Real exactBachelierImpliedVolatility(Option::Type optionType, Real strike, Real forward, Real tte, Real bachelierPrice, Real discount)
cross-asset, generic volatility structure