Skip to content

Commit

Permalink
allow swaptions to take OvernightIndexedSwap (#1593)
Browse files Browse the repository at this point in the history
  • Loading branch information
lballabio authored Mar 28, 2024
2 parents d6f6c13 + 9b4efa3 commit 9ff0542
Show file tree
Hide file tree
Showing 22 changed files with 375 additions and 151 deletions.
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

0 comments on commit 9ff0542

Please sign in to comment.