20#include <ql/errors.hpp>
21#include <ql/experimental/fx/blackdeltacalculator.hpp>
22#include <ql/math/interpolations/cubicinterpolation.hpp>
23#include <ql/math/interpolations/linearinterpolation.hpp>
32 const std::vector<Real>&
strikes,
34 bool flatExtrapolation)
35 :
FxSmileSection(spot, rd, rf, t), strikes_(
strikes), vols_(vols), flatExtrapolation_(flatExtrapolation) {
43 interpolator_ = Cubic(CubicInterpolation::Kruger,
true, CubicInterpolation::SecondDerivative, 0.0,
44 CubicInterpolation::FirstDerivative)
49 QL_FAIL(
"Invalid method " << (
int)method);
65 Date referenceDate,
const std::vector<Date>& dates,
const std::vector<Real>& putDeltas,
66 const std::vector<Real>& callDeltas,
bool hasAtm,
const Matrix& blackVolMatrix,
const DayCounter& dayCounter,
67 const Calendar& cal,
const Handle<Quote>& spot,
const Handle<YieldTermStructure>& domesticTS,
68 const Handle<YieldTermStructure>& foreignTS, DeltaVolQuote::DeltaType dt, DeltaVolQuote::AtmType at,
69 boost::optional<DeltaVolQuote::DeltaType> atmDeltaType,
const Period& switchTenor, DeltaVolQuote::DeltaType ltdt,
70 DeltaVolQuote::AtmType ltat, boost::optional<QuantLib::DeltaVolQuote::DeltaType> longTermAtmDeltaType,
72 : BlackVolatilityTermStructure(referenceDate, cal, Following, dayCounter), dates_(dates), times_(dates.size(), 0),
73 putDeltas_(putDeltas), callDeltas_(callDeltas), hasAtm_(hasAtm), spot_(spot), domesticTS_(domesticTS),
74 foreignTS_(foreignTS), dt_(dt), at_(at), atmDeltaType_(atmDeltaType), switchTenor_(switchTenor), ltdt_(ltdt),
75 ltat_(ltat), longTermAtmDeltaType_(longTermAtmDeltaType), interpolationMethod_(im),
76 flatExtrapolation_(flatExtrapolation) {
87 QL_REQUIRE(
dates.size() > 1,
"at least 1 date required");
89 for (Size i = 0; i <
dates.size(); i++) {
90 QL_REQUIRE(referenceDate <
dates[i],
"Dates must be greater than reference date");
93 QL_REQUIRE(
times_[i] >
times_[i - 1],
"dates must be sorted unique!");
98 Size n = putDeltas.size() + (hasAtm ? 1 : 0) + callDeltas.size();
99 QL_REQUIRE(n > 0,
"Need at least one delta");
100 QL_REQUIRE(blackVolMatrix.columns() == n,
"Invalid number of columns in blackVolMatrix, got "
101 << blackVolMatrix.columns() <<
" but have " << n <<
" deltas");
102 QL_REQUIRE(blackVolMatrix.rows() ==
dates.size(),
"Invalid number of rows in blackVolMatrix, got "
103 << blackVolMatrix.rows() <<
" but have " <<
dates.size()
108 bool forceMonotoneVariance =
false;
109 for (Size i = 0; i < n; i++) {
110 vector<Volatility> vols(
dates.size());
111 for (Size j = 0; j <
dates.size(); j++) {
112 vols[j] = blackVolMatrix[j][i];
117 QuantLib::ext::make_shared<BlackVarianceCurve>(referenceDate,
dates, vols, dayCounter, forceMonotoneVariance));
128 Real spot =
spot_->value();
129 DiscountFactor dDiscount =
domesticTS_->discount(t);
130 DiscountFactor fDiscount =
foreignTS_->discount(t);
132 DeltaVolQuote::AtmType at;
133 DeltaVolQuote::DeltaType dt;
134 DeltaVolQuote::DeltaType atmDt;
147 auto comp = [](Real a, Real b) {
return !close(a, b) && a < b; };
148 map<Real, Real,
decltype(comp)> smileSection(comp);
153 BlackDeltaCalculator bdc(Option::Put, dt, spot, dDiscount, fDiscount, vol *
sqrt(t));
154 Real strike = bdc.strikeFromDelta(delta);
155 if (smileSection.count(strike) == 0)
156 smileSection[strike] = vol;
157 }
catch (
const std::exception& e) {
158 QL_FAIL(
"BlackVolatilitySurfaceDelta: Error during calculating put strike at delta " << delta <<
": "
166 BlackDeltaCalculator bdc(Option::Put, atmDt, spot, dDiscount, fDiscount, vol *
sqrt(t));
167 Real strike = bdc.atmStrike(at);
168 if (smileSection.count(strike) == 0)
169 smileSection[strike] = vol;
170 }
catch (
const std::exception& e) {
171 QL_FAIL(
"BlackVolatilitySurfaceDelta: Error during calculating atm strike: " << e.what());
178 BlackDeltaCalculator bdc(Option::Call, dt, spot, dDiscount, fDiscount, vol *
sqrt(t));
179 Real strike = bdc.strikeFromDelta(delta);
180 if (smileSection.count(strike) == 0)
181 smileSection[strike] = vol;
182 }
catch (
const std::exception& e) {
183 QL_FAIL(
"BlackVolatilitySurfaceDelta: Error during calculating call strike at delta " << delta <<
": "
191 strikes.reserve(smileSection.size());
193 vols.reserve(smileSection.size());
194 for (
const auto& kv : smileSection) {
196 vols.push_back(kv.second);
200 QL_REQUIRE(!vols.empty(),
201 "BlackVolatilitySurfaceDelta::blackVolSmile(" << t <<
"): no strikes given, this is unexpected.");
202 if (vols.size() == 1) {
204 return QuantLib::ext::make_shared<ConstantSmileSection>(vols.front());
207 return QuantLib::ext::make_shared<InterpolatedSmileSection>(spot, dDiscount, fDiscount, t,
strikes, vols,
224 if (strike == 0 || strike == Null<Real>()) {
Black volatility surface based on delta.
boost::optional< QuantLib::DeltaVolQuote::DeltaType > atmDeltaType_
DeltaVolQuote::DeltaType dt_
BlackVolatilitySurfaceDelta(Date referenceDate, const std::vector< Date > &dates, const std::vector< Real > &putDeltas, const std::vector< Real > &callDeltas, bool hasAtm, const Matrix &blackVolMatrix, const DayCounter &dayCounter, const Calendar &cal, const Handle< Quote > &spot, const Handle< YieldTermStructure > &domesticTS, const Handle< YieldTermStructure > &foreignTS, DeltaVolQuote::DeltaType dt=DeltaVolQuote::DeltaType::Spot, DeltaVolQuote::AtmType at=DeltaVolQuote::AtmType::AtmDeltaNeutral, boost::optional< QuantLib::DeltaVolQuote::DeltaType > atmDeltaType=boost::none, const Period &switchTenor=0 *Days, DeltaVolQuote::DeltaType ltdt=DeltaVolQuote::DeltaType::Fwd, DeltaVolQuote::AtmType ltat=DeltaVolQuote::AtmType::AtmDeltaNeutral, boost::optional< QuantLib::DeltaVolQuote::DeltaType > longTermAtmDeltaType=boost::none, InterpolatedSmileSection::InterpolationMethod interpolationMethod=InterpolatedSmileSection::InterpolationMethod::Linear, bool flatExtrapolation=true)
std::vector< Real > putDeltas_
DeltaVolQuote::DeltaType ltdt_
std::vector< QuantLib::ext::shared_ptr< BlackVarianceCurve > > interpolators_
Handle< YieldTermStructure > foreignTS_
std::vector< Time > times_
std::vector< Real > callDeltas_
Handle< YieldTermStructure > domesticTS_
QuantLib::ext::shared_ptr< FxSmileSection > blackVolSmile(Time t) const
Return an FxSmile for the time t.
boost::optional< QuantLib::DeltaVolQuote::DeltaType > longTermAtmDeltaType_
InterpolatedSmileSection::InterpolationMethod interpolationMethod_
virtual Volatility blackVolImpl(Time t, Real strike) const override
const std::vector< QuantLib::Date > & dates() const
DeltaVolQuote::AtmType at_
Real forward(Time t) const
DeltaVolQuote::AtmType ltat_
std::vector< Real > strikes_
Volatility volatility(Real strike) const override
InterpolationMethod
Supported interpolation methods.
std::vector< Volatility > vols_
Interpolation interpolator_
InterpolatedSmileSection(Real spot, Real rd, Real rf, Time t, const std::vector< Real > &strikes, const std::vector< Volatility > &vols, InterpolationMethod method, bool flatExtrapolation=false)
ctor
RandomVariable sqrt(RandomVariable x)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)