Skip to content

Commit 268fe54

Browse files
pcaspersjenkins
authored andcommitted
QPR-11772 update cf report, refactor a bit too
1 parent 4b75f5c commit 268fe54

1 file changed

Lines changed: 55 additions & 43 deletions

File tree

OREAnalytics/orea/app/reportwriter.cpp

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,33 @@
1919
*/
2020

2121
#include <orea/app/reportwriter.hpp>
22-
23-
// FIXME: including all is slow and bad
24-
#include <boost/range/adaptor/indexed.hpp>
25-
#include <boost/lexical_cast.hpp>
2622
#include <orea/orea.hpp>
23+
2724
#include <ored/ored.hpp>
2825
#include <ored/portfolio/structuredtradeerror.hpp>
29-
#include <ostream>
30-
#include <ql/cashflows/averagebmacoupon.hpp>
31-
#include <ql/cashflows/indexedcashflow.hpp>
32-
#include <ql/cashflows/inflationcoupon.hpp>
26+
27+
#include <qle/cashflows/cappedflooredaveragebmacoupon.hpp>
3328
#include <qle/cashflows/commodityindexedcashflow.hpp>
3429
#include <qle/cashflows/commodityindexedaveragecashflow.hpp>
35-
#include <ql/errors.hpp>
36-
#include <ql/experimental/coupons/strippedcapflooredcoupon.hpp>
3730
#include <qle/cashflows/averageonindexedcoupon.hpp>
3831
#include <qle/cashflows/fxlinkedcashflow.hpp>
3932
#include <qle/cashflows/overnightindexedcoupon.hpp>
4033
#include <qle/cashflows/indexedcoupon.hpp>
4134
#include <qle/cashflows/equitycoupon.hpp>
4235
#include <qle/currencies/currencycomparator.hpp>
4336
#include <qle/instruments/cashflowresults.hpp>
44-
#include <stdio.h>
4537

38+
#include <ql/cashflows/averagebmacoupon.hpp>
39+
#include <ql/cashflows/indexedcashflow.hpp>
40+
#include <ql/cashflows/inflationcoupon.hpp>
41+
#include <ql/errors.hpp>
42+
#include <ql/experimental/coupons/strippedcapflooredcoupon.hpp>
43+
44+
#include <boost/range/adaptor/indexed.hpp>
45+
#include <boost/lexical_cast.hpp>
46+
47+
#include <ostream>
48+
#include <stdio.h>
4649

4750
using ore::data::to_string;
4851
using QuantLib::Date;
@@ -207,15 +210,18 @@ void ReportWriter::writeCashflow(ore::data::Report& report, const std::string& b
207210
if (payer)
208211
amount *= -1.0;
209212
std::string ccy = trade->legCurrencies()[i];
213+
210214
boost::shared_ptr<QuantLib::Coupon> ptrCoupon =
211215
boost::dynamic_pointer_cast<QuantLib::Coupon>(ptrFlow);
212216
boost::shared_ptr<QuantExt::CommodityCashFlow> ptrCommCf =
213217
boost::dynamic_pointer_cast<QuantExt::CommodityCashFlow>(ptrFlow);
218+
214219
Real coupon;
215220
Real accrual;
216221
Real notional;
217222
Date accrualStartDate, accrualEndDate;
218223
Real accruedAmount;
224+
219225
if (ptrCoupon) {
220226
coupon = ptrCoupon->rate();
221227
accrual = ptrCoupon->accrualPeriod();
@@ -229,7 +235,8 @@ void ReportWriter::writeCashflow(ore::data::Report& report, const std::string& b
229235
} else if (ptrCommCf) {
230236
coupon = Null<Real>();
231237
accrual = Null<Real>();
232-
notional = ptrCommCf->periodQuantity(); // this is measured in units, e.g. barrels for oil
238+
notional =
239+
ptrCommCf->periodQuantity(); // this is measured in units, e.g. barrels for oil
233240
accrualStartDate = accrualEndDate = Null<Date>();
234241
accruedAmount = Null<Real>();
235242
flowType = "Notional (units)";
@@ -241,16 +248,11 @@ void ReportWriter::writeCashflow(ore::data::Report& report, const std::string& b
241248
accruedAmount = Null<Real>();
242249
flowType = "Notional";
243250
}
244-
// This BMA part here (and below) is necessary because the fixingDay() method of
245-
// AverageBMACoupon returns an exception rather than the last fixing day of the period.
246251

247-
boost::shared_ptr<QuantLib::Coupon> cpn =
248-
boost::dynamic_pointer_cast<QuantLib::Coupon>(ptrFlow);
249-
if (cpn) {
252+
if (auto cpn = boost::dynamic_pointer_cast<QuantLib::Coupon>(ptrFlow)) {
250253
ptrFlow = unpackIndexedCoupon(cpn);
251254
}
252-
boost::shared_ptr<AverageBMACoupon> ptrBMA =
253-
boost::dynamic_pointer_cast<QuantLib::AverageBMACoupon>(ptrFlow);
255+
254256
boost::shared_ptr<QuantLib::FloatingRateCoupon> ptrFloat =
255257
boost::dynamic_pointer_cast<QuantLib::FloatingRateCoupon>(ptrFlow);
256258
boost::shared_ptr<QuantLib::InflationCoupon> ptrInfl =
@@ -261,44 +263,47 @@ void ReportWriter::writeCashflow(ore::data::Report& report, const std::string& b
261263
boost::dynamic_pointer_cast<QuantExt::FXLinkedCashFlow>(ptrFlow);
262264
boost::shared_ptr<QuantExt::EquityCoupon> ptrEqCp =
263265
boost::dynamic_pointer_cast<QuantExt::EquityCoupon>(ptrFlow);
266+
264267
Date fixingDate;
265268
Real fixingValue = Null<Real>();
266-
if (ptrBMA) {
267-
// We return the last fixing inside the coupon period
268-
fixingDate = ptrBMA->fixingDates().end()[-2];
269-
fixingValue = ptrBMA->pricer()->swapletRate();
270-
if (fixingDate > asof)
271-
flowType = "BMAaverage";
272-
} else if (ptrFloat) {
269+
if (ptrFloat) {
273270
fixingDate = ptrFloat->fixingDate();
271+
if (fixingDate > asof)
272+
flowType = "InterestProjected";
273+
274274
try {
275275
fixingValue = ptrFloat->index()->fixing(fixingDate);
276276
} catch (...) {
277-
// catch invalid fixing date, missing fixing, etc. and fall through with
278-
// fixingValue = Null (which appears as NA in the report)
279277
}
280-
if (fixingDate > asof)
281-
flowType = "InterestProjected";
278+
282279
if (auto c = boost::dynamic_pointer_cast<QuantLib::IborCoupon>(ptrFloat)) {
283280
fixingValue = (c->rate() - c->spread()) / c->gearing();
284281
}
282+
285283
if (auto c = boost::dynamic_pointer_cast<QuantLib::CappedFlooredIborCoupon>(ptrFloat)) {
286284
fixingValue = (c->underlying()->rate() - c->underlying()->spread()) /
287-
c->underlying()->gearing();
285+
c->underlying()->gearing();
288286
}
289-
if (auto sc = boost::dynamic_pointer_cast<QuantLib::StrippedCappedFlooredCoupon>(ptrFloat)) {
290-
if (auto c = boost::dynamic_pointer_cast<QuantLib::CappedFlooredIborCoupon>(sc->underlying())) {
287+
288+
if (auto sc =
289+
boost::dynamic_pointer_cast<QuantLib::StrippedCappedFlooredCoupon>(ptrFloat)) {
290+
if (auto c = boost::dynamic_pointer_cast<QuantLib::CappedFlooredIborCoupon>(
291+
sc->underlying())) {
291292
fixingValue = (c->underlying()->rate() - c->underlying()->spread()) /
292-
c->underlying()->gearing();
293+
c->underlying()->gearing();
293294
}
294295
}
295-
// for ON coupons the fixing value is the compounded / averaged rate, not the last
296-
// single ON fixing
296+
297+
// for (capped-floored) BMA / ON / subperiod coupons the fixing value is the
298+
// compounded / averaged rate, not a single index fixing
299+
297300
if (auto on = boost::dynamic_pointer_cast<QuantExt::AverageONIndexedCoupon>(ptrFloat)) {
298301
fixingValue = (on->rate() - on->spread()) / on->gearing();
299302
} else if (auto on = boost::dynamic_pointer_cast<QuantExt::OvernightIndexedCoupon>(
300303
ptrFloat)) {
301304
fixingValue = (on->rate() - on->effectiveSpread()) / on->gearing();
305+
} else if (auto c = boost::dynamic_pointer_cast<QuantLib::AverageBMACoupon>(ptrFloat)) {
306+
fixingValue = (c->rate() - c->spread()) / c->gearing();
302307
} else if (auto c = boost::dynamic_pointer_cast<
303308
QuantExt::CappedFlooredAverageONIndexedCoupon>(ptrFloat)) {
304309
fixingValue = (c->underlying()->rate() - c->underlying()->spread()) /
@@ -307,9 +312,13 @@ void ReportWriter::writeCashflow(ore::data::Report& report, const std::string& b
307312
QuantExt::CappedFlooredOvernightIndexedCoupon>(ptrFloat)) {
308313
fixingValue = (c->underlying()->rate() - c->underlying()->effectiveSpread()) /
309314
c->underlying()->gearing();
310-
}
311-
// similar treatment of sub period coupons
312-
if (auto sp = boost::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(ptrFloat)) {
315+
} else if (auto c =
316+
boost::dynamic_pointer_cast<QuantExt::CappedFlooredAverageBMACoupon>(
317+
ptrFloat)) {
318+
fixingValue = (c->underlying()->rate() - c->underlying()->spread()) /
319+
c->underlying()->gearing();
320+
} else if (auto sp =
321+
boost::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(ptrFloat)) {
313322
fixingValue = (sp->rate() - sp->spread()) / sp->gearing();
314323
}
315324
} else if (ptrInfl) {
@@ -390,18 +399,21 @@ void ReportWriter::writeCashflow(ore::data::Report& report, const std::string& b
390399
qlIndexName = tmp->index()->name();
391400
usesCapVol = true;
392401
// for now we output the stripped caplet vol, not the effective one
393-
// capVolatility = tmp->effectiveCapletVolatility();
394-
// floorVolatility = tmp->effectiveFloorletVolatility();
395402
} else if (auto tmp =
396403
boost::dynamic_pointer_cast<CappedFlooredAverageONIndexedCoupon>(c)) {
397404
floorStrike = tmp->effectiveFloor();
398405
capStrike = tmp->effectiveCap();
399406
volFixingDate = tmp->underlying()->fixingDates().front();
400407
qlIndexName = tmp->index()->name();
401408
usesCapVol = true;
402-
// capVolatility = tmp->effectiveCapletVolatility();
403409
// for now we output the stripped caplet vol, not the effective one
404-
// floorVolatility = tmp->effectiveFloorletVolatility();
410+
} else if (auto tmp =
411+
boost::dynamic_pointer_cast<CappedFlooredAverageBMACoupon>(c)) {
412+
floorStrike = tmp->effectiveFloor();
413+
capStrike = tmp->effectiveCap();
414+
volFixingDate = tmp->underlying()->fixingDates().front();
415+
qlIndexName = tmp->index()->name();
416+
usesCapVol = true;
405417
}
406418

407419
// get market volaility for cap / floor

0 commit comments

Comments
 (0)