Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow swaptions to take OvernightIndexedSwap #1593

Merged
merged 14 commits into from
Mar 28, 2024
1 change: 1 addition & 0 deletions Examples/BermudanSwaption/BermudanSwaption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
# include <ql/auto_link.hpp>
#endif
#include <ql/instruments/vanillaswap.hpp>
#include <ql/instruments/swaption.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
#include <ql/pricingengines/swaption/treeswaptionengine.hpp>
Expand Down
2 changes: 1 addition & 1 deletion ql/cashflows/overnightindexedcoupon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ namespace QuantLib {
overnightIndex,
gearing, spread,
refPeriodStart, refPeriodEnd,
dayCounter, false) {
dayCounter, false), averagingMethod_(averagingMethod) {

// value dates
Date tmpEndDate = endDate;
Expand Down
3 changes: 3 additions & 0 deletions ql/cashflows/overnightindexedcoupon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ namespace QuantLib {
const std::vector<Rate>& indexFixings() const;
//! value dates for the rates to be compounded
const std::vector<Date>& valueDates() const { return valueDates_; }
//! averaging method
const RateAveraging::Type averagingMethod() const { return averagingMethod_; }
//@}
//! \name FloatingRateCoupon interface
//@{
Expand All @@ -87,6 +89,7 @@ namespace QuantLib {
mutable std::vector<Rate> fixings_;
Size n_;
std::vector<Time> dt_;
RateAveraging::Type averagingMethod_;

Rate averageRate(const Date& date) const;
};
Expand Down
2 changes: 1 addition & 1 deletion ql/experimental/basismodels/swaptioncfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ namespace QuantLib {
floatWeights_.push_back(k->amount());
}

SwapCashFlows::SwapCashFlows(const ext::shared_ptr<VanillaSwap>& swap,
SwapCashFlows::SwapCashFlows(const ext::shared_ptr<FixedVsFloatingSwap>& swap,
const Handle<YieldTermStructure>& discountCurve,
bool contTenorSpread)
: IborLegCashFlows(swap->floatingLeg(), discountCurve, contTenorSpread) {
Expand Down
2 changes: 1 addition & 1 deletion ql/experimental/basismodels/swaptioncfs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ namespace QuantLib {
std::vector<Real> annuityWeights_;

public:
SwapCashFlows(const ext::shared_ptr<VanillaSwap>& swap,
SwapCashFlows(const ext::shared_ptr<FixedVsFloatingSwap>& swap,
const Handle<YieldTermStructure>& discountCurve,
bool contTenorSpread = true);
SwapCashFlows() = default;
Expand Down
13 changes: 7 additions & 6 deletions ql/experimental/basismodels/tenorswaptionvts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ FOR A PARTICULAR PURPOSE. See the license for more details.

#include <ql/experimental/basismodels/tenorswaptionvts.hpp>
#include <ql/experimental/basismodels/swaptioncfs.hpp>
#include <ql/instruments/vanillaswap.hpp>
#include <ql/exercise.hpp>
#include <ql/indexes/iborindex.hpp>
#include <ql/math/rounding.hpp>
Expand Down Expand Up @@ -60,15 +61,15 @@ namespace QuantLib {
volTS.baseIndex_->fixingCalendar(), ModifiedFollowing,
Unadjusted, DateGeneration::Backward, false);
// and swaps
ext::shared_ptr<VanillaSwap> baseSwap(new VanillaSwap(
auto baseSwap = ext::make_shared<VanillaSwap>(
Swap::Payer, 1.0, baseFixedSchedule, 1.0, volTS.baseFixedDC_, baseFloatSchedule,
volTS.baseIndex_, 0.0, volTS.baseIndex_->dayCounter()));
ext::shared_ptr<VanillaSwap> targSwap(new VanillaSwap(
volTS.baseIndex_, 0.0, volTS.baseIndex_->dayCounter());
auto targSwap = ext::make_shared<VanillaSwap>(
Swap::Payer, 1.0, baseFixedSchedule, 1.0, volTS.baseFixedDC_, targFloatSchedule,
volTS.targIndex_, 0.0, volTS.targIndex_->dayCounter()));
ext::shared_ptr<VanillaSwap> finlSwap(new VanillaSwap(
volTS.targIndex_, 0.0, volTS.targIndex_->dayCounter());
auto finlSwap = ext::make_shared<VanillaSwap>(
Swap::Payer, 1.0, finlFixedSchedule, 1.0, volTS.targFixedDC_, targFloatSchedule,
volTS.targIndex_, 0.0, volTS.targIndex_->dayCounter()));
volTS.targIndex_, 0.0, volTS.targIndex_->dayCounter());
// adding engines
baseSwap->setPricingEngine(
ext::shared_ptr<PricingEngine>(new DiscountingSwapEngine(volTS.discountCurve_)));
Expand Down
81 changes: 58 additions & 23 deletions ql/instruments/makeswaption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <ql/cashflows/cashflows.hpp>
#include <ql/exercise.hpp>
#include <ql/indexes/swapindex.hpp>
#include <ql/instruments/makeois.hpp>
#include <ql/instruments/makeswaption.hpp>
#include <ql/instruments/makevanillaswap.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
Expand Down Expand Up @@ -71,39 +72,73 @@ namespace QuantLib {
EuropeanExercise(exerciseDate_));
}

Rate usedStrike = strike_;
Rate usedStrike;
ext::shared_ptr<OvernightIndexedSwapIndex> OIswap_index = ext::dynamic_pointer_cast<OvernightIndexedSwapIndex>(swapIndex_);
if (strike_ == Null<Rate>()) {
// ATM on curve(s) attached to index
QL_REQUIRE(!swapIndex_->forwardingTermStructure().empty(),
"null term structure set to this instance of " <<
swapIndex_->name());
ext::shared_ptr<VanillaSwap> temp =
swapIndex_->underlyingSwap(fixingDate_);
temp->setPricingEngine(
ext::shared_ptr<PricingEngine>(new DiscountingSwapEngine(
swapIndex_->exogenousDiscount()
if (OIswap_index) {
auto temp = OIswap_index->underlyingSwap(fixingDate_);
temp->setPricingEngine(
ext::make_shared<DiscountingSwapEngine>(
swapIndex_->exogenousDiscount()
? swapIndex_->discountingTermStructure()
: swapIndex_->forwardingTermStructure(),
false)));
usedStrike = temp->fairRate();
false
)
);
usedStrike = temp->fairRate();
} else {
auto temp = swapIndex_->underlyingSwap(fixingDate_);
temp->setPricingEngine(
ext::make_shared<DiscountingSwapEngine>(
swapIndex_->exogenousDiscount()
? swapIndex_->discountingTermStructure()
: swapIndex_->forwardingTermStructure(),
false
)
);
usedStrike = temp->fairRate();
}
} else {
usedStrike = strike_;
}

BusinessDayConvention bdc = swapIndex_->fixedLegConvention();
underlyingSwap_ =
MakeVanillaSwap(swapIndex_->tenor(),
swapIndex_->iborIndex(), usedStrike)
.withEffectiveDate(swapIndex_->valueDate(fixingDate_))
.withFixedLegCalendar(swapIndex_->fixingCalendar())
.withFixedLegDayCount(swapIndex_->dayCounter())
.withFixedLegTenor(swapIndex_->fixedLegTenor())
.withFixedLegConvention(bdc)
.withFixedLegTerminationDateConvention(bdc)
.withType(underlyingType_)
.withNominal(nominal_)
.withIndexedCoupons(useIndexedCoupons_);

ext::shared_ptr<Swaption> swaption(new Swaption(
underlyingSwap_, exercise_, delivery_, settlementMethod_));
if (OIswap_index) {
underlyingSwap_ =
(ext::shared_ptr<OvernightIndexedSwap>)(
MakeOIS(swapIndex_->tenor(),
OIswap_index->overnightIndex(), usedStrike)
.withEffectiveDate(swapIndex_->valueDate(fixingDate_))
.withPaymentCalendar(swapIndex_->fixingCalendar())
.withFixedLegDayCount(swapIndex_->dayCounter())
.withPaymentAdjustment(bdc)
.withFixedLegConvention(bdc)
.withFixedLegTerminationDateConvention(bdc)
.withType(underlyingType_)
.withNominal(nominal_)
);
} else {
underlyingSwap_ =
(ext::shared_ptr<VanillaSwap>)(
MakeVanillaSwap(swapIndex_->tenor(),
swapIndex_->iborIndex(), usedStrike)
.withEffectiveDate(swapIndex_->valueDate(fixingDate_))
.withFixedLegCalendar(swapIndex_->fixingCalendar())
.withFixedLegDayCount(swapIndex_->dayCounter())
.withFixedLegTenor(swapIndex_->fixedLegTenor())
.withFixedLegConvention(bdc)
.withFixedLegTerminationDateConvention(bdc)
.withType(underlyingType_)
.withNominal(nominal_)
.withIndexedCoupons(useIndexedCoupons_)
);
}
ext::shared_ptr<Swaption> swaption = ext::make_shared<Swaption>(
underlyingSwap_, exercise_, delivery_, settlementMethod_);
swaption->setPricingEngine(engine_);
return swaption;
}
Expand Down
2 changes: 1 addition & 1 deletion ql/instruments/makeswaption.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ namespace QuantLib {
ext::shared_ptr<SwapIndex> swapIndex_;
Settlement::Type delivery_;
Settlement::Method settlementMethod_;
mutable ext::shared_ptr<VanillaSwap> underlyingSwap_;
mutable ext::shared_ptr<FixedVsFloatingSwap> underlyingSwap_;

Period optionTenor_;
BusinessDayConvention optionConvention_;
Expand Down
2 changes: 1 addition & 1 deletion ql/instruments/nonstandardswap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

namespace QuantLib {

NonstandardSwap::NonstandardSwap(const VanillaSwap &fromVanilla)
NonstandardSwap::NonstandardSwap(const FixedVsFloatingSwap &fromVanilla)
: Swap(2), type_(fromVanilla.type()),
fixedNominal_(std::vector<Real>(fromVanilla.fixedLeg().size(),
fromVanilla.nominal())),
Expand Down
4 changes: 2 additions & 2 deletions ql/instruments/nonstandardswap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#define quantlib_nonstandard_swap_hpp

#include <ql/instruments/swap.hpp>
#include <ql/instruments/vanillaswap.hpp>
#include <ql/instruments/fixedvsfloatingswap.hpp>
#include <ql/time/daycounter.hpp>
#include <ql/time/schedule.hpp>
#include <ql/optional.hpp>
Expand All @@ -42,7 +42,7 @@ namespace QuantLib {
class arguments;
class results;
class engine;
NonstandardSwap(const VanillaSwap &fromVanilla);
explicit NonstandardSwap(const FixedVsFloatingSwap &fromVanilla);
NonstandardSwap(Swap::Type type,
std::vector<Real> fixedNominal,
const std::vector<Real>& floatingNominal,
Expand Down
10 changes: 4 additions & 6 deletions ql/instruments/swaption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ namespace QuantLib {
}
}

Swaption::Swaption(ext::shared_ptr<VanillaSwap> swap,
Swaption::Swaption(ext::shared_ptr<FixedVsFloatingSwap> swap,
const ext::shared_ptr<Exercise>& exercise,
Settlement::Type delivery,
Settlement::Method settlementMethod)
Expand Down Expand Up @@ -160,7 +160,6 @@ namespace QuantLib {
void Swaption::setupArguments(PricingEngine::arguments* args) const {

swap_->setupArguments(args);

auto* arguments = dynamic_cast<Swaption::arguments*>(args);

QL_REQUIRE(arguments != nullptr, "wrong argument type");
Expand All @@ -172,11 +171,10 @@ namespace QuantLib {
}

void Swaption::arguments::validate() const {
VanillaSwap::arguments::validate();
QL_REQUIRE(swap, "vanilla swap not set");
FixedVsFloatingSwap::arguments::validate();
QL_REQUIRE(swap, "swap not set");
QL_REQUIRE(exercise, "exercise not set");
Settlement::checkTypeAndMethodConsistency(settlementType,
settlementMethod);
Settlement::checkTypeAndMethodConsistency(settlementType, settlementMethod);
}

Volatility Swaption::impliedVolatility(Real targetValue,
Expand Down
18 changes: 12 additions & 6 deletions ql/instruments/swaption.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#define quantlib_instruments_swaption_hpp

#include <ql/option.hpp>
#include <ql/instruments/vanillaswap.hpp>
#include <ql/instruments/fixedvsfloatingswap.hpp>
#include <ql/termstructures/yieldtermstructure.hpp>
#include <ql/termstructures/volatility/volatilitytype.hpp>

Expand Down Expand Up @@ -59,6 +59,12 @@ namespace QuantLib {
//! %Swaption class
/*! \ingroup instruments

\warning it's possible to pass an overnight-indexed swap to
the constructor, but the only engine to fully support
it is BlackSwaptionEngine; other engines will treat
it as a vanilla swap. This is at best a decent
proxy, at worst simply wrong. Use with caution.

\test
- the correctness of the returned value is tested by checking
that the price of a payer (resp. receiver) swaption
Expand All @@ -82,7 +88,7 @@ namespace QuantLib {
public:
class arguments;
class engine;
Swaption(ext::shared_ptr<VanillaSwap> swap,
Swaption(ext::shared_ptr<FixedVsFloatingSwap> swap,
const ext::shared_ptr<Exercise>& exercise,
Settlement::Type delivery = Settlement::Physical,
Settlement::Method settlementMethod = Settlement::PhysicalOTC);
Expand All @@ -102,7 +108,7 @@ namespace QuantLib {
return settlementMethod_;
}
Swap::Type type() const { return swap_->type(); }
const ext::shared_ptr<VanillaSwap>& underlyingSwap() const {
const ext::shared_ptr<FixedVsFloatingSwap>& underlyingSwap() const {
return swap_;
}
//@}
Expand All @@ -119,18 +125,18 @@ namespace QuantLib {
Real displacement = 0.0) const;
private:
// arguments
ext::shared_ptr<VanillaSwap> swap_;
ext::shared_ptr<FixedVsFloatingSwap> swap_;
//Handle<YieldTermStructure> termStructure_;
Settlement::Type settlementType_;
Settlement::Method settlementMethod_;
};

//! %Arguments for swaption calculation
class Swaption::arguments : public VanillaSwap::arguments,
class Swaption::arguments : public FixedVsFloatingSwap::arguments,
public Option::arguments {
public:
arguments() = default;
ext::shared_ptr<VanillaSwap> swap;
ext::shared_ptr<FixedVsFloatingSwap> swap;
Settlement::Type settlementType = Settlement::Physical;
Settlement::Method settlementMethod;
void validate() const override;
Expand Down
17 changes: 8 additions & 9 deletions ql/legacy/libormarketmodels/lfmswaptionengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ namespace QuantLib {

static const Spread basisPoint = 1.0e-4;

VanillaSwap swap = *arguments_.swap;
swap.setPricingEngine(ext::shared_ptr<PricingEngine>(
new DiscountingSwapEngine(discountCurve_, false)));
auto swap = arguments_.swap;
swap->setPricingEngine(ext::shared_ptr<PricingEngine>(
new DiscountingSwapEngine(discountCurve_, false)));

Spread correction = swap.spread() *
std::fabs(swap.floatingLegBPS()/swap.fixedLegBPS());
Rate fixedRate = swap.fixedRate() - correction;
Rate fairRate = swap.fairRate() - correction;
Spread correction = swap->spread() *
std::fabs(swap->floatingLegBPS()/swap->fixedLegBPS());
Rate fixedRate = swap->fixedRate() - correction;
Rate fairRate = swap->fairRate() - correction;

ext::shared_ptr<SwaptionVolatilityMatrix> volatility =
model_->getSwaptionVolatilityMatrix();
Expand All @@ -65,9 +65,8 @@ namespace QuantLib {
Option::Type w = arguments_.type==Swap::Payer ? Option::Call : Option::Put;
Volatility vol = volatility->volatility(exercise, swapLength,
fairRate, true);
results_.value = (swap.fixedLegBPS()/basisPoint) *
results_.value = (swap->fixedLegBPS()/basisPoint) *
blackFormula(w, fixedRate, fairRate, vol*std::sqrt(exercise));
}

}

Loading
Loading