20#include <qle/math/stoplightbounds.hpp>
38 QL_REQUIRE(
types_.size() ==
reports_.size(),
"types and reports must be the same length");
41 QL_FAIL(
"Cannot find report");
43 auto index = std::distance(
types_.begin(), it);
49 const std::string& calculationCurrency,
50 const QuantLib::ext::shared_ptr<Portfolio>& portfolio,
51 const std::string& portfolioFilter,
52 std::unique_ptr<BacktestArgs> btArgs,
53 std::unique_ptr<SensiRunArgs> sensiArgs,
54 std::unique_ptr<FullRevalArgs> revalArgs,
55 std::unique_ptr<MultiThreadArgs> mtArgs,
56 const ext::shared_ptr<HistoricalScenarioGenerator>& hisScenGen,
58 const bool requireTradePnl)
59 :
MarketRiskReport(calculationCurrency, portfolio, portfolioFilter, btArgs->backtestPeriod_, hisScenGen, std::move(sensiArgs), std::move(revalArgs),
60 std::move(mtArgs), breakdown, requireTradePnl),
76 std::vector<TimePeriod> tps{
btArgs_->benchmarkPeriod_,
btArgs_->backtestPeriod_};
81 auto rpts = ext::dynamic_pointer_cast<BacktestReports>(reports);
82 bool trdDetail =
false;
85 trdDetail = detailTrade !=
nullptr;
92 QuantLib::ext::make_shared<PNLCalculator>(
btArgs_->benchmarkPeriod_));
93 auto btRpts = ext::dynamic_pointer_cast<BacktestReports>(reports);
95 QuantLib::ext::make_shared<BacktestPNLCalculator>(
btArgs_->backtestPeriod_,
writePnl_,
this, btRpts));
100 const ext::shared_ptr<MarketRiskGroupBase>& riskGroup,
101 const ext::shared_ptr<TradeGroupBase>& tradeGroup) {
102 QL_REQUIRE(
pnlCalculators_.size() == 2,
"Expecting 2 PNL Calculators for Backtest");
108 auto backtestPnlCalc = ext::dynamic_pointer_cast < BacktestPNLCalculator>(
pnlCalculators_[1]);
109 QL_REQUIRE(backtestPnlCalc,
"We must have a BacktestPnLCalculator");
121 const ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup,
122 const ext::shared_ptr<ore::analytics::TradeGroupBase>& tradeGroup) {
124 QL_REQUIRE(
histPnlGen_,
"Must have a Historical PNL Generator");
138 const ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup,
139 const ext::shared_ptr<ore::analytics::TradeGroupBase>& tradeGroup) {
143 Data data = {cpty, tradeGroup, riskGroup};
145 auto backtestRpts = ext::dynamic_pointer_cast<BacktestReports>(reports);
146 QL_REQUIRE(backtestRpts,
"We must have backtest reports");
175 for (
const auto& key :
hisScenGen_->baseScenario()->keys()) {
185 const ext::shared_ptr<BacktestReports>& reports,
const Data& data,
bool isFull,
const vector<Real>& pnls,
194 QL_REQUIRE(pnlScenDates.size() == pnls.size(),
"Backtest::calculateSummary(): internal error, pnlScenDates ("
195 << pnlScenDates.size() <<
") do not match pnls (" << pnls.size()
201 QL_REQUIRE(pnls.size() == tradePnls.size(),
"For trade level backtest detail report,"
202 <<
" expect the number of aggregate P&Ls (" << pnls.size()
203 <<
") to equal the number"
204 <<
" of trade P&Ls (" << tradePnls.size() <<
").");
208 vector<Size> callTradesToSkip;
209 vector<Size> postTradesToSkip;
211 for (Size t = 0; t < tradeIds.size(); t++) {
212 const string& tid = tradeIds[t];
214 callTradesToSkip.push_back(t);
216 postTradesToSkip.push_back(t);
222 vector<Real> scenTradePnls;
225 for (Size i = 0; i < pnls.size(); i++) {
226 const auto& start = pnlScenDates[i].first;
227 const auto& end = pnlScenDates[i].second;
230 callScenPnl = pnls[i];
231 if (!callTradesToSkip.empty()) {
232 scenTradePnls = tradePnls[i];
233 for (
const Size& t : callTradesToSkip) {
234 callScenPnl -= scenTradePnls[t];
240 cPassFail = callScenPnl > std::max(sr.
callValue,
btArgs_->exceptionThreshold_) ?
"fail" :
"pass";
244 postScenPnl = pnls[i];
245 if (!postTradesToSkip.empty()) {
246 scenTradePnls = tradePnls[i];
247 for (
const Size& t : postTradesToSkip) {
248 postScenPnl -= scenTradePnls[t];
253 pPassFail = -postScenPnl > std::max(sr.
postValue,
btArgs_->exceptionThreshold_) ?
"fail" :
"pass";
258 if (detailTrd && !
data.tradeGroup->allLevel()) {
259 const auto& scenTradePnls = tradePnls[i];
260 QL_REQUIRE(tradeIds.size() == scenTradePnls.size(),
"For trade level backtest detail report,"
261 <<
" the number of trades (" << tradeIds.size()
262 <<
") does not equal the size of the trade level P&L"
263 <<
" container (" << scenTradePnls.size()
264 <<
") on scenario date " << io::iso_date(start)
266 for (Size j = 0; j < scenTradePnls.size(); ++j) {
267 if (std::find(callTradesToSkip.begin(), callTradesToSkip.end(), j) == callTradesToSkip.end())
269 if (std::find(postTradesToSkip.begin(), postTradesToSkip.end(), j) == postTradesToSkip.end())
292 auto rpts = ext::dynamic_pointer_cast<BacktestReports>(reports);
293 QL_REQUIRE(rpts,
"Reports must be of type BacktestReports");
299 summary->addColumn(std::get<0>(t), std::get<1>(t), std::get<2>(t));
307 detail->addColumn(std::get<0>(t), std::get<1>(t), std::get<2>(t));
314 detailTrade->addColumn(
"TradeId",
string());
316 if (
btArgs_->tradeDetailIncludeAllColumns_ || std::get<3>(t))
317 detailTrade->addColumn(std::get<0>(t), std::get<1>(t), std::get<2>(t));
326 pnl->addColumn(std::get<0>(t), std::get<1>(t), std::get<2>(t));
333 pnlTrade->addColumn(
"TradeId",
string());
335 pnlTrade->addColumn(std::get<0>(t), std::get<1>(t), std::get<2>(t));
341 VarBenchmarks& benchmarks, Real confidence,
const bool isCall,
342 const QuantLib::ext::shared_ptr<MarketRiskGroupBase>& riskGroup,
343 std::set<std::pair<std::string, QuantLib::Size>>&
345 for (
auto& [type,
value] : benchmarks) {
347 value.second =
value.first->var(confidence, isCall, tradeIdIdxPairs);
373 bool isCall,
const RiskFactorKey& key_1, Real shift_1, Real delta, Real gamma, Real deltaPnl, Real gammaPnl,
374 const RiskFactorKey& key_2, Real shift_2,
const string& tradeId,
const string& currency, Real fxSpot) {
378 QuantLib::ext::shared_ptr<ore::data::Report> rpt;
379 if (tradeId.empty()) {
389 (std::abs(deltaPnl) <
sensiArgs_->pnlWriteThreshold_ && std::abs(gammaPnl) <
sensiArgs_->pnlWriteThreshold_))
393 auto& report = tradeId.empty() ? rpt->next() : rpt->next().add(tradeId);
398 .add(isCall ?
"call" :
"post")
411 Real delta, Real gamma, Real deltaPnl, Real gammaPnl,
412 const RiskFactorKey& key_2, Real shift_2,
const string& tradeId) {
414 backtest_->
addPnlRow(
reports_, scenarioIdx, isCall, key_1, shift_1, delta, gamma, deltaPnl, gammaPnl, key_2, shift_2,
QuantLib::ext::shared_ptr< MarketRiskBacktest::BacktestReports > reports_
MarketRiskBacktest * backtest_
void writePNL(QuantLib::Size scenarioIdx, bool isCall, const RiskFactorKey &key_1, QuantLib::Real shift_1, QuantLib::Real delta, QuantLib::Real gamma, QuantLib::Real deltaPnl, QuantLib::Real gammaPnl, const RiskFactorKey &key_2=RiskFactorKey(), QuantLib::Real shift_2=0.0, const std::string &tradeId="") override
std::vector< ReportType > types_
const QuantLib::ext::shared_ptr< ore::data::Report > & get(ReportType type)
ReportType
Report types that can be populated during a SIMM backtest.
ore::analytics::TradePnLStore tradePnls_
std::set< std::string > postTradeIds_
std::vector< QuantLib::Real > pnls_
bool disablesAll(const QuantLib::ext::shared_ptr< ore::analytics::ScenarioFilter > &filter) const override
virtual void addSummaryRow(const QuantLib::ext::shared_ptr< BacktestReports > &reports, const Data &data, bool isCall, QuantLib::Real im, QuantLib::Size observations, bool isFull, QuantLib::Size exceptions, const std::vector< QuantLib::Size > &ragBounds, const VarBenchmarks &sensiBenchmarks, const VarBenchmarks &fullBenchmarks) const =0
Add a row to the summary report.
ore::analytics::TradePnLStore sensiTradePnls_
VarBenchmarks fullRevalCallBenchmarks_
virtual const std::vector< std::tuple< std::string, ore::data::Report::ReportType, QuantLib::Size, bool > > detailColumns()=0
virtual bool runTradeDetail(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports) override
std::vector< ore::data::TimePeriod > timePeriods() override
virtual void calculateBenchmarks(VarBenchmarks &benchmarks, QuantLib::Real confidence, const bool isCall, const QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > &riskGroup, std::set< std::pair< std::string, QuantLib::Size > > &tradeIdIdxPairs)
Calculate and update the benchmarks.
std::vector< QuantLib::Real > sensiPnls_
virtual void reset(const QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > &riskGroup) override
void writeReports(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports, const QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > &riskGroup, const QuantLib::ext::shared_ptr< ore::analytics::TradeGroupBase > &tradeGroup) override
ore::analytics::TradePnLStore foTradePnls_
SummaryResults calculateSummary(const QuantLib::ext::shared_ptr< BacktestReports > &reports, const Data &data, bool isFull, const std::vector< QuantLib::Real > &pnls, const std::vector< std::string > &tradeIds, const TradePnLStore &tradePnls)
void createReports(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports) override
virtual QuantLib::Real postValue(const Data &data)=0
std::vector< QuantLib::Real > bmPnls_
std::map< VarType, std::pair< QuantLib::ext::shared_ptr< ore::analytics::VarCalculator >, QuantLib::Real > > VarBenchmarks
pointers to the VAR benchmarks
std::vector< QuantLib::Real > foSensiPnls_
virtual QuantLib::Real callValue(const Data &data)=0
void addPnlCalculators(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports) override
VarBenchmarks fullRevalPostBenchmarks_
virtual std::string counterparty(const std::string &tradeId) const =0
std::set< std::string > callTradeIds_
virtual void addDetailRow(const QuantLib::ext::shared_ptr< BacktestReports > &reports, const Data &data, bool isCall, QuantLib::Real im, const QuantLib::Date &start, const QuantLib::Date &end, bool isFull, QuantLib::Real pnl, const std::string &result, const std::string &tradeId="") const =0
Add a row to the detail report.
virtual const std::vector< std::tuple< std::string, ore::data::Report::ReportType, QuantLib::Size > > pnlColumns()=0
virtual void adjustFullRevalPnls(std::vector< QuantLib::Real > &pnls, std::vector< QuantLib::Real > &bmPnls, ore::analytics::TradePnLStore &tradePnls, const std::vector< QuantLib::Real > &foSensiPnls, const std::vector< QuantLib::Real > &bmFoSensiPnls, const ore::analytics::TradePnLStore &foTradePnls, const QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > &riskGroup)
VarBenchmarks sensiPostBenchmarks_
std::vector< QuantLib::Real > bmFoSensiPnls_
void handleSensiResults(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports, const QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > &riskGroup, const QuantLib::ext::shared_ptr< ore::analytics::TradeGroupBase > &tradeGroup) override
void initialise() override
virtual void addPnlRow(const QuantLib::ext::shared_ptr< BacktestReports > &reports, QuantLib::Size scenarioIdx, bool isCall, const ore::analytics::RiskFactorKey &key_1, QuantLib::Real shift_1, QuantLib::Real delta, QuantLib::Real gamma, QuantLib::Real deltaPnl, QuantLib::Real gammaPnl, const ore::analytics::RiskFactorKey &key_2=ore::analytics::RiskFactorKey(), QuantLib::Real shift_2=0.0, const std::string &tradeId="", const std::string ¤cy="", QuantLib::Real fxSpot=1.0)
Add a row to the P&L contribution report.
std::vector< QuantLib::Real > bmSensiPnls_
variables for benchmark calculations
void handleFullRevalResults(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports, const QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > &riskGroup, const QuantLib::ext::shared_ptr< ore::analytics::TradeGroupBase > &tradeGroup) override
std::unique_ptr< BacktestArgs > btArgs_
MarketRiskBacktest(const std::string &calculationCurrency, const QuantLib::ext::shared_ptr< ore::data::Portfolio > &portfolio, const std::string &portfolioFilter, std::unique_ptr< BacktestArgs > btArgs, std::unique_ptr< SensiRunArgs > sensiArgs=nullptr, std::unique_ptr< FullRevalArgs > revalArgs=nullptr, std::unique_ptr< MultiThreadArgs > mtArgs=nullptr, const QuantLib::ext::shared_ptr< ore::analytics::HistoricalScenarioGenerator > &hisScenGen=nullptr, const bool breakdown=false, const bool requireTradePnl=false)
virtual const std::vector< std::tuple< std::string, ore::data::Report::ReportType, QuantLib::Size > > summaryColumns()=0
VarBenchmarks sensiCallBenchmarks_
std::vector< QuantLib::ext::shared_ptr< ore::data::Report > > reports_
virtual void initialise()
std::string calculationCurrency_
std::vector< QuantLib::ext::shared_ptr< PNLCalculator > > pnlCalculators_
QuantLib::ext::shared_ptr< HistoricalScenarioGenerator > hisScenGen_
std::vector< std::string > tradeIds_
virtual bool runFullReval(const QuantLib::ext::shared_ptr< MarketRiskGroupBase > &riskGroup) const
std::set< std::pair< std::string, QuantLib::Size > > tradeIdIdxPairs_
virtual void reset(const QuantLib::ext::shared_ptr< MarketRiskGroupBase > &riskGroup)
std::unique_ptr< SensiRunArgs > sensiArgs_
QuantLib::ext::shared_ptr< ore::analytics::HistoricalPnlGenerator > histPnlGen_
std::vector< std::vector< QuantLib::Real > > TradePnLStore
Data types stored in the scenario class.
SafeStack< ValueType > value
SafeStack< Filter > filter
A Class to write a cube out to file.
scenario generator that builds from historical shifts
Class for generating sensi pnl.
A cube implementation that stores the cube in memory.
bace class for all market risk backtests
std::string to_string(const LocationInfo &l)
Class for aggregating SensitivityRecords.
Used to pass information.
Used to store results for writing rows in the summary report.
QuantLib::Size observations
std::vector< QuantLib::Size > bounds
QuantLib::Size postExceptions
QuantLib::Size callExceptions