21#include <boost/algorithm/string/join.hpp>
22#include <boost/range/adaptor/indexed.hpp>
23#include <boost/range/adaptor/transformed.hpp>
31#include <ql/math/interpolations/loginterpolation.hpp>
32#include <ql/math/matrix.hpp>
33#include <ql/pricingengines/blackformula.hpp>
34#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
35#include <ql/termstructures/volatility/equityfx/blackvariancecurve.hpp>
36#include <ql/termstructures/volatility/equityfx/blackvariancesurface.hpp>
37#include <ql/time/calendars/weekendsonly.hpp>
38#include <ql/time/daycounters/actual365fixed.hpp>
58 const CurveConfigurations&
curveConfigs,
const Handle<EquityIndex2>& eqIndex,
59 const map<
string, QuantLib::ext::shared_ptr<EquityCurve>>& requiredEquityCurves,
60 const map<
string, QuantLib::ext::shared_ptr<EquityVolCurve>>& requiredEquityVolCurves,
61 const map<
string, QuantLib::ext::shared_ptr<FXVolCurve>>& requiredFxVolCurves,
62 const map<
string, QuantLib::ext::shared_ptr<CorrelationCurve>>& requiredCorrelationCurves,
63 const Market* fxIndices,
const bool buildCalibrationInfo) {
66 LOG(
"EquityVolCurve: start building equity volatility structure with ID " <<
spec.
curveConfigID());
71 if (config.calendar().empty())
79 DLOG(
"EquityVolCurve: Attempting to build equity vol curve from volatilityConfig, " << config.volatilityConfig().size() <<
" volatility configs provided.");
80 for (
auto vc : config.volatilityConfig()) {
83 if (!vc->calendar().empty())
86 if (
auto eqvc = QuantLib::ext::dynamic_pointer_cast<ProxyVolatilityConfig>(vc)) {
88 requiredFxVolCurves, requiredCorrelationCurves, fxIndices);
89 }
else if (
auto qvc = QuantLib::ext::dynamic_pointer_cast<QuoteBasedVolatilityConfig>(vc)) {
93 "EquityVolCurve: Only lognormal volatilities and option premiums supported for equity "
94 "volatility surfaces.");
95 if (
auto cvc = QuantLib::ext::dynamic_pointer_cast<ConstantVolatilityConfig>(vc)) {
97 }
else if (
auto vcc = QuantLib::ext::dynamic_pointer_cast<VolatilityCurveConfig>(vc)) {
99 }
else if (
auto vssc = QuantLib::ext::dynamic_pointer_cast<VolatilityStrikeSurfaceConfig>(vc)) {
101 }
else if (
auto vmsc = QuantLib::ext::dynamic_pointer_cast<VolatilityMoneynessSurfaceConfig>(vc)) {
103 }
else if (
auto vdsc = QuantLib::ext::dynamic_pointer_cast<VolatilityDeltaSurfaceConfig>(vc)) {
105 }
else if (
auto vdsc = QuantLib::ext::dynamic_pointer_cast<VolatilityApoFutureSurfaceConfig>(vc)) {
106 QL_FAIL(
"EquityVolCurve: VolatilityApoFutureSurfaceConfig surface not supported for Equities");
108 QL_FAIL(
"EquityVolCurve: Unexpected VolatilityConfig");
111 QL_FAIL(
"EquityVolCurve: VolatilityConfig must be QuoteBased or a Proxy");
117 catch (std::exception& e) {
118 DLOG(
"EquityVolCurve: equity vol curve building failed :" << e.what());
121 DLOG(
"EquityVolCurve: equity vol curve building failed: unknown error");
125 QL_FAIL(
"EquityVolCurve: Failed to build equity volatility structure from " << config.volatilityConfig().size() <<
" volatility configs provided.");
126 LOG(
"EquityVolCurve: finished building equity volatility structure with ID " <<
spec.
curveConfigID());
132 }
catch (exception& e) {
133 QL_FAIL(
"Equity volatility curve building failed : " << e.what());
135 QL_FAIL(
"Equity volatility curve building failed: unknown error");
140 const ConstantVolatilityConfig& cvc,
const Loader& loader) {
141 DLOG(
"EquityVolCurve: start building constant volatility structure");
146 "Quote for Equity Constant Volatility Config must be a Volatility");
148 const QuantLib::ext::shared_ptr<MarketDatum>& md = loader.get(cvc.quote(), asof);
149 QL_REQUIRE(md->asofDate() == asof,
"MarketDatum asofDate '" << md->asofDate() <<
"' <> asof '" << asof <<
"'");
151 "MarketDatum instrument type '" << md->instrumentType() <<
"' <> 'MarketDatum::InstrumentType::EQUITY_OPTION'");
152 QuantLib::ext::shared_ptr<EquityOptionQuote> q = QuantLib::ext::dynamic_pointer_cast<EquityOptionQuote>(md);
153 QL_REQUIRE(q,
"Internal error: could not downcast MarketDatum '" << md->name() <<
"' to EquityOptionQuote");
154 QL_REQUIRE(q->name() == cvc.quote(),
155 "EquityOptionQuote name '" << q->name() <<
"' <> ConstantVolatilityConfig quote '" << cvc.quote() <<
"'");
156 TLOG(
"Found the constant volatility quote " << q->name());
160 DLOG(
"Creating BlackConstantVol structure");
163 DLOG(
"EquityVolCurve: finished building constant volatility structure");
167 const VolatilityCurveConfig& vcc,
const Loader& loader) {
169 DLOG(
"EquityVolCurve: start building 1-D volatility curve");
174 "Quote for Equity Constant Volatility Config must be a Volatility");
177 QL_REQUIRE(vcc.quotes().size() > 0,
"No quotes specified in config " << vc.curveID());
184 map<Date, Real> curveData;
188 DLOG(
"Have single quote with pattern " << wildcard->pattern());
191 for (
const auto& md : loader.get(*wildcard, asof)) {
193 QL_REQUIRE(md->asofDate() == asof,
"MarketDatum asofDate '" << md->asofDate() <<
"' <> asof '" << asof <<
"'");
195 auto q = QuantLib::ext::dynamic_pointer_cast<EquityOptionQuote>(md);
196 QL_REQUIRE(q,
"Internal error: could not downcast MarketDatum '" << md->name() <<
"' to EquityOptionQuote");
197 QL_REQUIRE(q->quoteType() == vcc.quoteType(),
198 "EquityOptionQuote type '" << q->quoteType() <<
"' <> VolatilityCurveConfig quote type '" << vcc.quoteType() <<
"'");
200 TLOG(
"The quote " << q->name() <<
" matched the pattern");
203 if (expiryDate > asof) {
205 QL_REQUIRE(curveData.count(expiryDate) == 0,
"Duplicate quote for the expiry date "
206 << io::iso_date(expiryDate)
207 <<
" provided by equity volatility config "
212 TLOG(
"Added quote " << q->name() <<
": (" << io::iso_date(expiryDate) <<
"," << fixed
213 << setprecision(9) << q->quote()->value() <<
")");
217 QL_REQUIRE(curveData.size() > 0,
"No quotes found matching regular expression " << vcc.quotes()[0]);
221 DLOG(
"Have " << vcc.quotes().size() <<
" explicit quotes");
223 Size excludedAlreadyExpired = 0;
226 std::ostringstream ss;
229 Wildcard w(ss.str());
230 for (
const auto& md : loader.get(w, asof)) {
232 QL_REQUIRE(md->asofDate() == asof,
"MarketDatum asofDate '" << md->asofDate() <<
"' <> asof '" << asof <<
"'");
234 auto q = QuantLib::ext::dynamic_pointer_cast<EquityOptionQuote>(md);
235 QL_REQUIRE(q,
"Internal error: could not downcast MarketDatum '" << md->name() <<
"' to EquityOptionQuote");
238 auto it = find(vcc.quotes().begin(), vcc.quotes().end(), q->name());
240 if (it != vcc.quotes().end()) {
241 TLOG(
"Found the configured quote " << q->name());
244 if (expiryDate <= asof) {
245 LOG(
"Warning Stale Marketdata: Equity volatility quote '"
246 << q->name() <<
"' has expired in the past (" << io::iso_date(expiryDate) <<
") and is ignored");
247 ++excludedAlreadyExpired;
250 QL_REQUIRE(curveData.count(expiryDate) == 0,
"Duplicate quote for the date "
251 << io::iso_date(expiryDate)
252 <<
" provided by equity volatility config "
257 TLOG(
"Added quote " << q->name() <<
": (" << io::iso_date(expiryDate) <<
"," << fixed
258 << setprecision(9) << q->quote()->value() <<
")");
261 QL_REQUIRE(curveData.size() > 0,
"No 'live' quotes found");
263 QL_REQUIRE((curveData.size() - excludedAlreadyExpired) == vcc.quotes().size(),
264 "Found " << curveData.size() + excludedAlreadyExpired <<
" quotes, of which "
265 << excludedAlreadyExpired <<
" has been in the past but " << vcc.quotes().size()
266 <<
" quotes were given in config.");
271 vector<Volatility> volatilities;
272 for (
const auto& datum : curveData) {
273 dates.push_back(datum.first);
274 volatilities.push_back(datum.second);
275 TLOG(
"Added data point (" << io::iso_date(dates.back()) <<
"," << fixed << setprecision(9)
276 << volatilities.back() <<
")");
279 DLOG(
"Creating BlackVarianceCurve object.");
280 auto tmp = QuantLib::ext::make_shared<BlackVarianceCurve>(asof, dates, volatilities,
dayCounter_);
287 if (vcc.interpolation() ==
"Linear") {
288 DLOG(
"Interpolation set to Linear.");
289 }
else if (vcc.interpolation() ==
"Cubic") {
290 DLOG(
"Setting interpolation to Cubic.");
291 tmp->setInterpolation<Cubic>();
292 }
else if (vcc.interpolation() ==
"LogLinear") {
293 DLOG(
"Setting interpolation to LogLinear.");
294 tmp->setInterpolation<LogLinear>();
296 DLOG(
"Interpolation " << vcc.interpolation() <<
" not recognised so leaving it Linear.");
304 DLOG(
"Enabling BlackVarianceCurve flat volatility extrapolation.");
305 vol_->enableExtrapolation();
307 DLOG(
"Disabling BlackVarianceCurve extrapolation.");
308 vol_->disableExtrapolation();
310 DLOG(
"BlackVarianceCurve does not support using interpolator for extrapolation "
311 <<
"so default to flat volatility extrapolation.");
312 vol_->enableExtrapolation();
314 DLOG(
"Unexpected extrapolation so default to flat volatility extrapolation.");
315 vol_->enableExtrapolation();
318 DLOG(
"EquityVolCurve: finished building 1-D volatility curve");
322 const VolatilityStrikeSurfaceConfig& vssc,
const Loader& loader,
323 const QuantLib::Handle<EquityIndex2>& eqIndex) {
325 DLOG(
"EquityVolCurve: start building 2-D strike volatility surface");
327 QL_REQUIRE(vssc.expiries().size() > 0,
"No expiries defined");
328 QL_REQUIRE(vssc.strikes().size() > 0,
"No strikes defined");
331 bool expiriesWc = find(vssc.expiries().begin(), vssc.expiries().end(),
"*") != vssc.expiries().end();
332 bool strikesWc = find(vssc.strikes().begin(), vssc.strikes().end(),
"*") != vssc.strikes().end();
334 QL_REQUIRE(vssc.expiries().size() == 1,
"Wild card expiry specified but more expiries also specified.");
337 QL_REQUIRE(vssc.strikes().size() == 1,
"Wild card strike specified but more strikes also specified.");
339 bool wildcard = strikesWc || expiriesWc;
341 vector<Real> callStrikes, putStrikes;
342 vector<Real> callData, putData;
343 vector<Date> callExpiries, putExpiries;
346 bool strikeRelevant = strikesWc;
347 bool expiryRelevant = expiriesWc;
348 bool quoteRelevant =
true;
351 Size callQuotesAdded = 0;
352 Size putQuotesAdded = 0;
353 Size excludedAlreadyExpired = 0;
354 std::ostringstream ss;
357 Wildcard w(ss.str());
358 for (
const auto& md : loader.get(w, asof)) {
359 QL_REQUIRE(md->asofDate() == asof,
"MarketDatum asofDate '" << md->asofDate() <<
"' <> asof '" << asof <<
"'");
360 QuantLib::ext::shared_ptr<EquityOptionQuote> q = QuantLib::ext::dynamic_pointer_cast<EquityOptionQuote>(md);
361 QL_REQUIRE(q,
"Internal error: could not downcast MarketDatum '" << md->name() <<
"' to EquityOptionQuote");
364 auto absoluteStrike = QuantLib::ext::dynamic_pointer_cast<AbsoluteStrike>(q->strike());
368 auto j = std::find(vssc.expiries().begin(), vssc.expiries().end(), q->expiry());
369 expiryRelevant = j != vssc.expiries().end();
372 auto i = std::find_if(vssc.strikes().begin(), vssc.strikes().end(),
373 [&absoluteStrike](
const std::string& x) {
374 return close_enough(parseReal(x), absoluteStrike->strike());
376 strikeRelevant = i != vssc.strikes().end();
378 quoteRelevant = strikeRelevant && expiryRelevant;
386 if (tmpDate <= asof) {
387 LOG(
"expired Equity volatility quote '"
388 << q->name() <<
"' ignored, expired on (" << io::iso_date(tmpDate)
390 ++excludedAlreadyExpired;
394 Real quoteValue = q->quote()->value();
400 callStrikes.push_back(strikeValue);
401 callData.push_back(quoteValue);
402 callExpiries.push_back(tmpDate);
405 putStrikes.push_back(strikeValue);
406 putData.push_back(quoteValue);
407 putExpiries.push_back(tmpDate);
413 QL_REQUIRE(callQuotesAdded > 0,
"No valid equity volatility quotes provided");
414 bool callSurfaceOnly =
false;
415 if (callQuotesAdded > 0 && putQuotesAdded == 0) {
417 "For Premium quotes, call and put quotes must be supplied.");
418 DLOG(
"EquityVolCurve: " << vc.curveID() <<
": Only one set of quotes, can build surface directly");
419 callSurfaceOnly =
true;
423 Size explicitGridSize = vssc.expiries().size() * vssc.strikes().size();
425 QL_REQUIRE(callQuotesAdded + excludedAlreadyExpired == explicitGridSize,
426 "EquityVolCurve: " << vc.curveID() <<
": " << callQuotesAdded +excludedAlreadyExpired
427 <<
" quotes provided, of which " << excludedAlreadyExpired <<
"have been excluded, but "
428 << explicitGridSize <<
" expected.");
429 if (!callSurfaceOnly) {
430 QL_REQUIRE(callQuotesAdded == putQuotesAdded,
431 "Call and Put quotes must match for explicitly defined surface, "
432 << callQuotesAdded <<
" call quotes, and " << putQuotesAdded <<
" put quotes");
433 DLOG(
"EquityVolCurve: " << vc.curveID() <<
": Complete set of " << callQuotesAdded
434 <<
", call and put quotes found.");
438 QL_REQUIRE(callStrikes.size() == callData.size() && callData.size() == callExpiries.size(),
439 "Quotes loaded don't produce strike,vol,expiry vectors of equal length.");
440 QL_REQUIRE(putStrikes.size() == putData.size() && putData.size() == putExpiries.size(),
441 "Quotes loaded don't produce strike,vol,expiry vectors of equal length.");
442 DLOG(
"EquityVolCurve: " << vc.curveID() <<
": Found " << callQuotesAdded <<
", call quotes and "
443 << putQuotesAdded <<
" put quotes using wildcard.");
446 bool flatStrikeExtrap =
true;
447 bool flatTimeExtrap =
true;
448 if (vssc.extrapolation()) {
452 TLOG(
"EquityVolCurve: Strike extrapolation switched to using interpolator.");
453 flatStrikeExtrap =
false;
455 TLOG(
"EquityVolCurve: Strike extrapolation cannot be turned off on its own so defaulting to flat.");
457 TLOG(
"EquityVolCurve: Strike extrapolation has been set to flat.");
459 TLOG(
"EquityVolCurve: Strike extrapolation " << strikeExtrapType <<
" not expected so default to flat.");
464 TLOG(
"EquityVolCurve: Time extrapolation switched to using interpolator.");
465 flatTimeExtrap =
false;
467 TLOG(
"EquityVolCurve: Time extrapolation cannot be turned off on its own so defaulting to flat.");
469 TLOG(
"EquityVolCurve: Time extrapolation has been set to flat.");
471 TLOG(
"EquityVolCurve: Time extrapolation " << timeExtrapType <<
" not expected so default to flat.");
475 TLOG(
"EquityVolCurve: Extrapolation is turned off for the whole surface so the time and"
476 <<
" strike extrapolation settings are ignored");
481 for (
auto const& d : callExpiries)
483 for (
auto const& d : putExpiries)
488 bool preferOutOfTheMoney = vc.preferOutOfTheMoney() ? *vc.preferOutOfTheMoney() :
true;
495 DLOG(
"EquityVolCurve: Building a option price surface for calls and puts");
496 QuantLib::ext::shared_ptr<OptionPriceSurface> callSurface =
497 QuantLib::ext::make_shared<OptionPriceSurface>(asof, callExpiries, callStrikes, callData,
dayCounter_);
498 QuantLib::ext::shared_ptr<OptionPriceSurface> putSurface =
499 QuantLib::ext::make_shared<OptionPriceSurface>(asof, putExpiries, putStrikes, putData,
dayCounter_);
501 DLOG(
"EquityVolCurve: CallSurface contains " << callSurface->expiries().size() <<
" expiries.");
503 DLOG(
"EquityVolCurve: Stripping equity volatility surface from the option premium surfaces");
504 QuantLib::ext::shared_ptr<EquityOptionSurfaceStripper> eoss = QuantLib::ext::make_shared<EquityOptionSurfaceStripper>(
505 eqIndex, callSurface, putSurface,
calendar_,
dayCounter_, vssc.exerciseType(), flatStrikeExtrap,
506 flatStrikeExtrap, flatTimeExtrap, preferOutOfTheMoney, solverOptions);
507 vol_ = eoss->volSurface();
511 if (callExpiries.size() == 1 && callStrikes.size() == 1) {
512 DLOG(
"EquityVolCurve: Building BlackConstantVol");
513 vol_ = QuantLib::ext::shared_ptr<BlackVolTermStructure>(
514 new BlackConstantVol(asof, Calendar(), callData[0],
dayCounter_));
517 QuantLib::ext::shared_ptr<BlackVarianceSurfaceSparse> callSurface =
518 QuantLib::ext::make_shared<BlackVarianceSurfaceSparse>(asof,
calendar_, callExpiries, callStrikes, callData,
522 if (callSurfaceOnly) {
527 QuantLib::ext::shared_ptr<BlackVarianceSurfaceSparse> putSurface =
528 QuantLib::ext::make_shared<BlackVarianceSurfaceSparse>(asof,
calendar_, putExpiries, putStrikes,
530 flatStrikeExtrap, flatTimeExtrap);
532 QuantLib::ext::shared_ptr<EquityOptionSurfaceStripper> eoss =
533 QuantLib::ext::make_shared<EquityOptionSurfaceStripper>(
535 flatStrikeExtrap, flatStrikeExtrap, flatTimeExtrap, preferOutOfTheMoney);
536 vol_ = eoss->volSurface();
540 QL_FAIL(
"EquityVolCurve: Invalid quote type provided.");
542 DLOG(
"EquityVolCurve: Setting BlackVarianceSurfaceSparse extrapolation to " <<
to_string(vssc.extrapolation()));
543 vol_->enableExtrapolation(vssc.extrapolation());
545 DLOG(
"EquityVolCurve: EquityVolCurve: finished building 2-D strike volatility surface");
549vector<Real> checkMoneyness(
const vector<string>& strMoneynessLevels) {
551 using boost::adaptors::transformed;
552 using boost::algorithm::join;
554 vector<Real> moneynessLevels = parseVectorOfValues<Real>(strMoneynessLevels, &parseReal);
555 sort(moneynessLevels.begin(), moneynessLevels.end(), [](Real x, Real y) { return !close(x, y) && x < y; });
556 QL_REQUIRE(adjacent_find(moneynessLevels.begin(), moneynessLevels.end(),
557 [](Real x, Real y) { return close(x, y); }) == moneynessLevels.end(),
558 "The configured moneyness levels contain duplicates");
559 DLOG(
"EquityVolCurve: Parsed " << moneynessLevels.size() <<
" unique configured moneyness levels.");
560 DLOG(
"EquityVolCurve: The moneyness levels are: " << join(
563 return moneynessLevels;
568 const VolatilityMoneynessSurfaceConfig& vmsc,
const Loader& loader,
569 const QuantLib::Handle<EquityIndex2>& eqIndex) {
571 LOG(
"EquityVolCurve: start building 2-D volatility moneyness strike surface");
572 using boost::adaptors::transformed;
573 using boost::algorithm::join;
577 "EquityVolCurve: Equity Moneyness Surface supports lognormal volatility quotes only");
580 vector<Real> moneynessLevels = checkMoneyness(vmsc.moneynessLevels());
584 if (find(vmsc.expiries().begin(), vmsc.expiries().end(),
"*") != vmsc.expiries().end()) {
586 QL_REQUIRE(vmsc.expiries().size() == 1,
"EquityVolCurve: Wild card expiry specified but more expiries also specified.");
587 DLOG(
"EquityVolCurve: Have expiry wildcard pattern " << vmsc.expiries()[0]);
592 map<Date, vector<Real>> surfaceData;
595 Size quotesAdded = 0;
601 vector<QuantLib::ext::shared_ptr<BaseStrike>>
strikes;
602 for (
const auto& moneynessLevel : moneynessLevels) {
603 strikes.push_back(QuantLib::ext::make_shared<MoneynessStrike>(moneynessType, moneynessLevel));
607 std::ostringstream ss;
610 Wildcard w(ss.str());
611 for (
const auto& md : loader.get(w, asof)) {
613 QL_REQUIRE(md->asofDate() == asof,
"MarketDatum asofDate '" << md->asofDate() <<
"' <> asof '" << asof <<
"'");
615 auto q = QuantLib::ext::dynamic_pointer_cast<EquityOptionQuote>(md);
616 QL_REQUIRE(q,
"Internal error: could not downcast MarketDatum '" << md->name() <<
"' to EquityOptionQuote");
617 QL_REQUIRE(q->eqName() == vc.equityId(),
"EquityOptionQuote eqName '"
618 << q->eqName() <<
"' <> EquityVolatilityCurveConfig equityId '"
619 << vc.equityId() <<
"'");
620 QL_REQUIRE(q->ccy() == vc.ccy(),
621 "EquityOptionQuote ccy '" << q->ccy() <<
"' <> EquityVolatilityCurveConfig ccy '" << vc.ccy() <<
"'");
622 QL_REQUIRE(q->quoteType() == vmsc.quoteType(),
623 "EquityOptionQuote quoteType '" << q->quoteType() <<
"' <> VolatilityMoneynessSurfaceConfig quoteType '" << vmsc.quoteType() <<
"'");
626 vector<QuantLib::ext::shared_ptr<BaseStrike>>::iterator strikeIt;
631 [&q](QuantLib::ext::shared_ptr<BaseStrike> s) { return *s == *q->strike(); });
636 auto it = find(vc.quotes().begin(), vc.quotes().end(), q->name());
637 if (it == vc.quotes().end())
642 [&q](QuantLib::ext::shared_ptr<BaseStrike> s) { return *s == *q->strike(); });
648 Size pos = std::distance(
strikes.begin(), strikeIt);
654 if (surfaceData.count(eDate) == 0)
655 surfaceData[eDate] = vector<Real>(moneynessLevels.size(), Null<Real>());
657 QL_REQUIRE(surfaceData[eDate][pos] == Null<Real>(),
658 "EquityVolCurve: Quote " << q->name() <<
" provides a duplicate quote for the date " << io::iso_date(eDate)
659 <<
" and strike " << *q->strike());
660 surfaceData[eDate][pos] = q->quote()->value();
663 TLOG(
"EquityVolCurve: Added quote " << q->name() <<
": (" << io::iso_date(eDate) <<
"," << *q->strike() <<
"," << fixed
664 << setprecision(9) <<
"," << q->quote()->value() <<
")");
667 DLOG(
"EquityVolCurve: added " << quotesAdded <<
" quotes in building moneyness strike surface.");
672 QL_REQUIRE(!surfaceData.empty(),
"EquityVolCurve: Moneyness Surface Data is empty");
674 for (
const auto& kv : surfaceData) {
675 for (Size j = 0; j < moneynessLevels.size(); j++) {
676 QL_REQUIRE(kv.second[j] != Null<Real>(),
"EquityVolCurve: Volatility for expiry date "
677 << io::iso_date(kv.first) <<
" and strike " << *strikes[j]
678 <<
" not found. Cannot proceed with a sparse matrix.");
684 QL_REQUIRE(vc.quotes().size() == quotesAdded,
685 "EquityVolCurve: Found " << quotesAdded <<
" quotes, but " << vc.quotes().size() <<
" quotes required by config.");
690 vector<Date> expiryDates(surfaceData.size());
691 vector<Time> expiryTimes(surfaceData.size());
692 vector<vector<Handle<Quote>>> vols(moneynessLevels.size());
693 for (
const auto row : surfaceData | boost::adaptors::indexed(0)) {
694 expiryDates[row.index()] = row.value().first;
695 expiryTimes[row.index()] =
dayCounter_.yearFraction(asof, row.value().first);
696 for (Size i = 0; i < row.value().second.size(); i++) {
697 vols[i].push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(row.value().second[i])));
702 if (!expiryDates.empty())
707 bool flatExtrapolation =
true;
708 if (vmsc.extrapolation()) {
712 TLOG(
"EquityVolCurve: Strike extrapolation switched to using interpolator.");
713 flatExtrapolation =
false;
715 TLOG(
"EquityVolCurve: Strike extrapolation cannot be turned off on its own so defaulting to flat.");
717 TLOG(
"EquityVolCurve: Strike extrapolation has been set to flat.");
719 TLOG(
"EquityVolCurve: Strike extrapolation " << strikeExtrapType <<
" not expected so default to flat.");
724 TLOG(
"EquityVolCurve: BlackVarianceSurfaceMoneyness only supports flat volatility extrapolation in the time direction");
727 TLOG(
"EquityVolCurve: Extrapolation is turned off for the whole surface so the time and"
728 <<
" strike extrapolation settings are ignored");
732 if (vmsc.timeInterpolation() !=
"Linear") {
733 TLOG(
"EquityVolCurve: BlackVarianceSurfaceMoneyness only supports linear time interpolation in variance.");
737 if (vmsc.strikeInterpolation() !=
"Linear") {
738 TLOG(
"EquityVolCurve: BlackVarianceSurfaceMoneyness only supports linear strike interpolation in variance.");
747 bool stickyStrike =
false;
750 DLOG(
"EquityVolCurve: Creating BlackVarianceSurfaceMoneynessForward object");
751 vol_ = QuantLib::ext::make_shared<BlackVarianceSurfaceMoneynessForward>(
753 eqIndex->equityDividendCurve(), eqIndex->equityForecastCurve(), stickyStrike, flatExtrapolation);
756 DLOG(
"EquityVolCurve: Creating BlackVarianceSurfaceMoneynessSpot object");
757 vol_ = QuantLib::ext::make_shared<BlackVarianceSurfaceMoneynessSpot>(
calendar_, eqIndex->equitySpot(), expiryTimes,
762 DLOG(
"EquityVolCurve: Setting BlackVarianceSurfaceMoneyness extrapolation to " <<
to_string(vmsc.extrapolation()));
763 vol_->enableExtrapolation(vmsc.extrapolation());
765 DLOG(
"EquityVolCurve: EquityVolCurve: finished building 2-D volatility moneyness strike surface");
770 const QuantLib::Handle<QuantExt::EquityIndex2>& eqIndex) {
772 using boost::adaptors::transformed;
773 using boost::algorithm::join;
775 DLOG(
"EquityVolCurve: start building 2-D volatility delta strike surface");
778 "EquityVolCurve: only quote type"
779 <<
" RATE_LNVOL is currently supported for a 2-D volatility delta strike surface.");
783 sort(putDeltas.begin(), putDeltas.end(), [](Real x, Real y) { return !close(x, y) && x < y; });
784 QL_REQUIRE(adjacent_find(putDeltas.begin(), putDeltas.end(), [](Real x, Real y) { return close(x, y); }) ==
786 "EquityVolCurve: The configured put deltas contain duplicates");
787 DLOG(
"EquityVolCurve: Parsed " << putDeltas.size() <<
" unique configured put deltas");
788 DLOG(
"EquityVolCurve: Put deltas are: " << join(putDeltas | transformed([](Real d) {
return ore::data::to_string(d); }),
","));
792 sort(callDeltas.begin(), callDeltas.end(), [](Real x, Real y) { return !close(x, y) && x > y; });
793 QL_REQUIRE(adjacent_find(callDeltas.begin(), callDeltas.end(), [](Real x, Real y) { return close(x, y); }) ==
795 "EquityVolCurve: The configured call deltas contain duplicates");
796 DLOG(
"EquityVolCurve: Parsed " << callDeltas.size() <<
" unique configured call deltas");
797 DLOG(
"EquityVolCurve: Call deltas are: " << join(callDeltas | transformed([](Real d) {
return ore::data::to_string(d); }),
","));
803 QL_REQUIRE(vdsc.
expiries().size() == 1,
"Wild card expiry specified but more expiries also specified.");
804 DLOG(
"EquityVolCurve: Have expiry wildcard pattern " << vdsc.
expiries()[0]);
809 map<Date, vector<Real>> surfaceData;
812 Size numStrikes = putDeltas.size() + 1 + callDeltas.size();
815 Size quotesAdded = 0;
820 boost::optional<DeltaVolQuote::DeltaType> atmDeltaType;
826 vector<QuantLib::ext::shared_ptr<BaseStrike>>
strikes;
827 for (
const auto& pd : putDeltas) {
828 strikes.push_back(QuantLib::ext::make_shared<DeltaStrike>(deltaType, Option::Put, pd));
830 strikes.push_back(QuantLib::ext::make_shared<AtmStrike>(atmType, atmDeltaType));
831 for (
const auto& cd : callDeltas) {
832 strikes.push_back(QuantLib::ext::make_shared<DeltaStrike>(deltaType, Option::Call, cd));
836 std::ostringstream ss;
840 for (
const auto& md : loader.
get(w, asof)) {
842 QL_REQUIRE(md->asofDate() == asof,
"MarketDatum asofDate '" << md->asofDate() <<
"' <> asof '" << asof <<
"'");
844 auto q = QuantLib::ext::dynamic_pointer_cast<EquityOptionQuote>(md);
845 QL_REQUIRE(q,
"Internal error: could not downcast MarketDatum '" << md->name() <<
"' to EquityOptionQuote");
846 QL_REQUIRE(q->eqName() == vc.
equityId(),
"EquityOptionQuote eqName '"
847 << q->eqName() <<
"' <> EquityVolatilityCurveConfig equityId '"
849 QL_REQUIRE(q->ccy() == vc.
ccy(),
850 "EquityOptionQuote ccy '" << q->ccy() <<
"' <> EquityVolatilityCurveConfig ccy '" << vc.
ccy() <<
"'");
851 QL_REQUIRE(q->quoteType() == vdsc.
quoteType(),
852 "EquityOptionQuote quoteType '" << q->quoteType() <<
"' <> VolatilityMoneynessSurfaceConfig quoteType '" << vdsc.
quoteType() <<
"'");
855 vector<QuantLib::ext::shared_ptr<BaseStrike>>::iterator strikeIt;
860 [&q](QuantLib::ext::shared_ptr<BaseStrike> s) { return *s == *q->strike(); });
865 auto it = find(vc.
quotes().begin(), vc.
quotes().end(), q->name());
866 if (it == vc.
quotes().end())
872 [&q](QuantLib::ext::shared_ptr<BaseStrike> s) { return *s == *q->strike(); });
873 QL_REQUIRE(strikeIt !=
strikes.end(),
874 "EquityVolCurve: The quote '"
876 <<
"' is in the list of configured quotes but does not match any of the configured strikes");
880 Size pos = std::distance(
strikes.begin(), strikeIt);
884 QuantLib::ext::shared_ptr<Expiry> expiry =
parseExpiry(q->expiry());
885 if (
auto expiryDate = QuantLib::ext::dynamic_pointer_cast<ExpiryDate>(expiry)) {
886 eDate = expiryDate->expiryDate();
887 }
else if (
auto expiryPeriod = QuantLib::ext::dynamic_pointer_cast<ExpiryPeriod>(expiry)) {
889 eDate =
calendar_.adjust(asof + expiryPeriod->expiryPeriod());
893 if (surfaceData.count(eDate) == 0)
894 surfaceData[eDate] = vector<Real>(numStrikes, Null<Real>());
896 QL_REQUIRE(surfaceData[eDate][pos] == Null<Real>(),
897 "EquityVolCurve: Quote " << q->name() <<
" provides a duplicate quote for the date " << io::iso_date(eDate)
898 <<
" and strike " << *q->strike());
899 surfaceData[eDate][pos] = q->quote()->value();
902 TLOG(
"EquityVolCurve: Added quote " << q->name() <<
": (" << io::iso_date(eDate) <<
"," << *q->strike() <<
"," << fixed
903 << setprecision(9) <<
"," << q->quote()->value() <<
")");
906 DLOG(
"EquityVolCurve: EquityVolCurve: added " << quotesAdded <<
" quotes in building delta strike surface.");
911 for (
const auto& kv : surfaceData) {
912 for (Size j = 0; j < numStrikes; j++) {
913 QL_REQUIRE(kv.second[j] != Null<Real>(),
"EquityVolCurve: Volatility for expiry date "
914 << io::iso_date(kv.first) <<
" and strike " << *
strikes[j]
915 <<
" not found. Cannot proceed with a sparse matrix.");
921 QL_REQUIRE(vc.
quotes().size() == quotesAdded,
922 "EquityVolCurve: Found " << quotesAdded <<
" quotes, but " << vc.
quotes().size() <<
" quotes required by config.");
926 vector<Date> expiryDates;
927 Matrix vols(surfaceData.size(), numStrikes);
928 for (
const auto row : surfaceData | boost::adaptors::indexed(0)) {
929 expiryDates.push_back(row.value().first);
930 copy(row.value().second.begin(), row.value().second.end(), vols.row_begin(row.index()));
935 transform(putDeltas.begin(), putDeltas.end(), putDeltas.begin(), [](Real pd) { return -1.0 * pd; });
936 DLOG(
"EquityVolCurve: Multiply put deltas by -1.0 before creating BlackVolatilitySurfaceDelta object.");
937 DLOG(
"EquityVolCurve: Put deltas are: " << join(putDeltas | transformed([](Real d) {
return ore::data::to_string(d); }),
","));
941 bool flatExtrapolation =
true;
946 TLOG(
"EquityVolCurve: Strike extrapolation switched to using interpolator.");
947 flatExtrapolation =
false;
949 TLOG(
"EquityVolCurve: Strike extrapolation cannot be turned off on its own so defaulting to flat.");
951 TLOG(
"EquityVolCurve: Strike extrapolation has been set to flat.");
953 TLOG(
"EquityVolCurve: Strike extrapolation " << strikeExtrapType <<
" not expected so default to flat.");
958 TLOG(
"EquityVolCurve: BlackVolatilitySurfaceDelta only supports flat volatility extrapolation in the time direction");
961 TLOG(
"EquityVolCurve: Extrapolation is turned off for the whole surface so the time and"
962 <<
" strike extrapolation settings are ignored");
967 TLOG(
"EquityVolCurve: BlackVolatilitySurfaceDelta only supports linear time interpolation.");
973 im = InterpolatedSmileSection::InterpolationMethod::Linear;
975 im = InterpolatedSmileSection::InterpolationMethod::NaturalCubic;
977 im = InterpolatedSmileSection::InterpolationMethod::FinancialCubic;
979 im = InterpolatedSmileSection::InterpolationMethod::CubicSpline;
981 im = InterpolatedSmileSection::InterpolationMethod::Linear;
982 DLOG(
"EquityVolCurve: BlackVolatilitySurfaceDelta does not support strike interpolation '" << vdsc.
strikeInterpolation()
983 <<
"' so setting it to linear.");
987 if (!expiryDates.empty())
990 DLOG(
"EquityVolCurve: Creating BlackVolatilitySurfaceDelta object");
992 vol_ = QuantLib::ext::make_shared<BlackVolatilitySurfaceDelta>(
993 asof, expiryDates, putDeltas, callDeltas, hasAtm, vols,
dayCounter_,
calendar_, eqIndex->equitySpot(),
994 eqIndex->equityForecastCurve(), eqIndex->equityDividendCurve(), deltaType, atmType, atmDeltaType, 0 * Days,
995 deltaType, atmType, atmDeltaType, im, flatExtrapolation);
1000 DLOG(
"EquityVolCurve: finished building 2-D volatility delta strike surface");
1005 const map<
string, QuantLib::ext::shared_ptr<EquityCurve>>& eqCurves,
1006 const map<
string, QuantLib::ext::shared_ptr<EquityVolCurve>>& eqVolCurves,
1007 const map<
string, QuantLib::ext::shared_ptr<FXVolCurve>>& fxVolCurves,
1008 const map<
string, QuantLib::ext::shared_ptr<CorrelationCurve>>& requiredCorrelationCurves,
1009 const Market* fxIndices) {
1011 DLOG(
"EquityVolCurve: start building proxy vol surface");
1017 auto proxyConfig = *
curveConfigs.equityCurveConfig(proxy);
1018 auto proxyVolConfig = *
curveConfigs.equityVolCurveConfig(proxy);
1026 auto curve = eqCurves.find(eqSpec.
name());
1027 QL_REQUIRE(curve != eqCurves.end(),
"EquityVolCurve: Failed to find equity curve, when building equity vol curve " <<
spec.
name());
1028 auto proxyCurve = eqCurves.find(proxySpec.
name());
1029 QL_REQUIRE(proxyCurve != eqCurves.end(),
"EquityVolCurve: Failed to find equity curve for proxy "
1030 << proxySpec.
name() <<
", when building equity vol curve "
1032 auto proxyVolCurve = eqVolCurves.find(proxyVolSpec.
name());
1033 QL_REQUIRE(proxyVolCurve != eqVolCurves.end(),
"EquityVolCurve: Failed to find equity vol curve for proxy "
1034 << proxyVolSpec.
name() <<
", when building equity vol curve "
1039 QuantLib::ext::shared_ptr<BlackVolTermStructure> fxSurface;
1040 QuantLib::ext::shared_ptr<FxIndex> fxIndex;
1041 QuantLib::ext::shared_ptr<QuantExt::CorrelationTermStructure> correlation;
1042 if (config.ccy() != proxyVolConfig.ccy() && fxIndices !=
nullptr) {
1043 QL_REQUIRE(!epvc.
fxVolatilityCurve().empty(),
"EquityVolCurve: FXVolatilityCurve must be provided for Equity vol config " <<
1044 spec.
curveConfigID() <<
" as proxy currencies if different from equity currency.");
1045 QL_REQUIRE(!epvc.
correlationCurve().empty(),
"EquityVolCurve: CorrelationCurve must be provided for Equity vol config " <<
1046 spec.
curveConfigID() <<
" as proxy currencies if different from equity currency.");
1050 " for Equity vol config " <<
spec.
curveConfigID() <<
" must be of length 6, and of form CC1CCY2 e.g EURUSD");
1054 auto volIt = fxVolCurves.find(fxSpec.
name());
1055 if (volIt == fxVolCurves.end())
1056 QL_FAIL(
"EquityVolCurve: cannot find required Fx volatility surface " << fxSpec.
name() <<
" to build proxy vol surface for " << eqSpec.
name());
1057 fxSurface = volIt->second->volTermStructure();
1060 if (proxyVolForCcy != proxyVolConfig.ccy()) {
1061 Handle<BlackVolTermStructure> hFx(fxSurface);
1062 fxSurface = QuantLib::ext::make_shared<QuantExt::BlackInvertedVolTermStructure>(hFx);
1063 fxSurface->enableExtrapolation();
1066 fxIndex = fxIndices->
fxIndex(proxyVolConfig.ccy() + config.ccy()).currentLink();
1069 auto corrIt = requiredCorrelationCurves.find(corrSpec.
name());
1070 if (corrIt == requiredCorrelationCurves.end())
1071 QL_FAIL(
"EquityVolCurve: cannot find required correlation curve " << epvc.
correlationCurve() <<
" to build proxy vol surface for " << eqSpec.
name());
1072 correlation = corrIt->second->corrTermStructure();
1075 vol_ = QuantLib::ext::make_shared<BlackVolatilitySurfaceProxy>(proxyVolCurve->second->volTermStructure(), curve->second->equityIndex(),
1076 proxyCurve->second->equityIndex(), fxSurface, fxIndex, correlation);
1081 const Handle<EquityIndex2>& eqIndex) {
1083 DLOG(
"EquityVolCurve: Building calibration info for eq vol surface");
1091 std::vector<Real> moneyness = *rc.
moneyness();
1092 std::vector<std::string> deltas = *rc.
deltas();
1093 std::vector<Period> expiries = *rc.
expiries();
1095 calibrationInfo_ = QuantLib::ext::make_shared<FxEqCommVolCalibrationInfo>();
1097 DeltaVolQuote::AtmType atmType = DeltaVolQuote::AtmType::AtmDeltaNeutral;
1098 DeltaVolQuote::DeltaType deltaType = DeltaVolQuote::DeltaType::Fwd;
1100 if (
auto vdsc = QuantLib::ext::dynamic_pointer_cast<VolatilityDeltaSurfaceConfig>(
volatilityConfig_)) {
1115 std::vector<Real> times, forwards, rfDisc, divDisc;
1116 for (
auto const& p : expiries) {
1117 Date d =
vol_->optionDateFromTenor(p);
1119 times.push_back(
vol_->dayCounter().empty() ? Actual365Fixed().yearFraction(asof, d)
1120 :
vol_->timeFromReference(d));
1121 forwards.push_back(eqIndex->forecastFixing(d));
1122 rfDisc.push_back(eqIndex->equityForecastCurve()->discount(d));
1123 divDisc.push_back(eqIndex->equityDividendCurve()->discount(d));
1129 std::vector<std::vector<Real>> callPricesDelta(times.size(), std::vector<Real>(deltas.size(), 0.0));
1130 std::vector<std::vector<Real>> callPricesMoneyness(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1134 if (reportOnDeltaGrid) {
1137 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1139 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1141 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1143 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1145 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1147 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(deltas.size(),
true));
1149 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(deltas.size(),
true));
1150 TLOG(
"EquityVolCurve: Delta surface arbitrage analysis result (no calendar spread arbitrage included):");
1151 Real maxTime = QL_MAX_REAL;
1153 if (
vol_->dayCounter().empty())
1154 maxTime = Actual365Fixed().yearFraction(asof,
maxExpiry_);
1158 DeltaVolQuote::AtmType at;
1159 DeltaVolQuote::DeltaType dt;
1160 for (Size i = 0; i < times.size(); ++i) {
1167 at = DeltaVolQuote::AtmDeltaNeutral;
1168 dt = DeltaVolQuote::Fwd;
1170 bool validSlice =
true;
1171 for (Size j = 0; j < deltas.size(); ++j) {
1177 divDisc[i],
vol_, t);
1180 eqIndex->equitySpot()->value(), rfDisc[i], divDisc[i],
1185 rfDisc[i], divDisc[i],
vol_, t);
1187 Real stddev = std::sqrt(
vol_->blackVariance(t, strike));
1188 callPricesDelta[i][j] = blackFormula(Option::Call, strike, forwards[i], stddev);
1191 calibrationInfo_->deltaPutPrices[i][j] = blackFormula(Option::Put, strike, forwards[i], stddev, rfDisc[i]);
1193 calibrationInfo_->deltaCallPrices[i][j] = blackFormula(Option::Call, strike, forwards[i], stddev, rfDisc[i]);
1197 calibrationInfo_->deltaGridImpliedVolatility[i][j] = stddev / std::sqrt(t);
1198 }
catch (
const std::exception& e) {
1200 TLOG(
"EquityVolCurve: error for time " << t <<
" delta " << deltas[j] <<
": " << e.what());
1206 callPricesDelta[i]);
1213 }
catch (
const std::exception& e) {
1214 TLOG(
"error for time " << t <<
": " << e.what());
1223 TLOG(
"EquityVolCurve: Delta surface arbitrage analysis completed.");
1226 if (reportOnMoneynessGrid) {
1229 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1231 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1233 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1235 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1237 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1239 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(moneyness.size(),
true));
1241 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(moneyness.size(),
true));
1243 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(moneyness.size(),
true));
1244 for (Size i = 0; i < times.size(); ++i) {
1246 for (Size j = 0; j < moneyness.size(); ++j) {
1248 Real strike = moneyness[j] * forwards[i];
1250 Real stddev = std::sqrt(
vol_->blackVariance(t, strike));
1251 callPricesMoneyness[i][j] = blackFormula(Option::Call, strike, forwards[i], stddev);
1252 calibrationInfo_->moneynessGridImpliedVolatility[i][j] = stddev / std::sqrt(t);
1253 if (moneyness[j] >= 1) {
1254 calibrationInfo_->moneynessCallPrices[i][j] = blackFormula(Option::Call, strike, forwards[i], stddev, rfDisc[i]);
1256 calibrationInfo_->moneynessPutPrices[i][j] = blackFormula(Option::Put, strike, forwards[i], stddev, rfDisc[i]);
1258 }
catch (
const std::exception& e) {
1259 TLOG(
"EquityVolCurve: error for time " << t <<
" moneyness " << moneyness[j] <<
": " << e.what());
1263 if (!times.empty() && !moneyness.empty()) {
1266 callPricesMoneyness);
1267 for (Size i = 0; i < times.size(); ++i) {
1275 TLOG(
"EquityVolCurve: Moneyness surface Arbitrage analysis result:");
1277 }
catch (
const std::exception& e) {
1278 TLOG(
"EquityVolCurve: error: " << e.what());
1281 TLOG(
"EquityVolCurve: Moneyness surface Arbitrage analysis completed:");
1285 DLOG(
"EquityVolCurve: Building calibration info for eq vol surface completed.");
1287 }
catch (std::exception& e) {
1288 QL_FAIL(
"EquityVolCurve: calibration info building failed: " << e.what());
1290 QL_FAIL(
"EquityVolCurve: calibration info building failed: unknown error");
const std::vector< bool > & butterflyArbitrage() const
bool arbitrageFree() const
const std::vector< bool > & callSpreadArbitrage() const
const std::vector< Real > & density() const
const std::vector< std::vector< bool > > & butterflyArbitrage() const
bool arbitrageFree() const
const std::vector< std::vector< bool > > & calendarArbitrage() const
const std::vector< std::vector< bool > > & callSpreadArbitrage() const
const std::vector< CarrMadanMarginalProbability > & timeSlices() const
Correlation curve description.
virtual const vector< string > & quotes()
Return all the market quotes required for this config.
Container class for all Curve Configurations.
const std::string & curveConfigID() const
string name() const
returns the unique curve name
Utility class for handling delta strings ATM, 10P, 25C, ... used e.g. for FX Surfaces.
Equity curve description.
QuantLib::ext::shared_ptr< VolatilityConfig > volatilityConfig_
void buildCalibrationInfo(const QuantLib::Date &asof, const CurveConfigurations &curveConfigs, const EquityVolatilityCurveConfig &config, const Handle< QuantExt::EquityIndex2 > &eqIndex)
Build the calibration info.
QuantLib::ext::shared_ptr< FxEqCommVolCalibrationInfo > calibrationInfo_
QuantLib::Date maxExpiry_
QuantLib::ext::shared_ptr< BlackVolTermStructure > vol_
EquityVolCurve()
Default constructor.
QuantLib::Calendar calendar_
void buildVolatility(const QuantLib::Date &asof, const EquityVolatilityCurveConfig &vc, const ConstantVolatilityConfig &cvc, const Loader &loader)
Build a volatility structure from a single constant volatility quote.
const EquityVolatilityCurveSpec & spec() const
QuantLib::DayCounter dayCounter_
Equity volatility structure configuration.
const string & ccy() const
const string & equityId() const
const string & dayCounter() const
const ReportConfig & reportConfig() const
const string & calendar() const
Equity Volatility curve description.
FX Volatility curve description.
Market data loader base class.
virtual QuantLib::ext::shared_ptr< MarketDatum > get(const std::string &name, const QuantLib::Date &d) const
get quote by its unique name, throws if not existent, override in derived classes for performance
QuantLib::Handle< QuantExt::FxIndex > fxIndex(const string &fxIndex, const string &configuration=Market::defaultConfiguration) const
const std::string & correlationCurve() const
const std::string & fxVolatilityCurve() const
const std::string & proxyVolatilityCurve() const
const MarketDatum::QuoteType & quoteType() const
const boost::optional< bool > reportOnDeltaGrid() const
const boost::optional< std::vector< std::string > > & deltas() const
const boost::optional< bool > reportOnMoneynessGrid() const
const boost::optional< std::vector< Period > > & expiries() const
const boost::optional< std::vector< Real > > & moneyness() const
const std::string & deltaType() const
const std::vector< std::string > & putDeltas() const
const std::vector< std::string > & callDeltas() const
const std::vector< std::string > & expiries() const
const std::string & atmDeltaType() const
const std::string & atmType() const
const std::string & timeInterpolation() const
bool extrapolation() const
const std::string & strikeInterpolation() const
const std::string & strikeExtrapolation() const
const std::string & timeExtrapolation() const
Wrapper class for building Equity volatility structures.
Date getDateFromDateOrPeriod(const string &token, Date asof, QuantLib::Calendar cal, QuantLib::BusinessDayConvention bdc)
Get a date from a date string or period.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
QuantLib::Real convertMinorToMajorCurrency(const std::string &s, QuantLib::Real value)
Convert a value from a minor ccy to major.
DeltaVolQuote::AtmType parseAtmType(const std::string &s)
Convert text to QuantLib::DeltaVolQuote::AtmType.
Real parseReal(const string &s)
Convert text to Real.
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
DeltaVolQuote::DeltaType parseDeltaType(const std::string &s)
Convert text to QuantLib::DeltaVolQuote::DeltaType.
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
#define LOG(text)
Logging Macro (Level = Notice)
#define DLOG(text)
Logging Macro (Level = Debug)
#define TLOGGERSTREAM(text)
#define TLOG(text)
Logging Macro (Level = Data)
Real getAtmStrike(DeltaVolQuote::DeltaType dt, DeltaVolQuote::AtmType at, Real spot, Real domDiscount, Real forDiscount, boost::shared_ptr< BlackVolTermStructure > vol, Real t, Real accuracy, Size maxIterations)
std::string arbitrageAsString(const CarrMadanMarginalProbabilityClass &cm)
Real getStrikeFromDelta(Option::Type optionType, Real delta, DeltaVolQuote::DeltaType dt, Real spot, Real domDiscount, Real forDiscount, boost::shared_ptr< BlackVolTermStructure > vol, Real t, Real accuracy, Size maxIterations)
MoneynessStrike::Type parseMoneynessType(const string &type)
Parse MoneynessStrike::Type from type.
ReportConfig effectiveReportConfig(const ReportConfig &globalConfig, const ReportConfig &localConfig)
std::string to_string(const LocationInfo &l)
Extrapolation parseExtrapolation(const string &s)
Parse Extrapolation from string.
QuantLib::ext::shared_ptr< Expiry > parseExpiry(const string &strExpiry)
Parse an Expiry from its string representation, strExpiry.
boost::optional< Wildcard > getUniqueWildcard(const C &c)
checks if at most one element in C has a wild card and returns it in this case
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.
vector< string > curveConfigs
string conversion utilities
utilities for wildcard handling