Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
ReportWriter Class Reference

Write ORE outputs to reports. More...

#include <orea/app/reportwriter.hpp>

+ Collaboration diagram for ReportWriter:

Public Member Functions

 ReportWriter (const std::string &nullString="#NA")
 
virtual ~ReportWriter ()
 
virtual void writeNpv (ore::data::Report &report, const std::string &baseCurrency, QuantLib::ext::shared_ptr< ore::data::Market > market, const std::string &configuration, QuantLib::ext::shared_ptr< Portfolio > portfolio)
 
virtual void writeCashflow (ore::data::Report &report, const std::string &baseCurrency, QuantLib::ext::shared_ptr< ore::data::Portfolio > portfolio, QuantLib::ext::shared_ptr< ore::data::Market > market=QuantLib::ext::shared_ptr< ore::data::Market >(), const std::string &configuration=ore::data::Market::defaultConfiguration, const bool includePastCashflows=false)
 
virtual void writeCashflowNpv (ore::data::Report &report, const ore::data::InMemoryReport &cashflowReport, QuantLib::ext::shared_ptr< ore::data::Market > market, const std::string &configuration, const std::string &baseCcy, const Date &horizon=Date::maxDate())
 
virtual void writeCurves (ore::data::Report &report, const std::string &configID, const DateGrid &grid, const TodaysMarketParameters &marketConfig, const QuantLib::ext::shared_ptr< Market > &market, const bool continueOnError=false)
 
virtual void writeTradeExposures (ore::data::Report &report, QuantLib::ext::shared_ptr< PostProcess > postProcess, const std::string &tradeId)
 
virtual void writeNettingSetExposures (ore::data::Report &report, QuantLib::ext::shared_ptr< PostProcess > postProcess, const std::string &nettingSetId)
 
virtual void writeNettingSetExposures (ore::data::Report &report, QuantLib::ext::shared_ptr< PostProcess > postProcess)
 
virtual void writeNettingSetCvaSensitivities (ore::data::Report &report, QuantLib::ext::shared_ptr< PostProcess > postProcess, const std::string &nettingSetId)
 
virtual void writeNettingSetColva (ore::data::Report &report, QuantLib::ext::shared_ptr< PostProcess > postProcess, const std::string &nettingSetId)
 
virtual void writeXVA (ore::data::Report &report, const string &allocationMethod, QuantLib::ext::shared_ptr< Portfolio > portfolio, QuantLib::ext::shared_ptr< PostProcess > postProcess)
 
virtual void writeAggregationScenarioData (ore::data::Report &report, const AggregationScenarioData &data)
 
virtual void writeScenarioReport (ore::data::Report &report, const std::vector< QuantLib::ext::shared_ptr< SensitivityCube > > &sensitivityCubes, QuantLib::Real outputThreshold=0.0)
 
virtual void writeSensitivityReport (ore::data::Report &report, const QuantLib::ext::shared_ptr< SensitivityStream > &ss, QuantLib::Real outputThreshold=0.0, QuantLib::Size outputPrecision=2)
 
virtual void writeSensitivityConfigReport (ore::data::Report &report, const std::map< RiskFactorKey, QuantLib::Real > &shiftSizes, const std::map< RiskFactorKey, QuantLib::Real > &baseValues, const std::map< RiskFactorKey, std::string > &keyToFactor)
 
virtual void writeAdditionalResultsReport (ore::data::Report &report, QuantLib::ext::shared_ptr< ore::data::Portfolio > portfolio, QuantLib::ext::shared_ptr< Market > market, const std::string &baseCurrency, const std::size_t precision=6)
 
virtual void writeMarketData (ore::data::Report &report, const QuantLib::ext::shared_ptr< ore::data::Loader > &loader, const QuantLib::Date &asof, const set< string > &quoteNames, bool returnAll)
 
virtual void writeFixings (ore::data::Report &report, const QuantLib::ext::shared_ptr< ore::data::Loader > &loader)
 
virtual void writeDividends (ore::data::Report &report, const QuantLib::ext::shared_ptr< ore::data::Loader > &loader)
 
virtual void writePricingStats (ore::data::Report &report, const QuantLib::ext::shared_ptr< Portfolio > &portfolio)
 
virtual void writeCube (ore::data::Report &report, const QuantLib::ext::shared_ptr< NPVCube > &cube, const std::map< std::string, std::string > &nettingSetMap=std::map< std::string, std::string >())
 
const std::string & nullString () const
 
virtual void writeSIMMReport (const std::map< SimmConfiguration::SimmSide, std::map< NettingSetDetails, std::pair< std::string, SimmResults > > > &simmResultsMap, const QuantLib::ext::shared_ptr< ore::data::Report > report, const bool hasNettingSetDetails=false, const std::string &simmResultCcy="", const std::string &simmCalcCcyCall="", const std::string &simmCalcCcyPost="", const std::string &reportCcy="", QuantLib::Real fxSpot=1.0, QuantLib::Real outputThreshold=0.005)
 
virtual void writeSIMMReport (const std::map< SimmConfiguration::SimmSide, std::map< NettingSetDetails, std::map< std::string, SimmResults > > > &simmResultsMap, const QuantLib::ext::shared_ptr< ore::data::Report > report, const bool hasNettingSetDetails=false, const std::string &simmResultCcy="", const std::string &simmCalcCcyCall="", const std::string &simmCalcCcyPost="", const std::string &reportCcy="", const bool isFinalSimm=true, QuantLib::Real fxSpot=1.0, QuantLib::Real outputThreshold=0.005)
 
virtual void writeSIMMData (const ore::analytics::Crif &simmData, const QuantLib::ext::shared_ptr< ore::data::Report > &dataReport, const bool hasNettingSetDetails=false)
 Write the SIMM data report i.e. the netted CRIF records used in a SIMM calculation. More...
 
virtual void writeCrifReport (const QuantLib::ext::shared_ptr< ore::data::Report > &report, const ore::analytics::Crif &crifRecords)
 Write out CRIF records to a report. More...
 
virtual void writeScenarioStatistics (const QuantLib::ext::shared_ptr< ore::analytics::ScenarioGenerator > &generator, const std::vector< ore::analytics::RiskFactorKey > &keys, QuantLib::Size numPaths, const std::vector< QuantLib::Date > &dates, ore::data::Report &report)
 
virtual void writeScenarioDistributions (const QuantLib::ext::shared_ptr< ore::analytics::ScenarioGenerator > &generator, const std::vector< ore::analytics::RiskFactorKey > &keys, QuantLib::Size numPaths, const std::vector< QuantLib::Date > &dates, QuantLib::Size distSteps, ore::data::Report &report)
 
virtual void writeHistoricalScenarioDetails (const QuantLib::ext::shared_ptr< ore::analytics::HistoricalScenarioGenerator > &generator, ore::data::Report &report)
 
virtual void writeStockSplitReport (const QuantLib::ext::shared_ptr< ore::analytics::Scenario > &baseScenario, const QuantLib::ext::shared_ptr< ore::analytics::HistoricalScenarioLoader > &hsloader, const QuantLib::ext::shared_ptr< ore::data::AdjustmentFactors > &adjFactors, const QuantLib::ext::shared_ptr< ore::data::Report > &report)
 
void writeHistoricalScenarios (const QuantLib::ext::shared_ptr< HistoricalScenarioLoader > &hsloader, const QuantLib::ext::shared_ptr< ore::data::Report > &report)
 
void writeHistoricalScenarioDistributions (QuantLib::ext::shared_ptr< HistoricalScenarioGenerator > &hsgen, const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarket > &simMarket, const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarketParameters > &simMarketParams, QuantLib::ext::shared_ptr< ore::data::Report > histScenDetailsReport, QuantLib::ext::shared_ptr< ore::data::Report > statReport, QuantLib::ext::shared_ptr< ore::data::Report > distReport, QuantLib::Size distSteps=Null< Size >())
 
virtual void writeIMScheduleSummaryReport (const std::map< SimmConfiguration::SimmSide, std::map< NettingSetDetails, std::pair< std::string, IMScheduleResults > > > &finalResultsMap, const QuantLib::ext::shared_ptr< Report > report, const bool hasNettingSetDetails=false, const std::string &simmResultCcy="", const std::string &reportCcy="", QuantLib::Real fxSpot=1.0, QuantLib::Real outputThreshold=0.005)
 
virtual void writeIMScheduleTradeReport (const std::map< std::string, std::vector< IMScheduleCalculator::IMScheduleTradeData > > &tradeResults, const QuantLib::ext::shared_ptr< ore::data::Report > report, const bool hasNettingSetDetails=false)
 
virtual void writePnlReport (ore::data::Report &report, const ext::shared_ptr< InMemoryReport > &t0NpvReport, const ext::shared_ptr< InMemoryReport > &t0NpvLaggedReport, const ext::shared_ptr< InMemoryReport > &t1NpvLaggedReport, const ext::shared_ptr< InMemoryReport > &t1NpvReport, const ext::shared_ptr< InMemoryReport > &t0CashFlowReport, const Date &startDate, const Date &endDate, const std::string &baseCurrency, const ext::shared_ptr< ore::data::Market > &market, const std::string &configuration, const ext::shared_ptr< Portfolio > &portfolio)
 

Protected Member Functions

void addMarketDatum (ore::data::Report &report, const ore::data::MarketDatum &md, const QuantLib::Date &actualDate=Date())
 

Protected Attributes

std::string nullString_
 

Detailed Description

Write ORE outputs to reports.

Definition at line 54 of file reportwriter.hpp.

Constructor & Destructor Documentation

◆ ReportWriter()

ReportWriter ( const std::string &  nullString = "#NA")

Constructor.

Parameters
nullStringused to represent string values that are not applicable.

Definition at line 59 of file reportwriter.hpp.

const std::string & nullString() const

◆ ~ReportWriter()

virtual ~ReportWriter ( )
virtual

Definition at line 61 of file reportwriter.hpp.

61{};

Member Function Documentation

◆ writeNpv()

void writeNpv ( ore::data::Report report,
const std::string &  baseCurrency,
QuantLib::ext::shared_ptr< ore::data::Market market,
const std::string &  configuration,
QuantLib::ext::shared_ptr< Portfolio portfolio 
)
virtual

Definition at line 80 of file reportwriter.cpp.

82 {
83 LOG("portfolio valuation");
84 DayCounter dc = ActualActual(ActualActual::ISDA);
85 Date today = Settings::instance().evaluationDate();
86 report.addColumn("TradeId", string())
87 .addColumn("TradeType", string())
88 .addColumn("Maturity", Date())
89 .addColumn("MaturityTime", double(), 6)
90 .addColumn("NPV", double(), 6)
91 .addColumn("NpvCurrency", string())
92 .addColumn("NPV(Base)", double(), 6)
93 .addColumn("BaseCurrency", string())
94 .addColumn("Notional", double(), 2)
95 .addColumn("NotionalCurrency", string())
96 .addColumn("Notional(Base)", double(), 2)
97 .addColumn("NettingSet", string())
98 .addColumn("CounterParty", string());
99 for (auto & [tradeId, trade] : portfolio->trades()) {
100 try {
101 string npvCcy = trade->npvCurrency();
102 Real fx = 1.0, fxNotional = 1.0;
103 if (npvCcy != baseCurrency)
104 fx = market->fxRate(npvCcy + baseCurrency, configuration)->value();
105 if (trade->notionalCurrency() != "" && trade->notionalCurrency() != baseCurrency)
106 fxNotional = market->fxRate(trade->notionalCurrency() + baseCurrency, configuration)->value();
107 Real npv = trade->instrument()->NPV();
108 QL_REQUIRE(std::isfinite(npv), "npv is not finite (" << npv << ")");
109 Date maturity = trade->maturity();
110 report.next()
111 .add(trade->id())
112 .add(trade->tradeType())
113 .add(maturity)
114 .add(maturity == QuantLib::Null<Date>() ? Null<Real>() : dc.yearFraction(today, maturity))
115 .add(npv)
116 .add(npvCcy)
117 .add(npv * fx)
118 .add(baseCurrency)
119 .add(trade->notional())
120 .add(trade->notionalCurrency() == "" ? nullString_ : trade->notionalCurrency())
121 .add(trade->notional() == Null<Real>() || trade->notionalCurrency() == ""
122 ? Null<Real>()
123 : trade->notional() * fxNotional)
124 .add(trade->envelope().nettingSetId())
125 .add(trade->envelope().counterparty());
126 } catch (std::exception& e) {
127 StructuredTradeErrorMessage(trade->id(), trade->tradeType(), "Error during trade pricing", e.what()).log();
128 Date maturity = trade->maturity();
129 report.next()
130 .add(trade->id())
131 .add(trade->tradeType())
132 .add(maturity)
133 .add(maturity == QuantLib::Null<Date>() ? Null<Real>() : dc.yearFraction(today, maturity))
134 .add(Null<Real>())
136 .add(Null<Real>())
138 .add(Null<Real>())
140 .add(Null<Real>())
143 }
144 }
145 report.end();
146 LOG("NPV file written");
147}
virtual Report & add(const ReportType &rt)=0
virtual Report & next()=0
virtual void end()=0
virtual Report & addColumn(const string &name, const ReportType &, Size precision=0)=0
#define LOG(text)
Time maturity
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeCashflow()

void writeCashflow ( ore::data::Report report,
const std::string &  baseCurrency,
QuantLib::ext::shared_ptr< ore::data::Portfolio portfolio,
QuantLib::ext::shared_ptr< ore::data::Market market = QuantLib::ext::shared_ptr<ore::data::Market>(),
const std::string &  configuration = ore::data::Market::defaultConfiguration,
const bool  includePastCashflows = false 
)
virtual

Definition at line 149 of file reportwriter.cpp.

152 {
153
154 Date asof = Settings::instance().evaluationDate();
155
156 LOG("Writing cashflow report for " << asof);
157 report.addColumn("TradeId", string())
158 .addColumn("Type", string())
159 .addColumn("CashflowNo", Size())
160 .addColumn("LegNo", Size())
161 .addColumn("PayDate", Date())
162 .addColumn("FlowType", string())
163 .addColumn("Amount", double(), 4)
164 .addColumn("Currency", string())
165 .addColumn("Coupon", double(), 10)
166 .addColumn("Accrual", double(), 10)
167 .addColumn("AccrualStartDate", Date(), 4)
168 .addColumn("AccrualEndDate", Date(), 4)
169 .addColumn("AccruedAmount", double(), 4)
170 .addColumn("fixingDate", Date())
171 .addColumn("fixingValue", double(), 10)
172 .addColumn("Notional", double(), 4)
173 .addColumn("DiscountFactor", double(), 10)
174 .addColumn("PresentValue", double(), 10)
175 .addColumn("FXRate(Local-Base)", double(), 10)
176 .addColumn("PresentValue(Base)", double(), 10)
177 .addColumn("BaseCurrency", string())
178 .addColumn("FloorStrike", double(), 6)
179 .addColumn("CapStrike", double(), 6)
180 .addColumn("FloorVolatility", double(), 6)
181 .addColumn("CapVolatility", double(), 6)
182 .addColumn("EffectiveFloorVolatility", double(), 6)
183 .addColumn("EffectiveCapVolatility", double(), 6);
184
185 std::map<std::string, QuantLib::ext::shared_ptr<Trade>> trades = portfolio->trades();
186
187 for (auto [tradeId, trade]: trades) {
188
189 try {
190
191 // if trade is marked as not having cashflows, we skip it
192
193 if (!trade->hasCashflows()) {
194 WLOG("cashflow for " << trade->tradeType() << " " << trade->id() << " skipped");
195 continue;
196 }
197
198 // if trade provides cashflows as additional results, we use that information instead of the legs
199
200 auto addResults = trade->instrument()->additionalResults();
201
202 auto cashFlowResults = addResults.find("cashFlowResults");
203
204 // ensures all cashFlowResults from composite trades are being accounted for
205 auto lower = addResults.lower_bound("cashFlowResults");
206 auto upper = addResults.lower_bound("cashFlowResults_a");
207
208 std::map<Size, Size> cashflowNumber;
209
210 const Real multiplier = trade->instrument()->multiplier() * trade->instrument()->multiplier2();
211
212 if (lower != addResults.end()) {
213
214 for (auto cashFlowResults = lower; cashFlowResults != upper; ++cashFlowResults) {
215
216 // additional result based cashflow reporting
217
218 QL_REQUIRE(cashFlowResults->second.type() == typeid(std::vector<CashFlowResults>),
219 "internal error: cashflowResults type does not match CashFlowResults: '"
220 << cashFlowResults->second.type().name() << "'");
221 std::vector<CashFlowResults> cfResults =
222 boost::any_cast<std::vector<CashFlowResults>>(cashFlowResults->second);
223 //std::map<Size, Size> cashflowNumber;
224 for (auto const& cf : cfResults) {
225 string ccy = "";
226 if (!cf.currency.empty()) {
227 ccy = cf.currency;
228 } else if (trade->legCurrencies().size() > cf.legNumber) {
229 ccy = trade->legCurrencies()[cf.legNumber];
230 } else {
231 ccy = trade->npvCurrency();
232 }
233
234 Real effectiveAmount = Null<Real>();
235 Real discountFactor = Null<Real>();
236 Real presentValue = Null<Real>();
237 Real presentValueBase = Null<Real>();
238 Real fxRateLocalBase = Null<Real>();
239 Real floorStrike = Null<Real>();
240 Real capStrike = Null<Real>();
241 Real floorVolatility = Null<Real>();
242 Real capVolatility = Null<Real>();
243 Real effectiveFloorVolatility = Null<Real>();
244 Real effectiveCapVolatility = Null<Real>();
245
246 if (cf.amount != Null<Real>())
247 effectiveAmount = cf.amount * multiplier;
248 if (cf.discountFactor != Null<Real>())
249 discountFactor = cf.discountFactor;
250 else if (!cf.currency.empty() && cf.payDate != Null<Date>() && market) {
251 discountFactor = cf.payDate < asof
252 ? 0.0
253 : market->discountCurve(cf.currency, configuration)->discount(cf.payDate);
254 }
255 if (cf.presentValue != Null<Real>()) {
256 presentValue = cf.presentValue * multiplier;
257 } else if (effectiveAmount != Null<Real>() && discountFactor != Null<Real>()) {
258 presentValue = effectiveAmount * discountFactor;
259 }
260 if (cf.fxRateLocalBase != Null<Real>()) {
261 fxRateLocalBase = cf.fxRateLocalBase;
262 } else if (market) {
263 try {
264 fxRateLocalBase = market->fxRate(ccy + baseCurrency)->value();
265 } catch (...) {
266 }
267 }
268 if (cf.presentValueBase != Null<Real>()) {
269 presentValueBase = cf.presentValueBase;
270 } else if (presentValue != Null<Real>() && fxRateLocalBase != Null<Real>()) {
271 presentValueBase = presentValue * fxRateLocalBase;
272 }
273 if (cf.floorStrike != Null<Real>())
274 floorStrike = cf.floorStrike;
275 if (cf.capStrike != Null<Real>())
276 capStrike = cf.capStrike;
277 if (cf.floorVolatility != Null<Real>())
278 floorVolatility = cf.floorVolatility;
279 if (cf.capVolatility != Null<Real>())
280 capVolatility = cf.capVolatility;
281 if (cf.effectiveFloorVolatility != Null<Real>())
282 floorVolatility = cf.effectiveFloorVolatility;
283 if (cf.effectiveCapVolatility != Null<Real>())
284 capVolatility = cf.effectiveCapVolatility;
285
286 // to be consistent with the leg-based cf report we should do this:
287 // if (!includePastCashflows && cf.payDate <= asof)
288 // continue;
289 // however, this changes a lot of results, so we output all cfs for the time being
290
291 report.next()
292 .add(trade->id())
293 .add(trade->tradeType())
294 .add(++cashflowNumber[cf.legNumber])
295 .add(cf.legNumber)
296 .add(cf.payDate)
297 .add(cf.type)
298 .add(effectiveAmount)
299 .add(ccy)
300 .add(cf.rate)
301 .add(cf.accrualPeriod)
302 .add(cf.accrualStartDate)
303 .add(cf.accrualEndDate)
304 .add(cf.accruedAmount * (cf.accruedAmount == Null<Real>() ? 1.0 : multiplier))
305 .add(cf.fixingDate)
306 .add(cf.fixingValue)
307 .add(cf.notional * (cf.notional == Null<Real>() ? 1.0 : multiplier))
308 .add(discountFactor)
309 .add(presentValue)
310 .add(fxRateLocalBase)
311 .add(presentValueBase)
312 .add(baseCurrency)
313 .add(floorStrike)
314 .add(capStrike)
315 .add(floorVolatility)
316 .add(capVolatility)
317 .add(effectiveFloorVolatility)
318 .add(effectiveCapVolatility);
319 }
320 }
321 }
322 if (trade->legs().size() >= 1 && cashFlowResults == addResults.end()) {
323
324 // leg based cashflow reporting
325 auto maxLegNoIter = std::max_element(cashflowNumber.begin(), cashflowNumber.end());
326 Size addResultsLegs = 0;
327 if (maxLegNoIter != cashflowNumber.end())
328 addResultsLegs = maxLegNoIter->first + 1;
329
330 const vector<Leg>& legs = trade->legs();
331 for (size_t i = 0; i < legs.size(); i++) {
332 const QuantLib::Leg& leg = legs[i];
333 bool payer = trade->legPayers()[i];
334 string ccy = trade->legCurrencies()[i];
335 Handle<YieldTermStructure> discountCurve;
336 if (market)
337 discountCurve = market->discountCurve(ccy, configuration);
338 for (size_t j = 0; j < leg.size(); j++) {
339 QuantLib::ext::shared_ptr<QuantLib::CashFlow> ptrFlow = leg[j];
340 Date payDate = ptrFlow->date();
341 if (!ptrFlow->hasOccurred(asof) || includePastCashflows) {
342 Real amount = ptrFlow->amount();
343 string flowType = "";
344 if (payer)
345 amount *= -1.0;
346 std::string ccy = trade->legCurrencies()[i];
347
348 QuantLib::ext::shared_ptr<QuantLib::Coupon> ptrCoupon =
349 QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(ptrFlow);
350 QuantLib::ext::shared_ptr<QuantExt::CommodityCashFlow> ptrCommCf =
351 QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityCashFlow>(ptrFlow);
352
353 Real coupon;
354 Real accrual;
355 Real notional;
356 Date accrualStartDate, accrualEndDate;
357 Real accruedAmount;
358
359 if (ptrCoupon) {
360 coupon = ptrCoupon->rate();
361 accrual = ptrCoupon->accrualPeriod();
362 notional = ptrCoupon->nominal();
363 accrualStartDate = ptrCoupon->accrualStartDate();
364 accrualEndDate = ptrCoupon->accrualEndDate();
365 accruedAmount = ptrCoupon->accruedAmount(asof);
366 if (payer)
367 accruedAmount *= -1.0;
368 flowType = "Interest";
369 } else if (ptrCommCf) {
370 coupon = Null<Real>();
371 accrual = Null<Real>();
372 notional =
373 ptrCommCf->periodQuantity(); // this is measured in units, e.g. barrels for oil
374 accrualStartDate = accrualEndDate = Null<Date>();
375 accruedAmount = Null<Real>();
376 flowType = "Notional (units)";
377 } else {
378 coupon = Null<Real>();
379 accrual = Null<Real>();
380 notional = Null<Real>();
381 accrualStartDate = accrualEndDate = Null<Date>();
382 accruedAmount = Null<Real>();
383 flowType = "Notional";
384 }
385
386 if (auto cpn = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(ptrFlow)) {
387 ptrFlow = unpackIndexedCoupon(cpn);
388 }
389
390 QuantLib::ext::shared_ptr<QuantLib::FloatingRateCoupon> ptrFloat =
391 QuantLib::ext::dynamic_pointer_cast<QuantLib::FloatingRateCoupon>(ptrFlow);
392 QuantLib::ext::shared_ptr<QuantLib::InflationCoupon> ptrInfl =
393 QuantLib::ext::dynamic_pointer_cast<QuantLib::InflationCoupon>(ptrFlow);
394 QuantLib::ext::shared_ptr<QuantLib::IndexedCashFlow> ptrIndCf =
395 QuantLib::ext::dynamic_pointer_cast<QuantLib::IndexedCashFlow>(ptrFlow);
396 QuantLib::ext::shared_ptr<QuantExt::FXLinkedCashFlow> ptrFxlCf =
397 QuantLib::ext::dynamic_pointer_cast<QuantExt::FXLinkedCashFlow>(ptrFlow);
398 QuantLib::ext::shared_ptr<QuantExt::EquityCoupon> ptrEqCp =
399 QuantLib::ext::dynamic_pointer_cast<QuantExt::EquityCoupon>(ptrFlow);
400
401 Date fixingDate;
402 Real fixingValue = Null<Real>();
403 if (ptrFloat) {
404 fixingDate = ptrFloat->fixingDate();
405 if (fixingDate > asof)
406 flowType = "InterestProjected";
407
408 try {
409 fixingValue = ptrFloat->index()->fixing(fixingDate);
410 } catch (...) {
411 }
412
413 if (auto c = QuantLib::ext::dynamic_pointer_cast<QuantLib::IborCoupon>(ptrFloat)) {
414 fixingValue = (c->rate() - c->spread()) / c->gearing();
415 }
416
417 if (auto c = QuantLib::ext::dynamic_pointer_cast<QuantLib::CappedFlooredIborCoupon>(
418 ptrFloat)) {
419 fixingValue = (c->underlying()->rate() - c->underlying()->spread()) /
420 c->underlying()->gearing();
421 }
422
423 if (auto sc =
424 QuantLib::ext::dynamic_pointer_cast<QuantLib::StrippedCappedFlooredCoupon>(
425 ptrFloat)) {
426 if (auto c = QuantLib::ext::dynamic_pointer_cast<QuantLib::CappedFlooredIborCoupon>(
427 sc->underlying())) {
428 fixingValue = (c->underlying()->rate() - c->underlying()->spread()) /
429 c->underlying()->gearing();
430 }
431 }
432
433 // for (capped-floored) BMA / ON / subperiod coupons the fixing value is the
434 // compounded / averaged rate, not a single index fixing
435
436 if (auto on = QuantLib::ext::dynamic_pointer_cast<QuantExt::AverageONIndexedCoupon>(
437 ptrFloat)) {
438 fixingValue = (on->rate() - on->spread()) / on->gearing();
439 } else if (auto on =
440 QuantLib::ext::dynamic_pointer_cast<QuantExt::OvernightIndexedCoupon>(
441 ptrFloat)) {
442 fixingValue = (on->rate() - on->effectiveSpread()) / on->gearing();
443 } else if (auto c = QuantLib::ext::dynamic_pointer_cast<QuantLib::AverageBMACoupon>(
444 ptrFloat)) {
445 fixingValue = (c->rate() - c->spread()) / c->gearing();
446 } else if (auto c = QuantLib::ext::dynamic_pointer_cast<
448 fixingValue = (c->underlying()->rate() - c->underlying()->spread()) /
449 c->underlying()->gearing();
450 } else if (auto c = QuantLib::ext::dynamic_pointer_cast<
452 fixingValue = (c->underlying()->rate() - c->underlying()->effectiveSpread()) /
453 c->underlying()->gearing();
454 } else if (auto c = QuantLib::ext::dynamic_pointer_cast<
456 fixingValue = (c->underlying()->rate() - c->underlying()->spread()) /
457 c->underlying()->gearing();
458 } else if (auto sp = QuantLib::ext::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(
459 ptrFloat)) {
460 fixingValue = (sp->rate() - sp->spread()) / sp->gearing();
461 }
462 } else if (ptrInfl) {
463 fixingDate = ptrInfl->fixingDate();
464 fixingValue = ptrInfl->indexFixing();
465 flowType = "Inflation";
466 } else if (ptrIndCf) {
467 fixingDate = ptrIndCf->fixingDate();
468 fixingValue = ptrIndCf->indexFixing();
469 flowType = "Index";
470 } else if (ptrFxlCf) {
471 fixingDate = ptrFxlCf->fxFixingDate();
472 fixingValue = ptrFxlCf->fxRate();
473 } else if (ptrEqCp) {
474 fixingDate = ptrEqCp->fixingEndDate();
475 fixingValue = ptrEqCp->equityCurve()->fixing(fixingDate);
476 } else if (ptrCommCf) {
477 fixingDate = ptrCommCf->lastPricingDate();
478 fixingValue = ptrCommCf->fixing();
479 } else {
480 fixingDate = Null<Date>();
481 fixingValue = Null<Real>();
482 }
483
484 Real effectiveAmount = Null<Real>();
485 Real discountFactor = Null<Real>();
486 Real presentValue = Null<Real>();
487 Real presentValueBase = Null<Real>();
488 Real fxRateLocalBase = Null<Real>();
489 Real floorStrike = Null<Real>();
490 Real capStrike = Null<Real>();
491 Real floorVolatility = Null<Real>();
492 Real capVolatility = Null<Real>();
493 Real effectiveFloorVolatility = Null<Real>();
494 Real effectiveCapVolatility = Null<Real>();
495
496 if (amount != Null<Real>())
497 effectiveAmount = amount * multiplier;
498
499 if (market) {
500 discountFactor = ptrFlow->hasOccurred(asof) ? 0.0 : discountCurve->discount(payDate);
501 if (effectiveAmount != Null<Real>())
502 presentValue = discountFactor * effectiveAmount;
503 try {
504 fxRateLocalBase = market->fxRate(ccy + baseCurrency)->value();
505 presentValueBase = presentValue * fxRateLocalBase;
506 } catch (...) {
507 }
508
509 // scan for known capped / floored coupons and extract cap / floor strike and fixing
510 // date
511
512 // unpack stripped cap/floor coupon
513 QuantLib::ext::shared_ptr<CashFlow> c = ptrFlow;
514 if (auto tmp =
515 QuantLib::ext::dynamic_pointer_cast<StrippedCappedFlooredCoupon>(ptrFlow)) {
516 c = tmp->underlying();
517 }
518 Date volFixingDate;
519 std::string qlIndexName; // index used to retrieve vol
520 bool usesCapVol = false, usesSwaptionVol = false;
521 Period swaptionTenor;
522 if (auto tmp = QuantLib::ext::dynamic_pointer_cast<CappedFlooredCoupon>(c)) {
523 floorStrike = tmp->effectiveFloor();
524 capStrike = tmp->effectiveCap();
525 volFixingDate = tmp->fixingDate();
526 qlIndexName = tmp->index()->name();
527 if (auto cms = QuantLib::ext::dynamic_pointer_cast<CmsCoupon>(tmp->underlying())) {
528 swaptionTenor = cms->swapIndex()->tenor();
529 qlIndexName = cms->swapIndex()->iborIndex()->name();
530 usesSwaptionVol = true;
531 }else if(auto cms = boost::dynamic_pointer_cast<DurationAdjustedCmsCoupon>(tmp->underlying())) {
532 swaptionTenor = cms->swapIndex()->tenor();
533 qlIndexName = cms->swapIndex()->iborIndex()->name();
534 usesSwaptionVol = true;
535 }else if (auto ibor = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(tmp->underlying())) {
536 qlIndexName = ibor->index()->name();
537 usesCapVol = true;
538 }
539 } else if (auto tmp =
540 QuantLib::ext::dynamic_pointer_cast<CappedFlooredOvernightIndexedCoupon>(
541 c)) {
542 floorStrike = tmp->effectiveFloor();
543 capStrike = tmp->effectiveCap();
544 volFixingDate = tmp->underlying()->fixingDates().front();
545 qlIndexName = tmp->index()->name();
546 usesCapVol = true;
547 if (floorStrike != Null<Real>())
548 effectiveFloorVolatility = tmp->effectiveFloorletVolatility();
549 if (capStrike != Null<Real>())
550 effectiveCapVolatility = tmp->effectiveCapletVolatility();
551 } else if (auto tmp =
552 QuantLib::ext::dynamic_pointer_cast<CappedFlooredAverageONIndexedCoupon>(
553 c)) {
554 floorStrike = tmp->effectiveFloor();
555 capStrike = tmp->effectiveCap();
556 volFixingDate = tmp->underlying()->fixingDates().front();
557 qlIndexName = tmp->index()->name();
558 usesCapVol = true;
559 if (floorStrike != Null<Real>())
560 effectiveFloorVolatility = tmp->effectiveFloorletVolatility();
561 if (capStrike != Null<Real>())
562 effectiveCapVolatility = tmp->effectiveCapletVolatility();
563 } else if (auto tmp =
564 QuantLib::ext::dynamic_pointer_cast<CappedFlooredAverageBMACoupon>(c)) {
565 floorStrike = tmp->effectiveFloor();
566 capStrike = tmp->effectiveCap();
567 volFixingDate = tmp->underlying()->fixingDates().front();
568 qlIndexName = tmp->index()->name();
569 usesCapVol = true;
570 if (floorStrike != Null<Real>())
571 effectiveFloorVolatility = tmp->effectiveFloorletVolatility();
572 if (capStrike != Null<Real>())
573 effectiveCapVolatility = tmp->effectiveCapletVolatility();
574 }
575
576 // get market volaility for cap / floor
577
578 if (volFixingDate != Date() && fixingDate > market->asofDate()) {
579 volFixingDate = std::max(volFixingDate, market->asofDate() + 1);
580 if (floorStrike != Null<Real>()) {
581 if (usesSwaptionVol) {
582 floorVolatility =
583 market
584 ->swaptionVol(IndexNameTranslator::instance().oreName(qlIndexName),
585 configuration)
586 ->volatility(volFixingDate, swaptionTenor, floorStrike);
587 } else if (usesCapVol && floorVolatility == Null<Real>()) {
588 floorVolatility =
589 market
590 ->capFloorVol(IndexNameTranslator::instance().oreName(qlIndexName),
591 configuration)
592 ->volatility(volFixingDate, floorStrike);
593 }
594 }
595 if (capStrike != Null<Real>()) {
596 if (usesSwaptionVol) {
597 capVolatility =
598 market
599 ->swaptionVol(IndexNameTranslator::instance().oreName(qlIndexName),
600 configuration)
601 ->volatility(volFixingDate, swaptionTenor, capStrike);
602 } else if (usesCapVol && capVolatility == Null<Real>()) {
603 capVolatility =
604 market
605 ->capFloorVol(IndexNameTranslator::instance().oreName(qlIndexName),
606 configuration)
607 ->volatility(volFixingDate, capStrike);
608 }
609 }
610 }
611 }
612
613 report.next()
614 .add(trade->id())
615 .add(trade->tradeType())
616 .add(j + 1)
617 .add(i + addResultsLegs)
618 .add(payDate)
619 .add(flowType)
620 .add(effectiveAmount)
621 .add(ccy)
622 .add(coupon)
623 .add(accrual)
624 .add(accrualStartDate)
625 .add(accrualEndDate)
626 .add(accruedAmount * (accruedAmount == Null<Real>() ? 1.0 : multiplier))
627 .add(fixingDate)
628 .add(fixingValue)
629 .add(notional * (notional == Null<Real>() ? 1.0 : multiplier))
630 .add(discountFactor)
631 .add(presentValue)
632 .add(fxRateLocalBase)
633 .add(presentValueBase)
634 .add(baseCurrency)
635 .add(floorStrike)
636 .add(capStrike)
637 .add(floorVolatility)
638 .add(capVolatility)
639 .add(effectiveFloorVolatility)
640 .add(effectiveCapVolatility);
641 }
642 }
643 }
644 }
645
646 } catch (std::exception& e) {
647 StructuredTradeErrorMessage(trade->id(), trade->tradeType(), "Error during cashflow report generation",
648 e.what())
649 .log();
650 }
651 }
652 report.end();
653 LOG("Cashflow report written");
654}
#define WLOG(text)
QuantLib::Date fixingDate(const QuantLib::Date &d, const QuantLib::Period obsLag, const QuantLib::Frequency freq, bool interpolated)
boost::shared_ptr< Coupon > unpackIndexedCoupon(const boost::shared_ptr< Coupon > &c)
Date asof(14, Jun, 2018)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeCashflowNpv()

void writeCashflowNpv ( ore::data::Report report,
const ore::data::InMemoryReport cashflowReport,
QuantLib::ext::shared_ptr< ore::data::Market market,
const std::string &  configuration,
const std::string &  baseCcy,
const Date &  horizon = Date::maxDate() 
)
virtual

Definition at line 656 of file reportwriter.cpp.

658 {
659 // Pick the following fields form the in memory report:
660 // - tradeId
661 // - payment date
662 // - currency
663 // - present value
664 // Then convert PVs into base currency, aggrate per trade if payment date is within the horizon
665 // Write the resulting aggregate PV per trade into the report.
666
667 Size tradeIdColumn = 0;
668 Size tradeTypeColumn = 1;
669 Size payDateColumn = 4;
670 Size ccyColumn = 7;
671 Size pvColumn = 17;
672 QL_REQUIRE(cashflowReport.header(tradeIdColumn) == "TradeId", "incorrect trade id column " << tradeIdColumn);
673 QL_REQUIRE(cashflowReport.header(tradeTypeColumn) == "Type", "incorrect trade type column " << tradeTypeColumn);
674 QL_REQUIRE(cashflowReport.header(payDateColumn) == "PayDate", "incorrect payment date column " << payDateColumn);
675 QL_REQUIRE(cashflowReport.header(ccyColumn) == "Currency", "incorrect currency column " << ccyColumn);
676 QL_REQUIRE(cashflowReport.header(pvColumn) == "PresentValue", "incorrect pv column " << pvColumn);
677
678 map<string, Real> npvMap;
679 Date asof = Settings::instance().evaluationDate();
680 for (Size i = 0; i < cashflowReport.rows(); ++i) {
681 string tradeId = QuantLib::ext::get<string>(cashflowReport.data(tradeIdColumn).at(i));
682 string tradeType = QuantLib::ext::get<string>(cashflowReport.data(tradeTypeColumn).at(i));
683 Date payDate = QuantLib::ext::get<Date>(cashflowReport.data(payDateColumn).at(i));
684 string ccy = QuantLib::ext::get<string>(cashflowReport.data(ccyColumn).at(i));
685 Real pv = QuantLib::ext::get<Real>(cashflowReport.data(pvColumn).at(i));
686 Real fx = 1.0;
687 // There shouldn't be entries in the cf report without ccy. We assume ccy = baseCcy in this case and log an error.
688 if (ccy.empty()) {
689 StructuredTradeErrorMessage(tradeId, tradeType, "Error during CashflowNpv calculation.",
690 "Cashflow in row " + std::to_string(i) +
691 " has no ccy. Assuming ccy = baseCcy = " + baseCcy + ".")
692 .log();
693 }
694 if (!ccy.empty() && ccy != baseCcy)
695 fx = market->fxRate(ccy + baseCcy, configuration)->value();
696 if (npvMap.find(tradeId) == npvMap.end())
697 npvMap[tradeId] = 0.0;
698 if (payDate > asof && payDate <= horizon) {
699 npvMap[tradeId] += pv * fx;
700 DLOG("Cashflow NPV for trade " << tradeId << ": pv " << pv << " fx " << fx << " sum " << npvMap[tradeId]);
701 }
702 }
703
704 LOG("Writing cashflow NPV report for " << asof);
705 report.addColumn("TradeId", string())
706 .addColumn("PresentValue", double(), 10)
707 .addColumn("BaseCurrency", string())
708 .addColumn("Horizon", string());
709
710 for (auto r: npvMap)
711 report.next().add(r.first).add(r.second).add(baseCcy).add(horizon < Date::maxDate() ? ore::data::to_string(horizon) : "infinite");
712
713 report.end();
714 LOG("Cashflow NPV report written");
715}
const string & header(Size i) const
const vector< ReportType > & data(Size i) const
#define DLOG(text)
std::string to_string(const LocationInfo &l)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeCurves()

void writeCurves ( ore::data::Report report,
const std::string &  configID,
const DateGrid grid,
const TodaysMarketParameters marketConfig,
const QuantLib::ext::shared_ptr< Market > &  market,
const bool  continueOnError = false 
)
virtual

Definition at line 717 of file reportwriter.cpp.

719 {
720 LOG("Write curves... ");
721
722 QL_REQUIRE(marketConfig.hasConfiguration(configID), "curve configuration " << configID << " not found");
723
724 map<string, string> discountCurves = marketConfig.mapping(MarketObject::DiscountCurve, configID);
725 map<string, string> YieldCurves = marketConfig.mapping(MarketObject::YieldCurve, configID);
726 map<string, string> indexCurves = marketConfig.mapping(MarketObject::IndexCurve, configID);
727 map<string, string> zeroInflationIndices, defaultCurves;
728 if (marketConfig.hasMarketObject(MarketObject::ZeroInflationCurve))
729 zeroInflationIndices = marketConfig.mapping(MarketObject::ZeroInflationCurve, configID);
730 if (marketConfig.hasMarketObject(MarketObject::DefaultCurve))
731 defaultCurves = marketConfig.mapping(MarketObject::DefaultCurve, configID);
732
733 vector<Handle<YieldTermStructure>> yieldCurves;
734 vector<Handle<ZeroInflationIndex>> zeroInflationFixings;
735 vector<Handle<DefaultProbabilityTermStructure>> probabilityCurves;
736
737 report.addColumn("Tenor", Period()).addColumn("Date", Date());
738
739 for (auto it : discountCurves) {
740 DLOG("discount curve - " << it.first);
741 try {
742 yieldCurves.push_back(market->discountCurve(it.first, configID));
743 report.addColumn(it.first, double(), 15);
744 } catch (const std::exception& e) {
745 if (continueOnError) {
746 WLOG("skip this curve: " << e.what());
747 } else {
748 QL_FAIL(e.what());
749 }
750 }
751 }
752 for (auto it : YieldCurves) {
753 DLOG("yield curve - " << it.first);
754 try {
755 yieldCurves.push_back(market->yieldCurve(it.first, configID));
756 report.addColumn(it.first, double(), 15);
757 } catch (const std::exception& e) {
758 if (continueOnError) {
759 WLOG("skip this curve: " << e.what());
760 } else {
761 QL_FAIL(e.what());
762 }
763 }
764 }
765 for (auto it : indexCurves) {
766 DLOG("index curve - " << it.first);
767 try {
768 yieldCurves.push_back(market->iborIndex(it.first, configID)->forwardingTermStructure());
769 report.addColumn(it.first, double(), 15);
770 } catch (const std::exception& e) {
771 if (continueOnError) {
772 WLOG("skip this curve: " << e.what());
773 } else {
774 QL_FAIL(e.what());
775 }
776 }
777 }
778 for (auto it : zeroInflationIndices) {
779 DLOG("inflation curve - " << it.first);
780 try {
781 zeroInflationFixings.push_back(market->zeroInflationIndex(it.first, configID));
782 report.addColumn(it.first, double(), 15);
783 } catch (const std::exception& e) {
784 if (continueOnError) {
785 WLOG("skip this curve: " << e.what());
786 } else {
787 QL_FAIL(e.what());
788 }
789 }
790 }
791 for (auto it : defaultCurves) {
792 DLOG("default curve - " << it.first);
793 try {
794 probabilityCurves.push_back(market->defaultCurve(it.first, configID)->curve());
795 report.addColumn(it.first, double(), 15);
796 } catch (const std::exception& e) {
797 if (continueOnError) {
798 WLOG("skip this curve: " << e.what());
799 } else {
800 QL_FAIL(e.what());
801 }
802 }
803 }
804
805 for (Size j = 0; j < grid.size(); ++j) {
806 Date date = grid[j];
807 report.next().add(grid.tenors()[j]).add(date);
808 for (Size i = 0; i < yieldCurves.size(); ++i)
809 report.add(yieldCurves[i]->discount(date));
810 for (Size i = 0; i < zeroInflationFixings.size(); ++i)
811 report.add(zeroInflationFixings[i]->fixing(date));
812 for (Size i = 0; i < probabilityCurves.size(); ++i)
813 report.add(probabilityCurves[i]->survivalProbability(date));
814 }
815 report.end();
816}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeTradeExposures()

void writeTradeExposures ( ore::data::Report report,
QuantLib::ext::shared_ptr< PostProcess postProcess,
const std::string &  tradeId 
)
virtual

Definition at line 818 of file reportwriter.cpp.

819 {
820 const vector<Date> dates = postProcess->cube()->dates();
821 Date today = Settings::instance().evaluationDate();
822 DayCounter dc = ActualActual(ActualActual::ISDA);
823 const vector<Real>& epe = postProcess->tradeEPE(tradeId);
824 const vector<Real>& ene = postProcess->tradeENE(tradeId);
825 const vector<Real>& ee_b = postProcess->tradeEE_B(tradeId);
826 const vector<Real>& eee_b = postProcess->tradeEEE_B(tradeId);
827 const vector<Real>& pfe = postProcess->tradePFE(tradeId);
828 const vector<Real>& aepe = postProcess->allocatedTradeEPE(tradeId);
829 const vector<Real>& aene = postProcess->allocatedTradeENE(tradeId);
830 report.addColumn("TradeId", string())
831 .addColumn("Date", Date())
832 .addColumn("Time", double(), 6)
833 .addColumn("EPE", double())
834 .addColumn("ENE", double())
835 .addColumn("AllocatedEPE", double())
836 .addColumn("AllocatedENE", double())
837 .addColumn("PFE", double())
838 .addColumn("BaselEE", double())
839 .addColumn("BaselEEE", double());
840 report.next()
841 .add(tradeId)
842 .add(today)
843 .add(0.0)
844 .add(epe[0])
845 .add(ene[0])
846 .add(aepe[0])
847 .add(aene[0])
848 .add(pfe[0])
849 .add(ee_b[0])
850 .add(eee_b[0]);
851 for (Size j = 0; j < dates.size(); ++j) {
852
853 Time time = dc.yearFraction(today, dates[j]);
854 report.next()
855 .add(tradeId)
856 .add(dates[j])
857 .add(time)
858 .add(epe[j + 1])
859 .add(ene[j + 1])
860 .add(aepe[j + 1])
861 .add(aene[j + 1])
862 .add(pfe[j + 1])
863 .add(ee_b[j + 1])
864 .add(eee_b[j + 1]);
865 }
866 report.end();
867}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeNettingSetExposures() [1/2]

void writeNettingSetExposures ( ore::data::Report report,
QuantLib::ext::shared_ptr< PostProcess postProcess,
const std::string &  nettingSetId 
)
virtual

Definition at line 906 of file reportwriter.cpp.

907 {
908 report.addColumn("NettingSet", string())
909 .addColumn("Date", Date())
910 .addColumn("Time", double(), 6)
911 .addColumn("EPE", double(), 2)
912 .addColumn("ENE", double(), 2)
913 .addColumn("PFE", double(), 2)
914 .addColumn("ExpectedCollateral", double(), 2)
915 .addColumn("BaselEE", double(), 2)
916 .addColumn("BaselEEE", double(), 2);
917 addNettingSetExposure(report, postProcess, nettingSetId);
918 report.end();
919}
void addNettingSetExposure(ore::data::Report &report, QuantLib::ext::shared_ptr< PostProcess > postProcess, const string &nettingSetId)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeNettingSetExposures() [2/2]

void writeNettingSetExposures ( ore::data::Report report,
QuantLib::ext::shared_ptr< PostProcess postProcess 
)
virtual

Definition at line 921 of file reportwriter.cpp.

921 {
922 report.addColumn("NettingSet", string())
923 .addColumn("Date", Date())
924 .addColumn("Time", double(), 6)
925 .addColumn("EPE", double(), 2)
926 .addColumn("ENE", double(), 2)
927 .addColumn("PFE", double(), 2)
928 .addColumn("ExpectedCollateral", double(), 2)
929 .addColumn("BaselEE", double(), 2)
930 .addColumn("BaselEEE", double(), 2);
931
932 for (const auto& [n,_] : postProcess->nettingSetIds()) {
933 addNettingSetExposure(report, postProcess, n);
934 }
935 report.end();
936}
+ Here is the call graph for this function:

◆ writeNettingSetCvaSensitivities()

void writeNettingSetCvaSensitivities ( ore::data::Report report,
QuantLib::ext::shared_ptr< PostProcess postProcess,
const std::string &  nettingSetId 
)
virtual

Definition at line 938 of file reportwriter.cpp.

940 {
941 const vector<Real> grid = postProcess->spreadSensitivityTimes();
942 const vector<Real>& sensiHazardRate = postProcess->netCvaHazardRateSensitivity(nettingSetId);
943 const vector<Real>& sensiCdsSpread = postProcess->netCvaSpreadSensitivity(nettingSetId);
944 report.addColumn("NettingSet", string())
945 .addColumn("Time", double(), 6)
946 .addColumn("CvaHazardRateSensitivity", double(), 6)
947 .addColumn("CvaSpreadSensitivity", double(), 6);
948
949 if (sensiHazardRate.size() == 0 || sensiCdsSpread.size() == 0)
950 return;
951
952 for (Size j = 0; j < grid.size(); ++j) {
953 report.next().add(nettingSetId).add(grid[j]).add(sensiHazardRate[j]).add(sensiCdsSpread[j]);
954 }
955 report.end();
956}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeNettingSetColva()

void writeNettingSetColva ( ore::data::Report report,
QuantLib::ext::shared_ptr< PostProcess postProcess,
const std::string &  nettingSetId 
)
virtual

Definition at line 1058 of file reportwriter.cpp.

1059 {
1060 const vector<Date> dates = postProcess->cube()->dates();
1061 Date today = Settings::instance().evaluationDate();
1062 DayCounter dc = ActualActual(ActualActual::ISDA);
1063 const vector<Real>& collateral = postProcess->expectedCollateral(nettingSetId);
1064 const vector<Real>& colvaInc = postProcess->colvaIncrements(nettingSetId);
1065 const vector<Real>& floorInc = postProcess->collateralFloorIncrements(nettingSetId);
1066 Real colva = postProcess->nettingSetCOLVA(nettingSetId);
1067 Real floorValue = postProcess->nettingSetCollateralFloor(nettingSetId);
1068
1069 report.addColumn("NettingSet", string())
1070 .addColumn("Date", Date())
1071 .addColumn("Time", double(), 4)
1072 .addColumn("CollateralBalance", double(), 4)
1073 .addColumn("COLVA Increment", double(), 4)
1074 .addColumn("COLVA", double(), 4)
1075 .addColumn("CollateralFloor Increment", double(), 4)
1076 .addColumn("CollateralFloor", double(), 4);
1077
1078 report.next()
1079 .add(nettingSetId)
1080 .add(Null<Date>())
1081 .add(Null<Real>())
1082 .add(Null<Real>())
1083 .add(Null<Real>())
1084 .add(colva)
1085 .add(Null<Real>())
1086 .add(floorValue);
1087 Real colvaSum = 0.0;
1088 Real floorSum = 0.0;
1089 for (Size j = 0; j < dates.size(); ++j) {
1090 Real time = dc.yearFraction(today, dates[j]);
1091 colvaSum += colvaInc[j + 1];
1092 floorSum += floorInc[j + 1];
1093 report.next()
1094 .add(nettingSetId)
1095 .add(dates[j])
1096 .add(time)
1097 .add(collateral[j + 1])
1098 .add(colvaInc[j + 1])
1099 .add(colvaSum)
1100 .add(floorInc[j + 1])
1101 .add(floorSum);
1102 }
1103 report.end();
1104}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeXVA()

void writeXVA ( ore::data::Report report,
const string &  allocationMethod,
QuantLib::ext::shared_ptr< Portfolio portfolio,
QuantLib::ext::shared_ptr< PostProcess postProcess 
)
virtual

Definition at line 958 of file reportwriter.cpp.

959 {
960 const vector<Date> dates = postProcess->cube()->dates();
961 DayCounter dc = ActualActual(ActualActual::ISDA);
962 Size precision = 2;
963 report.addColumn("TradeId", string())
964 .addColumn("NettingSetId", string())
965 .addColumn("CVA", double(), precision)
966 .addColumn("DVA", double(), precision)
967 .addColumn("FBA", double(), precision)
968 .addColumn("FCA", double(), precision)
969 .addColumn("FBAexOwnSP", double(), precision)
970 .addColumn("FCAexOwnSP", double(), precision)
971 .addColumn("FBAexAllSP", double(), precision)
972 .addColumn("FCAexAllSP", double(), precision)
973 .addColumn("COLVA", double(), precision)
974 .addColumn("MVA", double(), precision)
975 .addColumn("OurKVACCR", double(), precision)
976 .addColumn("TheirKVACCR", double(), precision)
977 .addColumn("OurKVACVA", double(), precision)
978 .addColumn("TheirKVACVA", double(), precision)
979 .addColumn("CollateralFloor", double(), precision)
980 .addColumn("AllocatedCVA", double(), precision)
981 .addColumn("AllocatedDVA", double(), precision)
982 .addColumn("AllocationMethod", string())
983 .addColumn("BaselEPE", double(), precision)
984 .addColumn("BaselEEPE", double(), precision);
985
986 for (const auto& [n, _] : postProcess->nettingSetIds()) {
987 try {
988 postProcess->nettingSetCVA(n);
989 report.next()
990 .add("")
991 .add(n)
992 .add(postProcess->nettingSetCVA(n))
993 .add(postProcess->nettingSetDVA(n))
994 .add(postProcess->nettingSetFBA(n))
995 .add(postProcess->nettingSetFCA(n))
996 .add(postProcess->nettingSetFBA_exOwnSP(n))
997 .add(postProcess->nettingSetFCA_exOwnSP(n))
998 .add(postProcess->nettingSetFBA_exAllSP(n))
999 .add(postProcess->nettingSetFCA_exAllSP(n))
1000 .add(postProcess->nettingSetCOLVA(n))
1001 .add(postProcess->nettingSetMVA(n))
1002 .add(postProcess->nettingSetOurKVACCR(n))
1003 .add(postProcess->nettingSetTheirKVACCR(n))
1004 .add(postProcess->nettingSetOurKVACVA(n))
1005 .add(postProcess->nettingSetTheirKVACVA(n))
1006 .add(postProcess->nettingSetCollateralFloor(n))
1007 .add(postProcess->nettingSetCVA(n))
1008 .add(postProcess->nettingSetDVA(n))
1009 .add(allocationMethod)
1010 .add(postProcess->netEPE_B(n))
1011 .add(postProcess->netEEPE_B(n));
1012 } catch (const std::exception& e) {
1013 StructuredAnalyticsErrorMessage("XVA Report", "Error during writing xva for netting set.", e.what(),
1014 {{"nettingSetId", n}})
1015 .log();
1016 }
1017
1018 for (auto& [tid, trade] : portfolio->trades()) {
1019
1020 string nid = trade->envelope().nettingSetId();
1021 if (nid != n)
1022 continue;
1023 try {
1024 postProcess->tradeCVA(tid);
1025 report.next()
1026 .add(tid)
1027 .add(nid)
1028 .add(postProcess->tradeCVA(tid))
1029 .add(postProcess->tradeDVA(tid))
1030 .add(postProcess->tradeFBA(tid))
1031 .add(postProcess->tradeFCA(tid))
1032 .add(postProcess->tradeFBA_exOwnSP(tid))
1033 .add(postProcess->tradeFCA_exOwnSP(tid))
1034 .add(postProcess->tradeFBA_exAllSP(tid))
1035 .add(postProcess->tradeFCA_exAllSP(tid))
1036 .add(Null<Real>())
1037 .add(Null<Real>())
1038 .add(Null<Real>())
1039 .add(Null<Real>())
1040 .add(Null<Real>())
1041 .add(Null<Real>())
1042 .add(Null<Real>())
1043 .add(postProcess->allocatedTradeCVA(tid))
1044 .add(postProcess->allocatedTradeDVA(tid))
1045 .add(allocationMethod)
1046 .add(postProcess->tradeEPE_B(tid))
1047 .add(postProcess->tradeEEPE_B(tid));
1048 } catch (const std::exception& e) {
1049 StructuredAnalyticsErrorMessage("XVA Report", "Error during writing xva for trade.", e.what(),
1050 {{"tradeId", n}})
1051 .log();
1052 }
1053 }
1054 }
1055 report.end();
1056}
RandomVariable log(RandomVariable x)
+ Here is the call graph for this function:

◆ writeAggregationScenarioData()

void writeAggregationScenarioData ( ore::data::Report report,
const AggregationScenarioData data 
)
virtual

Definition at line 1106 of file reportwriter.cpp.

1106 {
1107 report.addColumn("Date", Size()).addColumn("Scenario", Size());
1108 for (auto const& k : data.keys()) {
1109 std::string tmp = ore::data::to_string(k.first) + k.second;
1110 report.addColumn(tmp.c_str(), double(), 8);
1111 }
1112 for (Size d = 0; d < data.dimDates(); ++d) {
1113 for (Size s = 0; s < data.dimSamples(); ++s) {
1114 report.next();
1115 report.add(d).add(s);
1116 for (auto const& k : data.keys()) {
1117 report.add(data.get(d, s, k.first, k.second));
1118 }
1119 }
1120 }
1121 report.end();
1122}
data
+ Here is the call graph for this function:

◆ writeScenarioReport()

void writeScenarioReport ( ore::data::Report report,
const std::vector< QuantLib::ext::shared_ptr< SensitivityCube > > &  sensitivityCubes,
QuantLib::Real  outputThreshold = 0.0 
)
virtual

Definition at line 1124 of file reportwriter.cpp.

1126 {
1127
1128 LOG("Writing Scenario report");
1129
1130 report.addColumn("TradeId", string());
1131 report.addColumn("Factor", string());
1132 report.addColumn("Up/Down", string());
1133 report.addColumn("Base NPV", double(), 2);
1134 report.addColumn("ShiftSize_1", double(), 6);
1135 report.addColumn("ShiftSize_2", double(), 6);
1136 report.addColumn("Scenario NPV", double(), 2);
1137 report.addColumn("Difference", double(), 2);
1138
1139 for (auto const& sensitivityCube : sensitivityCubes) {
1140
1141 auto scenarioDescriptions = sensitivityCube->scenarioDescriptions();
1142 auto tradeIds = sensitivityCube->tradeIdx();
1143 auto npvCube = sensitivityCube->npvCube();
1144
1145 for (const auto& [tradeId, i] : tradeIds) {
1146
1147 Real baseNpv = npvCube->getT0(i);
1148 for (const auto& [j, scenarioNpv] : npvCube->getTradeNPVs(i)) {
1149 auto scenarioDescription = scenarioDescriptions[j];
1150 Real difference = scenarioNpv - baseNpv;
1151 Real shift1 = scenarioDescription.key1().keytype == RiskFactorKey::KeyType::None
1152 ? Null<Real>()
1153 : sensitivityCube->actualShiftSize(scenarioDescription.key1());
1154 Real shift2 = scenarioDescription.key2().keytype == RiskFactorKey::KeyType::None
1155 ? Null<Real>()
1156 : sensitivityCube->actualShiftSize(scenarioDescription.key2());
1157 if (fabs(difference) > outputThreshold) {
1158 report.next();
1159 report.add(tradeId);
1160 report.add(prettyPrintInternalCurveName(scenarioDescription.factors()));
1161 report.add(scenarioDescription.typeString());
1162 report.add(baseNpv);
1163 report.add(shift1);
1164 report.add(shift2);
1165 report.add(scenarioNpv);
1166 report.add(difference);
1167 } else if (!std::isfinite(difference)) {
1168 // TODO: is this needed?
1169 ALOG("sensitivity scenario for trade " << tradeId << ", factor " << scenarioDescription.factors()
1170 << " is not finite (" << difference << ")");
1171 }
1172 }
1173 }
1174 }
1175
1176 report.end();
1177 LOG("Scenario report finished");
1178}
#define ALOG(text)
std::string prettyPrintInternalCurveName(std::string name)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeSensitivityReport()

void writeSensitivityReport ( ore::data::Report report,
const QuantLib::ext::shared_ptr< SensitivityStream > &  ss,
QuantLib::Real  outputThreshold = 0.0,
QuantLib::Size  outputPrecision = 2 
)
virtual

Definition at line 1180 of file reportwriter.cpp.

1181 {
1182
1183 LOG("Writing Sensitivity report");
1184
1185 Size shiftSizePrecision = outputPrecision < 6 ? 6 : outputPrecision;
1186 Size amountPrecision = outputPrecision < 2 ? 2 : outputPrecision;
1187
1188 report.addColumn("TradeId", string());
1189 report.addColumn("IsPar", string());
1190 report.addColumn("Factor_1", string());
1191 report.addColumn("ShiftSize_1", double(), shiftSizePrecision);
1192 report.addColumn("Factor_2", string());
1193 report.addColumn("ShiftSize_2", double(), shiftSizePrecision);
1194 report.addColumn("Currency", string());
1195 report.addColumn("Base NPV", double(), amountPrecision);
1196 report.addColumn("Delta", double(), amountPrecision);
1197 report.addColumn("Gamma", double(), amountPrecision);
1198
1199 // Make sure that we are starting from the start
1200 ss->reset();
1201 while (SensitivityRecord sr = ss->next()) {
1202 if ((outputThreshold == Null<Real>()) || (fabs(sr.delta) > outputThreshold ||
1203 (sr.gamma != Null<Real>() && fabs(sr.gamma) > outputThreshold))) {
1204 report.next();
1205 report.add(sr.tradeId);
1206 report.add(ore::data::to_string(sr.isPar));
1207 report.add(prettyPrintInternalCurveName(reconstructFactor(sr.key_1, sr.desc_1)));
1208 report.add(sr.shift_1);
1209 report.add(prettyPrintInternalCurveName(reconstructFactor(sr.key_2, sr.desc_2)));
1210 report.add(sr.shift_2);
1211 report.add(sr.currency);
1212 report.add(sr.baseNpv);
1213 report.add(sr.delta);
1214 report.add(sr.gamma);
1215 } else if (!std::isfinite(sr.delta) || !std::isfinite(sr.gamma)) {
1216 // TODO: Again, is this needed?
1217 ALOG("sensitivity record has infinite values: " << sr);
1218 }
1219 }
1220
1221 report.end();
1222 LOG("Sensitivity report finished");
1223}
string reconstructFactor(const RiskFactorKey &key, const string &desc)
Reconstruct the string description from a risk factor key and its index description desc.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeSensitivityConfigReport()

void writeSensitivityConfigReport ( ore::data::Report report,
const std::map< RiskFactorKey, QuantLib::Real > &  shiftSizes,
const std::map< RiskFactorKey, QuantLib::Real > &  baseValues,
const std::map< RiskFactorKey, std::string > &  keyToFactor 
)
virtual

Definition at line 1225 of file reportwriter.cpp.

1228 {
1229 LOG("Writing Sensitivity Config report");
1230
1231 report.addColumn("Key", string())
1232 .addColumn("Factor", string())
1233 .addColumn("BaseValue", double(), 8)
1234 .addColumn("ShiftSize", double(), 8);
1235
1236 for (auto const& [key, shift] : shiftSizes) {
1237 report.next();
1238 std::string keyStr = "na", factorStr = "na";
1239 Real baseValue = Null<Real>();
1240 keyStr = ore::data::to_string(key);
1241 if (auto it = keyToFactor.find(key); it != keyToFactor.end())
1242 factorStr = it->second;
1243 if (auto it = baseValues.find(key); it != baseValues.end())
1244 baseValue = it->second;
1245 report.add(keyStr).add(factorStr).add(baseValue).add(shift);
1246 }
1247
1248 report.end();
1249 LOG("Sensitivity Config report finished.");
1250}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeAdditionalResultsReport()

void writeAdditionalResultsReport ( ore::data::Report report,
QuantLib::ext::shared_ptr< ore::data::Portfolio portfolio,
QuantLib::ext::shared_ptr< Market market,
const std::string &  baseCurrency,
const std::size_t  precision = 6 
)
virtual

Definition at line 1263 of file reportwriter.cpp.

1265 {
1266
1267 LOG("Writing AdditionalResults report");
1268
1269 report.addColumn("TradeId", string())
1270 .addColumn("ResultId", string())
1271 .addColumn("ResultType", string())
1272 .addColumn("ResultValue", string());
1273
1274 for (auto & [tId, trade] : portfolio->trades()) {
1275 try {
1276 // we first add any additional trade data.
1277 string tradeId = tId;
1278 string tradeType = trade->tradeType();
1279 Real notional2 = Null<Real>();
1280 string notional2Ccy = "";
1281 // Get the additional data for the current instrument.
1282 auto additionalData = trade->additionalData();
1283 for (const auto& kv : additionalData) {
1284 auto p = parseBoostAny(kv.second, precision);
1285 if (boost::starts_with(p.first, "vector")) {
1286 vector<std::string> tokens;
1287 string vect = p.second;
1288 vect.erase(remove(vect.begin(), vect.end(), '\"'), vect.end());
1289 boost::split(tokens, vect, boost::is_any_of(","));
1290 for (Size i = 0; i < tokens.size(); i++) {
1291 boost::trim(tokens[i]);
1292 report.next()
1293 .add(tradeId)
1294 .add(kv.first + "[" + std::to_string(i) + "]")
1295 .add(p.first.substr(7))
1296 .add(tokens[i]);
1297 }
1298 } else
1299 report.next().add(tradeId).add(kv.first).add(p.first).add(p.second);
1300 }
1301 // if the 'notional[2]' has been provided convert it to base currency
1302 if (additionalData.count("notional[2]") != 0 && additionalData.count("notionalCurrency[2]") != 0) {
1303 notional2 = trade->additionalDatum<Real>("notional[2]");
1304 notional2Ccy = trade->additionalDatum<string>("notionalCurrency[2]");
1305 }
1306
1307 auto additionalResults = trade->instrument()->additionalResults();
1308 if (additionalResults.count("notional[2]") != 0 && additionalResults.count("notionalCurrency[2]") != 0) {
1309 notional2 = trade->instrument()->qlInstrument()->result<Real>("notional[2]");
1310 notional2Ccy = trade->instrument()->qlInstrument()->result<string>("notionalCurrency[2]");
1311 }
1312
1313 if (notional2 != Null<Real>() && notional2Ccy != "") {
1314 Real fx = 1.0;
1315 if (notional2Ccy != baseCurrency)
1316 fx = market->fxRate(notional2Ccy + baseCurrency)->value();
1317 std::ostringstream oss;
1318 oss << std::fixed << std::setprecision(8) << notional2 * fx;
1319 // report.next().add(tradeId).add("notionalInBaseCurrency[2]").add("double").add(oss.str());
1320 }
1321
1322 // Just use the unadjusted trade ID in the additional results report for the main instrument.
1323 // If we have one or more additional instruments, use "_i" as suffix where i = 1, 2, 3, ... for each
1324 // additional instrument in turn and underscore as prefix to reduce risk of ID clash. We also add the
1325 // multiplier as an extra additional result if additional results exist.
1326 auto instruments = trade->instrument()->additionalInstruments();
1327 auto multipliers = trade->instrument()->additionalMultipliers();
1328 QL_REQUIRE(instruments.size() == multipliers.size(),
1329 "Expected the number of "
1330 << "additional instruments (" << instruments.size() << ") to equal the number of "
1331 << "additional multipliers (" << multipliers.size() << ").");
1332
1333 for (Size i = 0; i <= instruments.size(); ++i) {
1334
1335 if (i > 0 && instruments[i - 1] == nullptr)
1336 continue;
1337
1338 std::map<std::string, boost::any> thisAddResults =
1339 i == 0 ? additionalResults : instruments[i - 1]->additionalResults();
1340
1341 // Trade ID suffix for additional instruments. Put underscores to reduce risk of clash with other IDs in
1342 // the portfolio (still a risk).
1343 tradeId = i == 0 ? trade->id() : ("_" + trade->id() + "_" + std::to_string(i));
1344
1345 // Add the multiplier if there are additional results.
1346 // Check on 'instMultiplier' already existing is probably unnecessary.
1347 if (!thisAddResults.empty() && thisAddResults.count("instMultiplier") == 0) {
1348 thisAddResults["instMultiplier"] = i == 0 ? trade->instrument()->multiplier() : multipliers[i - 1];
1349 }
1350
1351 // Write current instrument's additional results.
1352 for (const auto& kv : thisAddResults) {
1353 // some results are stored as maps. We loop over these so that there is one result per line
1354 if (kv.second.type() == typeid(result_type_matrix)) {
1355 addMapResults<result_type_matrix>(kv.second, tradeId, kv.first, report);
1356 } else if (kv.second.type() == typeid(result_type_vector)) {
1357 addMapResults<result_type_vector>(kv.second, tradeId, kv.first, report);
1358 } else if (kv.second.type() == typeid(result_type_scalar)) {
1359 addMapResults<result_type_scalar>(kv.second, tradeId, kv.first, report);
1360 } else {
1361 auto p = parseBoostAny(kv.second, precision);
1362 if (boost::starts_with(p.first, "vector")) {
1363 vector<std::string> tokens;
1364 string vect = p.second;
1365 vect.erase(remove(vect.begin(), vect.end(), '\"'), vect.end());
1366 boost::split(tokens, vect, boost::is_any_of(","));
1367 for (Size i = 0; i < tokens.size(); i++) {
1368 boost::trim(tokens[i]);
1369 report.next()
1370 .add(tradeId)
1371 .add(kv.first + "[" + std::to_string(i) + "]")
1372 .add(p.first.substr(7))
1373 .add(tokens[i]);
1374 }
1375 } else
1376 report.next().add(tradeId).add(kv.first).add(p.first).add(p.second);
1377 }
1378 }
1379 }
1380 } catch (const std::exception& e) {
1381 StructuredTradeErrorMessage(trade->id(), trade->tradeType(),
1382 "Error during trade pricing (additional results)", e.what())
1383 .log();
1384 }
1385 }
1386
1387 report.end();
1388
1389 LOG("AdditionalResults report written");
1390}
pair< string, string > parseBoostAny(const boost::any &anyType, Size precision)
std::map< Currency, std::vector< Real >, CurrencyComparator > result_type_vector
std::map< Currency, Real, CurrencyComparator > result_type_scalar
std::map< Currency, Matrix, CurrencyComparator > result_type_matrix
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeMarketData()

void writeMarketData ( ore::data::Report report,
const QuantLib::ext::shared_ptr< ore::data::Loader > &  loader,
const QuantLib::Date &  asof,
const set< string > &  quoteNames,
bool  returnAll 
)
virtual

Definition at line 1397 of file reportwriter.cpp.

1398 {
1399
1400 LOG("Writing MarketData report");
1401
1402 report.addColumn("datumDate", Date()).addColumn("datumId", string()).addColumn("datumValue", double(), 10);
1403
1404 if (returnAll) {
1405 for (const auto& md : loader->loadQuotes(asof)) {
1406 addMarketDatum(report, *md, loader->actualDate());
1407 }
1408 return;
1409 }
1410
1411 set<string> names;
1412 set<string> regexStrs;
1413 partitionQuotes(quoteNames, names, regexStrs);
1414
1415 vector<std::regex> regexes;
1416 regexes.reserve(regexStrs.size());
1417 for (auto regexStr : regexStrs) {
1418 regexes.push_back(regex(regexStr));
1419 }
1420
1421 for (const auto& md : loader->loadQuotes(asof)) {
1422 const auto& mdName = md->name();
1423
1424 if (names.find(mdName) != names.end()) {
1425 addMarketDatum(report, *md, loader->actualDate());
1426 continue;
1427 }
1428
1429 // This could be slow
1430 for (const auto& regex : regexes) {
1431 if (regex_match(mdName, regex)) {
1432 addMarketDatum(report, *md, loader->actualDate());
1433 break;
1434 }
1435 }
1436 }
1437
1438 report.end();
1439 LOG("MarketData report written");
1440}
void addMarketDatum(ore::data::Report &report, const ore::data::MarketDatum &md, const QuantLib::Date &actualDate=Date())
void partitionQuotes(const set< string > &quoteNames, set< string > &names, set< string > &regexes)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeFixings()

void writeFixings ( ore::data::Report report,
const QuantLib::ext::shared_ptr< ore::data::Loader > &  loader 
)
virtual

Definition at line 1442 of file reportwriter.cpp.

1442 {
1443
1444 LOG("Writing Fixings report");
1445
1446 report.addColumn("fixingDate", Date()).addColumn("fixingId", string()).addColumn("fixingValue", double(), 10);
1447
1448 for (const auto& f : loader->loadFixings()) {
1449 report.next().add(f.date).add(f.name).add(f.fixing);
1450 }
1451
1452 report.end();
1453 LOG("Fixings report written");
1454}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeDividends()

void writeDividends ( ore::data::Report report,
const QuantLib::ext::shared_ptr< ore::data::Loader > &  loader 
)
virtual

Definition at line 1456 of file reportwriter.cpp.

1456 {
1457
1458 LOG("Writing Dividends report");
1459
1460 report.addColumn("dividendExDate", Date())
1461 .addColumn("equityId", string())
1462 .addColumn("dividendRate", double(), 10)
1463 .addColumn("dividendPaymentDate", Date());
1464
1465 for (const auto& f : loader->loadDividends()) {
1466 report.next().add(f.exDate).add(f.name).add(f.rate).add(f.payDate);
1467 }
1468
1469 report.end();
1470 LOG("Dividends report written");
1471}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writePricingStats()

void writePricingStats ( ore::data::Report report,
const QuantLib::ext::shared_ptr< Portfolio > &  portfolio 
)
virtual

Definition at line 1473 of file reportwriter.cpp.

1473 {
1474
1475 LOG("Writing Pricing stats report");
1476
1477 report.addColumn("TradeId", string())
1478 .addColumn("TradeType", string())
1479 .addColumn("NumberOfPricings", Size())
1480 .addColumn("CumulativeTiming", Size())
1481 .addColumn("AverageTiming", Size());
1482
1483 for (auto const& [tid, trade] : portfolio->trades()) {
1484 std::size_t num = trade->getNumberOfPricings();
1485 Size cumulative = trade->getCumulativePricingTime() / 1000;
1486 Size average = num > 0 ? cumulative / num : 0;
1487 report.next().add(tid).add(trade->tradeType()).add(num).add(cumulative).add(average);
1488 }
1489
1490 report.end();
1491 LOG("Pricing stats report written");
1492}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeCube()

void writeCube ( ore::data::Report report,
const QuantLib::ext::shared_ptr< NPVCube > &  cube,
const std::map< std::string, std::string > &  nettingSetMap = std::map<std::string, std::string>() 
)
virtual

Definition at line 1494 of file reportwriter.cpp.

1495 {
1496 LOG("Writing cube report");
1497
1498 report.addColumn("Id", string())
1499 .addColumn("NettingSet", string())
1500 .addColumn("DateIndex", Size())
1501 .addColumn("Date", string())
1502 .addColumn("Sample", Size())
1503 .addColumn("Depth", Size())
1504 .addColumn("Value", double(), 4);
1505
1506 const map<string, Size>& idsAndPos = cube->idsAndIndexes();
1507 vector<string> dateStrings(cube->numDates());
1508 for (Size i = 0; i < cube->numDates(); ++i) {
1509 std::ostringstream oss;
1510 oss << QuantLib::io::iso_date(cube->dates()[i]);
1511 dateStrings[i] = oss.str();
1512 }
1513
1514 std::ostringstream oss;
1515 oss << QuantLib::io::iso_date(cube->asof());
1516 string asofString = oss.str();
1517
1518 vector<string> ids(idsAndPos.size());
1519 vector<string> nettingSetIds(idsAndPos.size());
1520 for (const auto& [id, idCubePos] : idsAndPos) {
1521 ids[idCubePos] = id;
1522 auto it = nettingSetMap.find(id);
1523 if (it != nettingSetMap.end())
1524 nettingSetIds[idCubePos] = it->second;
1525 else
1526 nettingSetIds[idCubePos] = "";
1527 }
1528
1529 // T0
1530 for (Size i = 0; i < ids.size(); ++i) {
1531 report.next();
1532 report.add(ids[i])
1533 .add(nettingSetIds[i])
1534 .add(static_cast<Size>(0))
1535 .add(asofString)
1536 .add(static_cast<Size>(0))
1537 .add(static_cast<Size>(0))
1538 .add(cube->getT0(i));
1539 }
1540
1541 // Cube
1542 for (Size i = 0; i < ids.size(); i++) {
1543 for (Size j = 0; j < cube->numDates(); j++) {
1544 for (Size k = 0; k < cube->samples(); k++) {
1545 for (Size l = 0; l < cube->depth(); l++) {
1546 report.next();
1547 report.add(ids[i])
1548 .add(nettingSetIds[i])
1549 .add(j + 1)
1550 .add(dateStrings[j])
1551 .add(k+1)
1552 .add(l)
1553 .add(cube->get(i, j, k, l));
1554 }
1555 }
1556 }
1557 }
1558
1559 report.end();
1560
1561 LOG("Cube report written");
1562}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nullString()

const std::string & nullString ( ) const

Definition at line 132 of file reportwriter.hpp.

132{ return nullString_; }

◆ writeSIMMReport() [1/2]

virtual void writeSIMMReport ( const std::map< SimmConfiguration::SimmSide, std::map< NettingSetDetails, std::pair< std::string, SimmResults > > > &  simmResultsMap,
const QuantLib::ext::shared_ptr< ore::data::Report report,
const bool  hasNettingSetDetails = false,
const std::string &  simmResultCcy = "",
const std::string &  simmCalcCcyCall = "",
const std::string &  simmCalcCcyPost = "",
const std::string &  reportCcy = "",
QuantLib::Real  fxSpot = 1.0,
QuantLib::Real  outputThreshold = 0.005 
)
virtual

Write out the SIMM results contained in the resultsMap and additionalMargin. The parameter resultsMap is a map containing the SIMM results containers for a set of portfolios. The key is the portfolio ID and the value is the SIMM results container for that portfolio. Similarly, the parameter additionalMargin contains the additional margin element for each portfolio.

+ Here is the caller graph for this function:

◆ writeSIMMReport() [2/2]

virtual void writeSIMMReport ( const std::map< SimmConfiguration::SimmSide, std::map< NettingSetDetails, std::map< std::string, SimmResults > > > &  simmResultsMap,
const QuantLib::ext::shared_ptr< ore::data::Report report,
const bool  hasNettingSetDetails = false,
const std::string &  simmResultCcy = "",
const std::string &  simmCalcCcyCall = "",
const std::string &  simmCalcCcyPost = "",
const std::string &  reportCcy = "",
const bool  isFinalSimm = true,
QuantLib::Real  fxSpot = 1.0,
QuantLib::Real  outputThreshold = 0.005 
)
virtual

◆ writeSIMMData()

void writeSIMMData ( const ore::analytics::Crif simmData,
const QuantLib::ext::shared_ptr< ore::data::Report > &  dataReport,
const bool  hasNettingSetDetails = false 
)
virtual

Write the SIMM data report i.e. the netted CRIF records used in a SIMM calculation.

Definition at line 1736 of file reportwriter.cpp.

1737 {
1738
1739 LOG("Writing SIMM data report.");
1740
1741 // Add the headers to the report
1742
1743 bool hasRegulations = false;
1744 for (const auto& cr : simmData) {
1745 if (!cr.collectRegulations.empty() || !cr.postRegulations.empty()) {
1746 hasRegulations = true;
1747 break;
1748 }
1749 }
1750
1751 // netting set headers
1752 dataReport->addColumn("Portfolio", string());
1753 if (hasNettingSetDetails) {
1754 for (const string& field : NettingSetDetails::optionalFieldNames())
1755 dataReport->addColumn(field, string());
1756 }
1757
1758 dataReport->addColumn("RiskType", string())
1759 .addColumn("ProductClass", string())
1760 .addColumn("Bucket", string())
1761 .addColumn("Qualifier", string())
1762 .addColumn("Label1", string())
1763 .addColumn("Label2", string())
1764 .addColumn("Amount", double())
1765 .addColumn("IMModel", string());
1766
1767 if (hasRegulations)
1768 dataReport->addColumn("collect_regulations", string())
1769 .addColumn("post_regulations", string());
1770
1771 // Write the report body by looping over the netted CRIF records
1772 for (const auto& cr : simmData) {
1773 // Skip to next netted CRIF record if 'AmountUSD' is negligible
1774 if (close_enough(cr.amountUsd, 0.0))
1775 continue;
1776
1777 // Skip Schedule IM records
1778 if (cr.imModel == "Schedule")
1779 continue;
1780
1781 // Same check as above, but for backwards compatibility, if im_model is not used
1782 // but Risk::Type is PV or Notional
1783 if (cr.imModel.empty() &&
1784 (cr.riskType == CrifRecord::RiskType::Notional || cr.riskType == CrifRecord::RiskType::PV))
1785 continue;
1786
1787 // Write current netted CRIF record
1788 dataReport->next();
1789 map<string, string> nettingSetMap = cr.nettingSetDetails.mapRepresentation();
1790 for (const string& field : NettingSetDetails::fieldNames(hasNettingSetDetails))
1791 dataReport->add(nettingSetMap[field]);
1792 dataReport->add(ore::data::to_string(cr.riskType))
1793 .add(ore::data::to_string(cr.productClass))
1794 .add(cr.bucket)
1795 .add(cr.qualifier)
1796 .add(cr.label1)
1797 .add(cr.label2)
1798 .add(cr.amountUsd)
1799 .add(cr.imModel);
1800
1801 if (hasRegulations) {
1802 string collectRegString = cr.collectRegulations.find(',') == string::npos
1803 ? cr.collectRegulations
1804 : '\"' + cr.collectRegulations + '\"';
1805 string postRegString = cr.postRegulations.find(',') == string::npos
1806 ? cr.postRegulations
1807 : '\"' + cr.postRegulations + '\"';
1808
1809 dataReport->add(collectRegString)
1810 .add(postRegString);
1811 }
1812 }
1813
1814 dataReport->end();
1815
1816 LOG("SIMM data report written.");
1817}
static const vector< string > optionalFieldNames()
static const vector< string > fieldNames(bool includeOptionalFields=true)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeCrifReport()

void writeCrifReport ( const QuantLib::ext::shared_ptr< ore::data::Report > &  report,
const ore::analytics::Crif crifRecords 
)
virtual

Write out CRIF records to a report.

Definition at line 1819 of file reportwriter.cpp.

1819 {
1820
1821 // If we have SIMM parameters, check if at least one of them uses netting set details optional field/s
1822 // It is easier to check here than to pass the flag from other places, since otherwise we'd have to handle certain edge cases
1823 // e.g. SIMM parameters use optional NSDs, but trades don't. So SIMM report should not display NSDs, but CRIF report still should.
1824 bool hasNettingSetDetails = false;
1825 for (const auto& cr : crif) {
1826 if (!cr.nettingSetDetails.emptyOptionalFields())
1827 hasNettingSetDetails = true;
1828 }
1829
1830 std::vector<string> addFields;
1831 bool hasCollectRegulations = false;
1832 bool hasPostRegulations = false;
1833 bool hasScheduleTrades = false;
1834 for (const auto& cr : crif) {
1835 // Check which additional fields are being used/populated
1836 for (const auto& af : cr.additionalFields) {
1837 if (std::find(addFields.begin(), addFields.end(), af.first) == addFields.end()) {
1838 addFields.push_back(af.first);
1839 }
1840 }
1841
1842 // Check if regulations are being used
1843 if (!hasCollectRegulations)
1844 hasCollectRegulations = !cr.collectRegulations.empty();
1845 if (!hasPostRegulations)
1846 hasPostRegulations = !cr.postRegulations.empty();
1847
1848 // Check if there are Schedule trades
1849 if (!hasScheduleTrades) {
1850 try {
1851 hasScheduleTrades = parseIMModel(cr.imModel) == SimmConfiguration::IMModel::Schedule;
1852 } catch (std::exception&) {
1853 }
1854 }
1855 }
1856
1857 // Add report headers
1858
1859 report->addColumn("TradeID", string()).addColumn("PortfolioID", string());
1860
1861 // Add additional netting set fields if netting set details are being used instead of just the netting set ID
1862 if (hasNettingSetDetails) {
1863 for (const string& optionalField : NettingSetDetails::optionalFieldNames())
1864 report->addColumn(optionalField, string());
1865 }
1866
1867 report->addColumn("ProductClass", string())
1868 .addColumn("RiskType", string())
1869 .addColumn("Qualifier", string())
1870 .addColumn("Bucket", string())
1871 .addColumn("Label1", string())
1872 .addColumn("Label2", string())
1873 .addColumn("AmountCurrency", string())
1874 .addColumn("Amount", double(), 2)
1875 .addColumn("AmountUSD", double(), 2)
1876 .addColumn("IMModel", string())
1877 .addColumn("TradeType", string());
1878
1879 if (hasScheduleTrades || crif.type() == Crif::CrifType::Frtb)
1880 report->addColumn("end_date", string());
1881
1882 if (crif.type() == Crif::CrifType::Frtb) {
1883 report->addColumn("Label3", string())
1884 .addColumn("CreditQuality", string())
1885 .addColumn("LongShortInd", string())
1886 .addColumn("CoveredBondInd", string())
1887 .addColumn("TrancheThickness", string())
1888 .addColumn("BB_RW", string());
1889 }
1890
1891 if (hasCollectRegulations)
1892 report->addColumn("collect_regulations", string());
1893
1894 if (hasPostRegulations)
1895 report->addColumn("post_regulations", string());
1896
1897 // Add additional CRIF fields
1898 for (const string& f : addFields) {
1899 report->addColumn(f, string());
1900 }
1901
1902 // Write individual CRIF records
1903 for (const auto& cr : crif) {
1904
1905 report->next().add(cr.tradeId).add(cr.portfolioId);
1906
1907 if (hasNettingSetDetails) {
1908 map<string, string> crNettingSetDetailsMap = NettingSetDetails(cr.nettingSetDetails).mapRepresentation();
1909 for (const string& optionalField : NettingSetDetails::optionalFieldNames())
1910 report->add(crNettingSetDetailsMap[optionalField]);
1911 }
1912
1913 report->add(ore::data::to_string(cr.productClass))
1914 .add(ore::data::to_string(cr.riskType))
1915 .add(cr.qualifier)
1916 .add(cr.bucket)
1917 .add(cr.label1)
1918 .add(cr.label2)
1919 .add(cr.amountCurrency)
1920 .add(cr.amount)
1921 .add(cr.amountUsd)
1922 .add(cr.imModel)
1923 .add(cr.tradeType);
1924
1925 if (hasScheduleTrades || crif.type() == Crif::CrifType::Frtb)
1926 report->add(cr.endDate);
1927
1928 if (crif.type() == Crif::CrifType::Frtb) {
1929 report->add(cr.label3)
1930 .add(cr.creditQuality)
1931 .add(cr.longShortInd)
1932 .add(cr.coveredBondInd)
1933 .add(cr.trancheThickness)
1934 .add(cr.bb_rw);
1935 }
1936
1937 if (hasCollectRegulations) {
1938 string regString = escapeCommaSeparatedList(cr.collectRegulations, '\0');
1939 report->add(regString);
1940 }
1941
1942 if (hasPostRegulations) {
1943 string regString = escapeCommaSeparatedList(cr.postRegulations, '\0');
1944 report->add(regString);
1945 }
1946
1947 for (const string& af : addFields) {
1948 if (cr.additionalFields.find(af) == cr.additionalFields.end())
1949 report->add("");
1950 else
1951 report->add(cr.getAdditionalFieldAsStr(af));
1952 }
1953 }
1954
1955 report->end();
1956}
SimmConfiguration::IMModel parseIMModel(const string &model)
std::string escapeCommaSeparatedList(const std::string &str, const char &csvQuoteChar)
Definition: utilities.cpp:248
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeScenarioStatistics()

void writeScenarioStatistics ( const QuantLib::ext::shared_ptr< ore::analytics::ScenarioGenerator > &  generator,
const std::vector< ore::analytics::RiskFactorKey > &  keys,
QuantLib::Size  numPaths,
const std::vector< QuantLib::Date > &  dates,
ore::data::Report report 
)
virtual

Definition at line 1958 of file reportwriter.cpp.

1960 {
1961 report.addColumn("Date", Date())
1962 .addColumn("Key", string())
1963 .addColumn("min", double(), 8)
1964 .addColumn("mean", double(), 8)
1965 .addColumn("max", double(), 8)
1966 .addColumn("stddev", double(), 8)
1967 .addColumn("skewness", double(), 8)
1968 .addColumn("kurtosis", double(), 8);
1969
1970 std::vector<boost::accumulators::accumulator_set<
1971 double, boost::accumulators::stats<boost::accumulators::tag::min, boost::accumulators::tag::max,
1972 boost::accumulators::tag::mean, boost::accumulators::tag::variance,
1973 boost::accumulators::tag::skewness, boost::accumulators::tag::kurtosis>>>
1974 acc(keys.size() * dates.size());
1975
1976 for (Size i = 0; i < numPaths; ++i) {
1977 for (Size d = 0; d < dates.size(); ++d) {
1978 QuantLib::ext::shared_ptr<Scenario> currentScenario = generator->next(dates[d]);
1979 for (Size k = 0; k < keys.size(); ++k) {
1980 acc[d * keys.size() + k](currentScenario->get(keys[k]));
1981 }
1982 }
1983 }
1984 for (Size d = 0; d < dates.size(); ++d) {
1985 for (Size k = 0; k < keys.size(); ++k) {
1986 Size idx = d * keys.size() + k;
1987 report.next()
1988 .add(dates[d])
1989 .add(ore::data::to_string(keys[k]))
1990 .add(boost::accumulators::min(acc[idx]))
1991 .add(boost::accumulators::mean(acc[idx]))
1992 .add(boost::accumulators::max(acc[idx]))
1993 .add(std::sqrt(boost::accumulators::variance(acc[idx])));
1994 if (!close_enough(boost::accumulators::variance(acc[idx]), 0.0)) {
1995 report.add(boost::accumulators::skewness(acc[idx])).add(boost::accumulators::kurtosis(acc[idx]));
1996 }
1997 else {
1998 // avoid ReportWriter::non-sensical output
1999 report.add(0.0).add(0.0);
2000 }
2001 }
2002 }
2003 report.end();
2004}
Matrix generator(const Matrix &t, const Real horizon)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeScenarioDistributions()

void writeScenarioDistributions ( const QuantLib::ext::shared_ptr< ore::analytics::ScenarioGenerator > &  generator,
const std::vector< ore::analytics::RiskFactorKey > &  keys,
QuantLib::Size  numPaths,
const std::vector< QuantLib::Date > &  dates,
QuantLib::Size  distSteps,
ore::data::Report report 
)
virtual

Definition at line 2029 of file reportwriter.cpp.

2032 {
2033 report.addColumn("Date", Date())
2034 .addColumn("Key", string())
2035 .addColumn("Bound", double(), 8)
2036 .addColumn("Count", Size());
2037
2038 std::vector<std::vector<std::vector<Real>>> values(
2039 dates.size(), std::vector<std::vector<Real>>(keys.size(), std::vector<Real>(numPaths, 0.0)));
2040
2041 for (Size i = 0; i < numPaths; ++i) {
2042 for (Size d = 0; d < dates.size(); ++d) {
2043 QuantLib::ext::shared_ptr<Scenario> currentScenario = generator->next(dates[d]);
2044 for (Size k = 0; k < keys.size(); ++k) {
2045 values[d][k][i] = currentScenario->get(keys[k]);
2046 }
2047 }
2048 }
2049
2050 std::vector<Real> bounds;
2051 std::vector<Size> counts;
2052 for (Size d = 0; d < dates.size(); ++d) {
2053 for (Size k = 0; k < keys.size(); ++k) {
2054 distributionCount(values[d][k].begin(), values[d][k].end(), distSteps, bounds, counts);
2055 for (Size i = 0; i < distSteps; ++i) {
2056 report.next().add(dates[d]).add(ore::data::to_string(keys[k])).add(bounds[i]).add(counts[i]);
2057 }
2058 }
2059 }
2060 report.end();
2061}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeHistoricalScenarioDetails()

void writeHistoricalScenarioDetails ( const QuantLib::ext::shared_ptr< ore::analytics::HistoricalScenarioGenerator > &  generator,
ore::data::Report report 
)
virtual

Definition at line 2063 of file reportwriter.cpp.

2064 {
2065
2066 report.addColumn("PLDate1", Date())
2067 .addColumn("PLDate2", Date())
2068 .addColumn("Key", string())
2069 .addColumn("BaseValue", double(), 8)
2070 .addColumn("AdjustmentFactor1", double(), 8)
2071 .addColumn("AdjustmentFactor2", double(), 8)
2072 .addColumn("ScenarioValue1", double(), 8)
2073 .addColumn("ScenarioValue2", double(), 8)
2074 .addColumn("ShiftType", string())
2075 .addColumn("Return", double(), 8)
2076 .addColumn("ScenarioValue", double(), 8);
2077
2078 Date asof = generator->baseScenario()->asof();
2079 for (Size i = 0; i < generator->startDates().size(); ++i) {
2080 std::ignore = generator->next(asof);
2081 for (auto const& d : generator->lastHistoricalScenarioCalculationDetails()) {
2082 report.next()
2083 .add(d.scenarioDate1)
2084 .add(d.scenarioDate2)
2085 .add(ore::data::to_string(d.key))
2086 .add(d.baseValue)
2087 .add(d.adjustmentFactor1)
2088 .add(d.adjustmentFactor2)
2089 .add(d.scenarioValue1)
2090 .add(d.scenarioValue2)
2091 .add(ore::data::to_string(d.returnType))
2092 .add(d.returnValue)
2093 .add(d.scenarioValue);
2094 }
2095 }
2096 report.end();
2097}
Size size(const ValueType &v)
+ Here is the call graph for this function:

◆ writeStockSplitReport()

void writeStockSplitReport ( const QuantLib::ext::shared_ptr< ore::analytics::Scenario > &  baseScenario,
const QuantLib::ext::shared_ptr< ore::analytics::HistoricalScenarioLoader > &  hsloader,
const QuantLib::ext::shared_ptr< ore::data::AdjustmentFactors > &  adjFactors,
const QuantLib::ext::shared_ptr< ore::data::Report > &  report 
)
virtual

Definition at line 2099 of file reportwriter.cpp.

2102 {
2103
2104 report->addColumn("EquityId", string())
2105 .addColumn("Date", Date())
2106 .addColumn("Price", double(), 8)
2107 .addColumn("Factor", double(), 8)
2108 .addColumn("CumulatedFactor", double(), 8)
2109 .addColumn("AdjustedPrice", double(), 8);
2110
2111 if (adjFactors) {
2112 std::set<std::string> names;
2113 for (auto const& k : baseScenario->keys()) {
2114 if (k.keytype == RiskFactorKey::KeyType::EquitySpot) {
2115 names.insert(k.name);
2116 }
2117 }
2118
2119 std::vector<QuantLib::Date> hsdates = hsloader->dates();
2120
2121 for (auto const& name : names) {
2122
2123 std::set<QuantLib::Date> dates = adjFactors->dates(name);
2124 dates.insert(hsdates.begin(), hsdates.end());
2125
2126 for (auto const& d : dates) {
2127
2128 Real price = Null<Real>();
2129 if (std::find(hsdates.begin(), hsdates.end(), d) != hsdates.end()) {
2130 auto scen = hsloader->getHistoricalScenario(d);
2131 RiskFactorKey rf(RiskFactorKey::KeyType::EquitySpot, name);
2132 if (scen->has(rf))
2133 price = scen->get(rf);
2134 }
2135 Real factor = adjFactors->getFactorContribution(name, d);
2136 Real cumFactor = adjFactors->getFactor(name, d);
2137 Real adjPrice = price == Null<Real>() ? Null<Real>() : price * cumFactor;
2138
2139 report->next().add(name).add(d).add(price).add(factor).add(cumFactor).add(adjPrice);
2140 }
2141 }
2142 }
2143 report->end();
2144}

◆ writeHistoricalScenarios()

void writeHistoricalScenarios ( const QuantLib::ext::shared_ptr< HistoricalScenarioLoader > &  hsloader,
const QuantLib::ext::shared_ptr< ore::data::Report > &  report 
)

Definition at line 2189 of file reportwriter.cpp.

2190 {
2191 // each scenario might have a different set of keys, so we collect the union of all keys
2192 // and write them out (missing keys will be written as NA to the report)
2193 std::set<RiskFactorKey> allKeys;
2194 for (const auto& s : hsloader->historicalScenarios())
2195 allKeys.insert(s->keys().begin(), s->keys().end());
2196 ScenarioWriter sw(nullptr, report, std::vector<RiskFactorKey>(allKeys.begin(), allKeys.end()));
2197 bool writeHeader = true;
2198 for (const auto& s : hsloader->historicalScenarios()) {
2199 sw.writeScenario(s, writeHeader);
2200 writeHeader = false;
2201 }
2202}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeHistoricalScenarioDistributions()

void writeHistoricalScenarioDistributions ( QuantLib::ext::shared_ptr< HistoricalScenarioGenerator > &  hsgen,
const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarket > &  simMarket,
const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarketParameters > &  simMarketParams,
QuantLib::ext::shared_ptr< ore::data::Report histScenDetailsReport,
QuantLib::ext::shared_ptr< ore::data::Report statReport,
QuantLib::ext::shared_ptr< ore::data::Report distReport,
QuantLib::Size  distSteps = Null<Size>() 
)

Definition at line 2146 of file reportwriter.cpp.

2151 {
2152
2153 // Don't leave it up to the caller to do this
2154 simMarket->scenarioGenerator() = hsgen;
2155 hsgen->baseScenario() = simMarket->baseScenario();
2156
2157 // If both report pointers are null, return early
2158 if (!statReport && !distReport)
2159 return;
2160
2161 // Make a transformed generator i.e. discount -> zero etc.
2162 auto hsgent = QuantLib::ext::make_shared<HistoricalScenarioGeneratorTransform>(hsgen, simMarket, simMarketParams);
2163
2164 const vector<RiskFactorKey>& keys = hsgen->baseScenario()->keys();
2165 Size numScen = hsgen->numScenarios();
2166 Date asof = hsgen->baseScenario()->asof();
2167
2168 // Write the statistics report if requested
2169 if (statReport) {
2170 hsgent->reset();
2171 writeScenarioStatistics(hsgent, keys, numScen, {asof}, *statReport);
2172 }
2173
2174 // Write the distribution report if requested
2175 if (distReport) {
2176 QL_REQUIRE(distSteps != Null<Size>(),
2177 "When creating a distribution report, a valid distribution step size is required");
2178 hsgent->reset();
2179 writeScenarioDistributions(hsgent, keys, numScen, {asof}, distSteps, *distReport);
2180 }
2181
2182 // Write the scenario report if requested
2183 if (histScenDetailsReport) {
2184 hsgent->reset();
2185 writeHistoricalScenarioDetails(hsgent, *histScenDetailsReport);
2186 }
2187}
virtual void writeHistoricalScenarioDetails(const QuantLib::ext::shared_ptr< ore::analytics::HistoricalScenarioGenerator > &generator, ore::data::Report &report)
virtual void writeScenarioStatistics(const QuantLib::ext::shared_ptr< ore::analytics::ScenarioGenerator > &generator, const std::vector< ore::analytics::RiskFactorKey > &keys, QuantLib::Size numPaths, const std::vector< QuantLib::Date > &dates, ore::data::Report &report)
virtual void writeScenarioDistributions(const QuantLib::ext::shared_ptr< ore::analytics::ScenarioGenerator > &generator, const std::vector< ore::analytics::RiskFactorKey > &keys, QuantLib::Size numPaths, const std::vector< QuantLib::Date > &dates, QuantLib::Size distSteps, ore::data::Report &report)
+ Here is the call graph for this function:

◆ writeIMScheduleSummaryReport()

void writeIMScheduleSummaryReport ( const std::map< SimmConfiguration::SimmSide, std::map< NettingSetDetails, std::pair< std::string, IMScheduleResults > > > &  finalResultsMap,
const QuantLib::ext::shared_ptr< Report report,
const bool  hasNettingSetDetails = false,
const std::string &  simmResultCcy = "",
const std::string &  reportCcy = "",
QuantLib::Real  fxSpot = 1.0,
QuantLib::Real  outputThreshold = 0.005 
)
virtual

Definition at line 2211 of file reportwriter.cpp.

2214 {
2215
2216 LOG("Writing IM Schedule results summary report.");
2217
2218 // netting set headers
2219 report->addColumn("Portfolio", string());
2220 if (hasNettingSetDetails) {
2221 for (const string& field : NettingSetDetails::optionalFieldNames())
2222 report->addColumn(field, string());
2223 }
2224
2225 report->addColumn("ProductClass", string())
2226 .addColumn("GrossIM", double(), 2)
2227 .addColumn("GrossCurrentRC", double(), 2)
2228 .addColumn("NetCurrentRC", double(), 2)
2229 .addColumn("NetToGrossRatio", double(), 6)
2230 .addColumn("Side", string())
2231 .addColumn("Regulation", string())
2232 .addColumn("ScheduleIM", double(), 2)
2233 .addColumn("Currency", string());
2234 if (!reportCcy.empty()) {
2235 report->addColumn("ScheduleIM(Report)", double(), 2).addColumn("ReportCurrency", string());
2236 }
2237
2238 const vector<SimmSide> sides({SimmSide::Call, SimmSide::Post});
2239 for (const SimmSide side : sides) {
2240 const string& sideString = to_string(side);
2241
2242 // Variable to hold sum of schedule IM over all portfolios
2243 Real sumSideScheduleIM = 0.0;
2244 Real sumSideScheduleIMReporting = 0.0;
2245
2246 std::set<std::string> winningRegs;
2247 if (finalResultsMap.find(side) != finalResultsMap.end()) {
2248 for (const auto& nv : finalResultsMap.at(side)) {
2249 const NettingSetDetails& portfolioId = nv.first;
2250 const string& regulation = nv.second.first;
2251 const IMScheduleResults& results = nv.second.second;
2252
2253 winningRegs.insert(regulation);
2254
2255 QL_REQUIRE(results.currency() == simmResultCcy,
2256 "writeIMScheduleSummaryReport(): IMSchedule results ("
2257 << results.currency() << ") should be denominated in the SIMM result currency ("
2258 << simmResultCcy << ").");
2259
2260 // Loop over the results for this portfolio
2261 for (const auto& imScheduleResult : results.data()) {
2262 ProductClass pc = imScheduleResult.first;
2263 IMScheduleResult result = imScheduleResult.second;
2264
2265 Real im = pc == ProductClass::All ? result.scheduleIM : result.grossIM;
2266
2267 report->next();
2268 const map<string, string> nettingSetMap = portfolioId.mapRepresentation();
2269 for (const string& field : NettingSetDetails::fieldNames(hasNettingSetDetails)) {
2270 report->add(nettingSetMap.at(field));
2271 }
2272 report->add(to_string(pc))
2273 .add(result.grossIM)
2274 .add(result.grossRC)
2275 .add(result.netRC)
2276 .add(result.NGR)
2277 .add(sideString)
2278 .add(regulation)
2279 .add(im)
2280 .add(results.currency());
2281
2282 if (!reportCcy.empty()) {
2283 Real scheduleIMReporting = im * fxSpot;
2284 report->add(scheduleIMReporting).add(reportCcy);
2285
2286 if (pc == ProductClass::All)
2287 sumSideScheduleIMReporting += scheduleIMReporting;
2288 }
2289
2290 if (pc == ProductClass::All)
2291 sumSideScheduleIM += result.scheduleIM;
2292 }
2293 }
2294 }
2295
2296 // Write out a row for the aggregate IM over all portfolios
2297 // We only write out this row if either reporting ccy was provided or if currency of all the results is the same
2298 string finalWinningReg = winningRegs.size() == 1 ? *(winningRegs.begin()) : "";
2299
2300 // Write out common columns
2301 report->next();
2302 Size numNettingSetFields = NettingSetDetails::fieldNames(hasNettingSetDetails).size();
2303 for (Size t = 0; t < numNettingSetFields; t++)
2304 report->add("All");
2305 report->add(to_string(ProductClass::All))
2306 .add(Null<Real>())
2307 .add(Null<Real>())
2308 .add(Null<Real>())
2309 .add(Null<Real>())
2310 .add(sideString)
2311 .add(finalWinningReg)
2312 .add(sumSideScheduleIM)
2313 .add(simmResultCcy);
2314
2315 // Write out schedule IM in reporting currency if we can
2316 if (!reportCcy.empty())
2317 report->add(sumSideScheduleIMReporting).add(reportCcy);
2318 }
2319
2320 report->end();
2321
2322 LOG("IM Schedule results summary report written.");
2323}
CrifRecord::ProductClass ProductClass
SimmConfiguration::SimmSide SimmSide
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeIMScheduleTradeReport()

void writeIMScheduleTradeReport ( const std::map< std::string, std::vector< IMScheduleCalculator::IMScheduleTradeData > > &  tradeResults,
const QuantLib::ext::shared_ptr< ore::data::Report report,
const bool  hasNettingSetDetails = false 
)
virtual

Definition at line 2325 of file reportwriter.cpp.

2327 {
2328
2329 LOG("Writing IM Schedule trade results report.");
2330
2331 report->addColumn("TradeId", string());
2332
2333 // netting set headers
2334 report->addColumn("Portfolio", string());
2335 if (hasNettingSetDetails) {
2336 for (const string& field : NettingSetDetails::optionalFieldNames())
2337 report->addColumn(field, string());
2338 }
2339
2340 report->addColumn("ProductClass", string())
2341 .addColumn("EndDate", string())
2342 .addColumn("Maturity", double(), 5)
2343 .addColumn("Label", string())
2344 .addColumn("Multiplier", double(), 2)
2345 .addColumn("Notional", double(), 2)
2346 .addColumn("NotionalCurrency", string())
2347 .addColumn("PV", double(), 2)
2348 .addColumn("PVCurrency", string())
2349 .addColumn("Notional(Base)", double(), 2)
2350 .addColumn("PV(Base)", double(), 2)
2351 .addColumn("BaseCurrency", string())
2352 .addColumn("GrossIM(Base)", double(), 2)
2353 .addColumn("CollectRegulations", string())
2354 .addColumn("PostRegulations", string());
2355
2356 // Variable to hold sum of schedule IM over all portfolios
2357 for (const auto& kv : tradeResults) {
2358 const string& tradeId = kv.first;
2359
2360 for (const IMScheduleTradeData& tradeData : kv.second) {
2361 const NettingSetDetails& portfolioId = tradeData.nettingSetDetails;
2362
2363 // Write row if IM not negligible relative to outputThreshold.
2364 report->next();
2365 report->add(tradeId);
2366
2367 const map<string, string> nettingSetMap = portfolioId.mapRepresentation();
2368 for (const string& field : NettingSetDetails::fieldNames(hasNettingSetDetails)) {
2369 report->add(nettingSetMap.at(field));
2370 }
2371 const string collectRegsString = tradeData.collectRegulations.find(',') == string::npos
2372 ? tradeData.collectRegulations
2373 : '\"' + tradeData.collectRegulations + '\"';
2374 const string postRegsString = tradeData.postRegulations.find(',') == string::npos
2375 ? tradeData.postRegulations
2376 : '\"' + tradeData.postRegulations + '\"';
2377 report->add(to_string(tradeData.productClass))
2378 .add(to_string(tradeData.endDate))
2379 .add(tradeData.maturity)
2380 .add(tradeData.labelString)
2381 .add(tradeData.multiplier)
2382 .add(tradeData.notional)
2383 .add(tradeData.notionalCcy)
2384 .add(tradeData.presentValue)
2385 .add(tradeData.presentValueCcy)
2386 .add(tradeData.notionalCalc)
2387 .add(tradeData.presentValueCalc)
2388 .add(tradeData.calculationCcy)
2389 .add(tradeData.grossMarginCalc)
2390 .add(collectRegsString)
2391 .add(postRegsString);
2392 }
2393 }
2394
2395 report->end();
2396
2397 LOG("IM Schedule trade results report written.");
2398}
IMScheduleCalculator::IMScheduleTradeData IMScheduleTradeData
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writePnlReport()

void writePnlReport ( ore::data::Report report,
const ext::shared_ptr< InMemoryReport > &  t0NpvReport,
const ext::shared_ptr< InMemoryReport > &  t0NpvLaggedReport,
const ext::shared_ptr< InMemoryReport > &  t1NpvLaggedReport,
const ext::shared_ptr< InMemoryReport > &  t1NpvReport,
const ext::shared_ptr< InMemoryReport > &  t0CashFlowReport,
const Date &  startDate,
const Date &  endDate,
const std::string &  baseCurrency,
const ext::shared_ptr< ore::data::Market > &  market,
const std::string &  configuration,
const ext::shared_ptr< Portfolio > &  portfolio 
)
virtual

Definition at line 2432 of file reportwriter.cpp.

2442 {
2443
2444 LOG("PnL report");
2445
2446 report.addColumn("TradeId", string())
2447 .addColumn("TradeType", string())
2448 .addColumn("Maturity", Date())
2449 .addColumn("MaturityTime", double(), 6)
2450 .addColumn("StartDate", Date())
2451 .addColumn("EndDate", Date())
2452 .addColumn("NPV(t0)", double(), 6)
2453 .addColumn("NPV(asof=t0;mkt=t1)", double(), 6)
2454 .addColumn("NPV(asof=t1;mkt=t0)", double(), 6)
2455 .addColumn("NPV(t1)", double(), 6)
2456 .addColumn("PeriodCashFlow", double(), 6)
2457 .addColumn("Theta", double(), 6)
2458 .addColumn("HypotheticalCleanPnL", double(), 6)
2459 .addColumn("CleanPnL", double(), 6)
2460 .addColumn("DirtyPnL", double(), 6)
2461 .addColumn("Currency", string());
2462
2463 Size tradeIdColumn = 0;
2464 Size tradeTypeColumn = 1;
2465 Size maturityDateColumn = 2;
2466 Size maturityTimeColumn = 3;
2467 Size npvBaseColumn = 6;
2468 Size baseCcyColumn = 7;
2469
2470 QL_REQUIRE(t0NpvReport->rows() == t0NpvLaggedReport->rows(), "different number of rows in npv reports");
2471 QL_REQUIRE(t0NpvReport->rows() == t1NpvLaggedReport->rows(), "different number of rows in npv reports");
2472 QL_REQUIRE(t0NpvReport->rows() == t1NpvReport->rows(), "different number of rows in npv reports");
2473
2474 QL_REQUIRE(t0NpvReport->header(tradeIdColumn) == "TradeId", "incorrect trade id column " << tradeIdColumn);
2475 QL_REQUIRE(t0NpvReport->header(tradeTypeColumn) == "TradeType", "incorrect trade type column " << tradeTypeColumn);
2476 QL_REQUIRE(t0NpvReport->header(maturityDateColumn) == "Maturity", "incorrect maturity date column " << maturityDateColumn);
2477 QL_REQUIRE(t0NpvReport->header(maturityTimeColumn) == "MaturityTime", "incorrect maturity time column " << maturityTimeColumn);
2478 QL_REQUIRE(t0NpvReport->header(npvBaseColumn) == "NPV(Base)", "incorrect npv base column " << npvBaseColumn);
2479 QL_REQUIRE(t0NpvReport->header(baseCcyColumn) == "BaseCurrency", "incorrect base currency column " << baseCcyColumn);
2480
2481 QL_REQUIRE(t0NpvLaggedReport->header(tradeIdColumn) == "TradeId", "incorrect trade id column " << tradeIdColumn);
2482 QL_REQUIRE(t0NpvLaggedReport->header(tradeTypeColumn) == "TradeType", "incorrect trade type column " << tradeTypeColumn);
2483 QL_REQUIRE(t0NpvLaggedReport->header(maturityDateColumn) == "Maturity", "incorrect maturity date column " << maturityDateColumn);
2484 QL_REQUIRE(t0NpvLaggedReport->header(maturityTimeColumn) == "MaturityTime", "incorrect maturity time column " << maturityTimeColumn);
2485 QL_REQUIRE(t0NpvLaggedReport->header(npvBaseColumn) == "NPV(Base)", "incorrect npv base column " << npvBaseColumn);
2486 QL_REQUIRE(t0NpvLaggedReport->header(baseCcyColumn) == "BaseCurrency", "incorrect base currency column " << baseCcyColumn);
2487
2488 QL_REQUIRE(t1NpvLaggedReport->header(tradeIdColumn) == "TradeId", "incorrect trade id column " << tradeIdColumn);
2489 QL_REQUIRE(t1NpvLaggedReport->header(tradeTypeColumn) == "TradeType", "incorrect trade type column " << tradeTypeColumn);
2490 QL_REQUIRE(t1NpvLaggedReport->header(maturityDateColumn) == "Maturity", "incorrect maturity date column " << maturityDateColumn);
2491 QL_REQUIRE(t1NpvLaggedReport->header(maturityTimeColumn) == "MaturityTime", "incorrect maturity time column " << maturityTimeColumn);
2492 QL_REQUIRE(t1NpvLaggedReport->header(npvBaseColumn) == "NPV(Base)", "incorrect npv base column " << npvBaseColumn);
2493 QL_REQUIRE(t1NpvLaggedReport->header(baseCcyColumn) == "BaseCurrency", "incorrect base currency column " << baseCcyColumn);
2494
2495 QL_REQUIRE(t1NpvReport->header(tradeIdColumn) == "TradeId", "incorrect trade id column " << tradeIdColumn);
2496 QL_REQUIRE(t1NpvReport->header(tradeTypeColumn) == "TradeType", "incorrect trade type column " << tradeTypeColumn);
2497 QL_REQUIRE(t1NpvReport->header(maturityDateColumn) == "Maturity", "incorrect maturity date column " << maturityDateColumn);
2498 QL_REQUIRE(t1NpvReport->header(maturityTimeColumn) == "MaturityTime", "incorrect maturity time column " << maturityTimeColumn);
2499 QL_REQUIRE(t1NpvReport->header(npvBaseColumn) == "NPV(Base)", "incorrect npv base column " << npvBaseColumn);
2500 QL_REQUIRE(t1NpvReport->header(baseCcyColumn) == "BaseCurrency", "incorrect base currency column " << baseCcyColumn);
2501
2502 for (Size i = 0; i < t0NpvReport->rows(); ++i) {
2503 try {
2504 string tradeId = boost::get<string>(t0NpvReport->data(tradeIdColumn).at(i));
2505 string tradeId2 = boost::get<string>(t0NpvLaggedReport->data(tradeIdColumn).at(i));
2506 string tradeId3 = boost::get<string>(t1NpvLaggedReport->data(tradeIdColumn).at(i));
2507 string tradeId4 = boost::get<string>(t1NpvReport->data(tradeIdColumn).at(i));
2508 QL_REQUIRE(tradeId == tradeId2 && tradeId == tradeId3 && tradeId == tradeId4, "inconsistent ordering of NPV reports");
2509 string tradeType = boost::get<string>(t0NpvReport->data(tradeTypeColumn).at(i));
2510 Date maturityDate = boost::get<Date>(t0NpvReport->data(maturityDateColumn).at(i));
2511 Real maturityTime = boost::get<Real>(t0NpvReport->data(maturityTimeColumn).at(i));
2512 string ccy = boost::get<string>(t0NpvReport->data(baseCcyColumn).at(i));
2513 QL_REQUIRE(ccy == baseCurrency, "inconsistent NPV and base currencies");
2514 Real t0Npv = boost::get<Real>(t0NpvReport->data(npvBaseColumn).at(i));
2515 Real t0NpvLagged = boost::get<Real>(t0NpvLaggedReport->data(npvBaseColumn).at(i));
2516 Real t1NpvLagged = boost::get<Real>(t1NpvLaggedReport->data(npvBaseColumn).at(i));
2517 Real t1Npv = boost::get<Real>(t1NpvReport->data(npvBaseColumn).at(i));
2518
2519 Real hypotheticalCleanPnl = t0NpvLagged - t0Npv;
2520 Real periodFlow = aggregateTradeFlow(tradeId, startDate, endDate, t0CashFlowReport, market, baseCurrency);
2521 Real theta = t1NpvLagged - t0Npv + periodFlow;
2522 Real dirtyPnl = t1Npv - t0Npv;
2523 Real cleanPnl = dirtyPnl + periodFlow;
2524 LOG("PnL report, writing line " << i << " tradeId " << tradeId);
2525
2526 report.next()
2527 .add(tradeId)
2528 .add(tradeType)
2529 .add(maturityDate)
2530 .add(maturityTime)
2531 .add(startDate)
2532 .add(endDate)
2533 .add(t0Npv)
2534 .add(t0NpvLagged)
2535 .add(t1NpvLagged)
2536 .add(t1Npv)
2537 .add(periodFlow)
2538 .add(theta)
2539 .add(hypotheticalCleanPnl)
2540 .add(cleanPnl)
2541 .add(dirtyPnl)
2542 .add(ccy);
2543
2544 } catch (std::exception& e) {
2545 ALOG("Error writing PnL report line: " << e.what());
2546 }
2547 }
2548
2549 report.end();
2550
2551 LOG("PnL report written.");
2552}
Real aggregateTradeFlow(const std::string &tradeId, const Date &d0, const Date &d1, const ext::shared_ptr< InMemoryReport > &cashFlowReport, const ext::shared_ptr< ore::data::Market > &market, const std::string &baseCurrency)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addMarketDatum()

void addMarketDatum ( ore::data::Report report,
const ore::data::MarketDatum md,
const QuantLib::Date &  actualDate = Date() 
)
protected

Definition at line 1392 of file reportwriter.cpp.

1392 {
1393 const Date& d = actualDate == Null<Date>() ? md.asofDate() : actualDate;
1394 report.next().add(d).add(md.name()).add(md.quote()->value());
1395}
const Handle< Quote > & quote() const
const string & name() const
+ Here is the call graph for this function:

Member Data Documentation

◆ nullString_

std::string nullString_
protected

Definition at line 216 of file reportwriter.hpp.