Skip to content

Commit 338b5f2

Browse files
mgronckiGitlab CI
authored andcommitted
Merge branch 'feature/QPR-13720' into 'master'
QPR-13720 introduce new optional product type for caps modelled as swaps Closes QPR-13720 See merge request qs/oreplus!3187
1 parent c8ec915 commit 338b5f2

2 files changed

Lines changed: 19 additions & 29 deletions

File tree

OREData/ored/portfolio/builders/swap.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class SwapEngineBuilderBase : public CachingPricingEngineBuilder<string, const C
4848
const std::string&, const std::set<std::string>&> {
4949
public:
5050
SwapEngineBuilderBase(const std::string& model, const std::string& engine)
51-
: CachingEngineBuilder(model, engine, {"Swap"}) {}
51+
: CachingEngineBuilder(model, engine, {"Swap", "CapFloor_as_Swap"}) {}
5252

5353
protected:
5454
virtual string keyImpl(const Currency& ccy, const std::string& discountCurve, const std::string& securitySpread,

OREData/ored/portfolio/capfloor.cpp

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ void CapFloor::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFacto
8484

8585
std::set<std::tuple<std::set<std::string>, std::string, std::string>> productModelEngines;
8686

87+
QuantLib::ext::shared_ptr<SwapEngineBuilderBase> swapBuilder;
88+
if (engineFactory->engineData()->hasProduct("CapFloor_as_Swap")) {
89+
swapBuilder = QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(engineFactory->builder("CapFloor_as_Swap"));
90+
} else if(engineFactory->engineData()->hasProduct("Swap")) {
91+
swapBuilder = QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(engineFactory->builder("Swap"));
92+
}
93+
8794
if (legData_.legType() == LegType::Floating) {
8895

8996
QuantLib::ext::shared_ptr<FloatingLegData> floatData =
@@ -133,11 +140,7 @@ void CapFloor::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFacto
133140
// and a short cap while we have documented a collar to be a short floor and long cap
134141
qlInstrument =
135142
QuantLib::ext::make_shared<QuantLib::Swap>(legs_, std::vector<bool>{!floors_.empty() && !caps_.empty()});
136-
if (engineFactory->engineData()->hasProduct("Swap")) {
137-
builder = engineFactory->builder("Swap");
138-
QuantLib::ext::shared_ptr<SwapEngineBuilderBase> swapBuilder =
139-
QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
140-
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
143+
if (swapBuilder) {
141144
qlInstrument->setPricingEngine(
142145
swapBuilder->engine(parseCurrency(legData_.currency()), std::string(), std::string(), {}));
143146
setSensitivityTemplate(*swapBuilder);
@@ -191,14 +194,13 @@ void CapFloor::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFacto
191194
}
192195

193196
} else if (legData_.legType() == LegType::CMS) {
194-
builder = engineFactory->builder("Swap");
195197

196198
QuantLib::ext::shared_ptr<CMSLegData> cmsData = QuantLib::ext::dynamic_pointer_cast<CMSLegData>(legData_.concreteLegData());
197199
QL_REQUIRE(cmsData, "Wrong LegType, expected CMS");
198200

199201
underlyingIndex = cmsData->swapIndex();
200202
Handle<SwapIndex> hIndex =
201-
engineFactory->market()->swapIndex(underlyingIndex, builder->configuration(MarketContext::pricing));
203+
engineFactory->market()->swapIndex(underlyingIndex, swapBuilder->configuration(MarketContext::pricing));
202204
QL_REQUIRE(!hIndex.empty(), "Could not find swap index " << underlyingIndex << " in market.");
203205

204206
QuantLib::ext::shared_ptr<SwapIndex> index = hIndex.currentLink();
@@ -220,18 +222,14 @@ void CapFloor::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFacto
220222
// the StrippedCappedFlooredCoupon used to extract the naked options assumes a long floor
221223
// and a short cap while we have documented a collar to be a short floor and long cap
222224
qlInstrument = QuantLib::ext::make_shared<QuantLib::Swap>(legs_, std::vector<bool>{!floors_.empty() && !caps_.empty()});
223-
if (engineFactory->engineData()->hasProduct("Swap")) {
224-
builder = engineFactory->builder("Swap");
225-
QuantLib::ext::shared_ptr<SwapEngineBuilderBase> swapBuilder =
226-
QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
227-
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
225+
if (swapBuilder) {
228226
qlInstrument->setPricingEngine(
229227
swapBuilder->engine(parseCurrency(legData_.currency()), std::string(), std::string(), {}));
230228
setSensitivityTemplate(*swapBuilder);
231229
addProductModelEngine(*swapBuilder);
232230
} else {
233-
qlInstrument->setPricingEngine(
234-
QuantLib::ext::make_shared<DiscountingSwapEngine>(engineFactory->market()->discountCurve(legData_.currency())));
231+
qlInstrument->setPricingEngine(QuantLib::ext::make_shared<DiscountingSwapEngine>(
232+
engineFactory->market()->discountCurve(legData_.currency())));
235233
}
236234
maturity_ = CashFlows::maturityDate(legs_.front());
237235
maturityType_ = "Leg Maturity Date";
@@ -256,18 +254,14 @@ void CapFloor::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFacto
256254
// the StrippedCappedFlooredCoupon used to extract the naked options assumes a long floor
257255
// and a short cap while we have documented a collar to be a short floor and long cap
258256
qlInstrument = QuantLib::ext::make_shared<QuantLib::Swap>(legs_, std::vector<bool>{!floors_.empty() && !caps_.empty()});
259-
if (engineFactory->engineData()->hasProduct("Swap")) {
260-
builder = engineFactory->builder("Swap");
261-
QuantLib::ext::shared_ptr<SwapEngineBuilderBase> swapBuilder =
262-
QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
263-
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
257+
if (swapBuilder) {
264258
qlInstrument->setPricingEngine(
265259
swapBuilder->engine(parseCurrency(legData_.currency()), std::string(), std::string(), {}));
266260
setSensitivityTemplate(*swapBuilder);
267261
addProductModelEngine(*swapBuilder);
268262
} else {
269-
qlInstrument->setPricingEngine(
270-
QuantLib::ext::make_shared<DiscountingSwapEngine>(engineFactory->market()->discountCurve(legData_.currency())));
263+
qlInstrument->setPricingEngine(QuantLib::ext::make_shared<DiscountingSwapEngine>(
264+
engineFactory->market()->discountCurve(legData_.currency())));
271265
}
272266
maturity_ = CashFlows::maturityDate(legs_.front());
273267
} else if (legData_.legType() == LegType::CMSSpread) {
@@ -292,18 +286,14 @@ void CapFloor::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFacto
292286
// the StrippedCappedFlooredCoupon used to extract the naked options assumes a long floor
293287
// and a short cap while we have documented a collar to be a short floor and long cap
294288
qlInstrument = QuantLib::ext::make_shared<QuantLib::Swap>(legs_, std::vector<bool>{!floors_.empty() && !caps_.empty()});
295-
if (engineFactory->engineData()->hasProduct("Swap")) {
296-
builder = engineFactory->builder("Swap");
297-
QuantLib::ext::shared_ptr<SwapEngineBuilderBase> swapBuilder =
298-
QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
299-
QL_REQUIRE(swapBuilder, "No Builder found for Swap " << id());
289+
if (swapBuilder) {
300290
qlInstrument->setPricingEngine(
301291
swapBuilder->engine(parseCurrency(legData_.currency()), std::string(), std::string(), {}));
302292
setSensitivityTemplate(*swapBuilder);
303293
addProductModelEngine(*swapBuilder);
304294
} else {
305-
qlInstrument->setPricingEngine(
306-
QuantLib::ext::make_shared<DiscountingSwapEngine>(engineFactory->market()->discountCurve(legData_.currency())));
295+
qlInstrument->setPricingEngine(QuantLib::ext::make_shared<DiscountingSwapEngine>(
296+
engineFactory->market()->discountCurve(legData_.currency())));
307297
}
308298
maturity_ = CashFlows::maturityDate(legs_.front());
309299
maturityType_ = "Leg Maturity Date";

0 commit comments

Comments
 (0)