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
4750using ore::data::to_string;
4851using 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