500 {
501
502 calculate();
503
504
505
506 t = std::max(t, 1.0 / 365.0);
507
509
510
511
514 return s->second->volatility(strike);
515 }
516
517
518
519
521 Size index_m = index_p == 0 ? Null<Size>() : index_p - 1;
523 index_p = Null<Size>();
524
525
526
527 while (index_m != Null<Size>() && index_m > 0 &&
smileHasError_[index_m])
528 --index_m;
529
531 ++index_p;
532
534 index_m = Null<Size>();
535
537 index_p = Null<Size>();
538
539 if (index_m == Null<Size>() && index_p == Null<Size>()) {
540
541
542
544 QL_FAIL("BlackVolatilitySurfaceBFRR::blackVolImpl(" << t << "," << strike
545 << "): no valid smiles, check the market data input.");
546 }
547
551 }
552
553
554
555 if (index_m != Null<Size>() &&
smiles_[index_m] ==
nullptr) {
556 DeltaVolQuote::AtmType at;
557 DeltaVolQuote::DeltaType dt;
561 } else {
564 }
565 try {
571 } catch (const std::exception& e) {
575 }
576 }
577
578 if (index_p != Null<Size>() &&
smiles_[index_p] ==
nullptr) {
579 DeltaVolQuote::AtmType at;
580 DeltaVolQuote::DeltaType dt;
584 } else {
587 }
588 try {
594 } catch (const std::exception& e) {
598 }
599 }
600
601
602
603
604
605 DeltaVolQuote::DeltaType dt_c =
606 dt_ == (DeltaVolQuote::Spot ||
dt_ == DeltaVolQuote::Fwd) ? DeltaVolQuote::Fwd : DeltaVolQuote::PaFwd;
607 DeltaVolQuote::AtmType at_c = DeltaVolQuote::AtmDeltaNeutral;
608
609
610
611 Real atmVol_m = 0.0, atmVol_p = 0.0;
612 std::vector<Real> putVols_m, callVols_m, putVols_p, callVols_p;
613
614 if (index_m != Null<Size>()) {
615 try {
616 atmVol_m =
smiles_[index_m]->volatility(
smiles_[index_m]->atmStrike(dt_c, at_c));
618 putVols_m.push_back(
619 smiles_[index_m]->volatility(
smiles_[index_m]->strikeFromDelta(Option::Put, d, dt_c)));
620 callVols_m.push_back(
621 smiles_[index_m]->volatility(
smiles_[index_m]->strikeFromDelta(Option::Call, d, dt_c)));
622 }
623 } catch (const std::exception& e) {
627 }
628 }
629
630 if (index_p != Null<Size>()) {
631 try {
632 atmVol_p =
smiles_[index_p]->volatility(
smiles_[index_p]->atmStrike(dt_c, at_c));
634 putVols_p.push_back(
635 smiles_[index_p]->volatility(
smiles_[index_p]->strikeFromDelta(Option::Put, d, dt_c)));
636 callVols_p.push_back(
637 smiles_[index_p]->volatility(
smiles_[index_p]->strikeFromDelta(Option::Call, d, dt_c)));
638 }
639 } catch (const std::exception& e) {
643 }
644 }
645
646
647
648 Real atmVol_i;
649 std::vector<Real> putVols_i, callVols_i;
650
651 if (index_p == Null<Size>()) {
652
653 atmVol_i = atmVol_m;
654 putVols_i = putVols_m;
655 callVols_i = callVols_m;
656 QL_REQUIRE(atmVol_i > 0.0, "BlackVolatilitySurfaceBFRR: negative front-extrapolated atm vol " << atmVol_i);
658 QL_REQUIRE(putVols_i[i] > 0.0,
659 "BlackVolatilitySurfaceBFRR: negative front-extrapolated put vol " << putVols_i[i]);
660 QL_REQUIRE(callVols_i[i] > 0.0,
661 "BlackVolatilitySurfaceBFRR: negative front-extrapolated call vol " << callVols_i[i]);
662 }
663 } else if (index_m == Null<Size>()) {
664
665 atmVol_i = atmVol_p;
666 putVols_i = putVols_p;
667 callVols_i = callVols_p;
668 QL_REQUIRE(atmVol_i > 0.0, "BlackVolatilitySurfaceBFRR: negative back-extrapolated atm vol " << atmVol_i);
670 QL_REQUIRE(putVols_i[i] > 0.0,
671 "BlackVolatilitySurfaceBFRR: negative back-extrapolated put vol " << putVols_i[i]);
672 QL_REQUIRE(callVols_i[i] > 0.0,
673 "BlackVolatilitySurfaceBFRR: negative back-extrapolated call vol " << callVols_i[i]);
674 }
675 } else {
676
678 atmVol_i = (1.0 - a) * atmVol_m + a * atmVol_p;
679 QL_REQUIRE(atmVol_i > 0.0, "BlackVolatilitySurfaceBFRR: negative atm vol "
680 << atmVol_i << " = " << (1.0 - a) << " * " << atmVol_m << " + " << a << " * "
681 << atmVol_p);
683 putVols_i.push_back((1.0 - a) * putVols_m[i] + a * putVols_p[i]);
684 callVols_i.push_back((1.0 - a) * callVols_m[i] + a * callVols_p[i]);
685 QL_REQUIRE(putVols_i.back() > 0.0, "BlackVolatilitySurfaceBFRR: negative put vol for delta="
687 << (1.0 - a) << " * " << putVols_m[i] << " + " << a << " * "
688 << putVols_p[i]);
689 QL_REQUIRE(callVols_i.back() > 0.0, "BlackVolatilitySurfaceBFRR: negative call vol for delta="
691 << (1.0 - a) << " * " << callVols_m[i] << " + " << a << " * "
692 << callVols_p[i]);
693 }
694 }
695
696
697
698
699
700
701
702
703
704 QuantLib::ext::shared_ptr<detail::SimpleDeltaInterpolatedSmile> smile;
705
706 try {
707 smile = QuantLib::ext::make_shared<detail::SimpleDeltaInterpolatedSmile>(
711 } catch (const std::exception& e) {
712
713
714 Size failureIndex = index_m != Null<Size>() ? index_m : index_p;
718 }
719
720
721
723
724
725
726 return smile->volatility(strike);
727}
std::vector< Date > settlementDates_
std::map< Real, QuantLib::ext::shared_ptr< detail::SimpleDeltaInterpolatedSmile > > cachedInterpolatedSmiles_
std::vector< Real > expiryTimes_
Volatility blackVolImpl(Time t, Real strike) const override
std::vector< QuantLib::ext::shared_ptr< detail::SimpleDeltaInterpolatedSmile > > smiles_
QuantLib::ext::shared_ptr< SimpleDeltaInterpolatedSmile > createSmile(const Real spot, const Real domDisc, const Real forDisc, const Real expiryTime, const std::vector< Real > &deltas, const std::vector< Real > &bfQuotes, const std::vector< Real > &rrQuotes, const Real atmVol, const DeltaVolQuote::DeltaType dt, const DeltaVolQuote::AtmType at, const Option::Type riskReversalInFavorOf, const bool butterflyIsBrokerStyle, const BlackVolatilitySurfaceBFRR::SmileInterpolation smileInterpolation)