Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
marketriskbacktest.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2023 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19/*! \file orea/engine/marketriskbacktest.hpp
20 \brief bace class for all market risk backtests
21 \ingroup engine
22*/
23
24#pragma once
25
36#include <boost/make_shared.hpp>
37
38namespace ore {
39namespace analytics {
40
42public:
43 //! VAR types used as a benchmark against which SIMM can be compared
45
47 public:
48 //! Report types that can be populated during a SIMM backtest
50
52 void add(const QuantLib::ext::shared_ptr<ore::data::Report>& report) {
53 QL_FAIL("Please use alternative add method, providing a ReportType");
54 }
55 void add(ReportType type, const QuantLib::ext::shared_ptr<ore::data::Report>& report) {
56 types_.push_back(type);
57 reports_.push_back(report);
58 }
59 const bool has(ReportType type) const {
60 auto it = std::find(types_.begin(), types_.end(), type);
61 return it != types_.end();
62 }
63 const QuantLib::ext::shared_ptr<ore::data::Report>& get(ReportType type);
64
65 protected:
66 std::vector<ReportType> types_;
67 };
68
69 struct BacktestArgs {
70 //! Time period over which to perform the backtest
72 //! Time period over which to calculate the benchmark VAR
74 //! Confidence level in the SIMM backtest
75 QuantLib::Real confidence_;
76 //! Amount by which absolute P&L value must exceed 0 for exception counting
77 QuantLib::Real exceptionThreshold_;
79
80 //! Call side trade IDs to be considered in the backtest. Other trades' PnLs will be removed from the total PnL
81 std::set<std::string> callTradeIds_ = {};
82 //! Post side trade IDs to be considered in the backtest. Other trades' PnLs will be removed from the total PnL
83 std::set<std::string> postTradeIds_ = {};
84
85 //! Confidence levels that feed in to defining the stop light bounds
86 std::vector<QuantLib::Real> ragLevels_ = {0.95, 0.9999};
89 QuantLib::Real conf = 0.99, QuantLib::Real exThres = 0.01,
90 bool tdc = false, const std::set<std::string>& callTradeIds = {},
91 const std::set<std::string>& postTradeIds = {})
92 : backtestPeriod_(btPeriod), benchmarkPeriod_(bmPeriod),
93 confidence_(conf), exceptionThreshold_(exThres),
94 tradeDetailIncludeAllColumns_(tdc), callTradeIds_(callTradeIds), postTradeIds_(postTradeIds) {}
95 };
96
97 //! Used to pass information
98 struct Data {
99 std::string counterparty;
100 QuantLib::ext::shared_ptr<ore::analytics::TradeGroupBase> tradeGroup;
101 QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase> riskGroup;
102 };
103
104 //! Used to store results for writing rows in the summary report
106 QuantLib::Size observations;
107 QuantLib::Real callValue;
108 QuantLib::Size callExceptions;
109 QuantLib::Real postValue;
110 QuantLib::Size postExceptions;
111 std::vector<QuantLib::Size> bounds;
112 };
113
116 QuantLib::ext::shared_ptr<ore::analytics::VarCalculator> calculator;
117 QuantLib::Real var = 0.0;
118
119 VarBenchmark(VarType type, QuantLib::ext::shared_ptr<ore::analytics::VarCalculator> calculator,
120 QuantLib::Real var = 0.0)
122
123 void reset() { var = 0.0; }
124 };
125
126 MarketRiskBacktest(const std::string& calculationCurrency,
127 const QuantLib::ext::shared_ptr<ore::data::Portfolio>& portfolio,
128 const std::string& portfolioFilter,
129 std::unique_ptr<BacktestArgs> btArgs,
130 std::unique_ptr<SensiRunArgs> sensiArgs = nullptr,
131 std::unique_ptr<FullRevalArgs> revalArgs = nullptr,
132 std::unique_ptr<MultiThreadArgs> mtArgs = nullptr,
133 const QuantLib::ext::shared_ptr<ore::analytics::HistoricalScenarioGenerator>& hisScenGen = nullptr,
134 const bool breakdown = false,
135 const bool requireTradePnl = false);
136
138
139 /*! Check if the given scenario \p filter turns off all risk factors in the
140 historical scenario generator
141 */
142 bool disablesAll(const QuantLib::ext::shared_ptr<ore::analytics::ScenarioFilter>& filter) const override;
143
144 //! Add a row to the P&L contribution report
145 virtual void addPnlRow(const QuantLib::ext::shared_ptr<BacktestReports>& reports, QuantLib::Size scenarioIdx,
146 bool isCall, const ore::analytics::RiskFactorKey& key_1, QuantLib::Real shift_1,
147 QuantLib::Real delta, QuantLib::Real gamma, QuantLib::Real deltaPnl, QuantLib::Real gammaPnl,
149 QuantLib::Real shift_2 = 0.0, const std::string& tradeId = "",
150 const std::string& currency = "", QuantLib::Real fxSpot = 1.0);
151
152protected:
153 std::unique_ptr<BacktestArgs> btArgs_;
154
155 void initialise() override;
156
157 //! pointers to the VAR benchmarks
158 typedef std::map<VarType, std::pair<QuantLib::ext::shared_ptr<ore::analytics::VarCalculator>, QuantLib::Real>>
161
162 //! variables for benchmark calculations
165 std::set<std::string> callTradeIds_;
166 std::set<std::string> postTradeIds_;
167
168 virtual const std::vector<std::tuple<std::string, ore::data::Report::ReportType, QuantLib::Size>> summaryColumns() = 0;
169 virtual const std::vector<std::tuple<std::string, ore::data::Report::ReportType, QuantLib::Size, bool>> detailColumns() = 0;
170 virtual const std::vector<std::tuple<std::string, ore::data::Report::ReportType, QuantLib::Size>> pnlColumns() = 0;
171 virtual QuantLib::Real callValue(const Data& data) = 0;
172 virtual QuantLib::Real postValue(const Data& data) = 0;
173 virtual std::string counterparty(const std::string& tradeId) const = 0;
174 virtual void setUpBenchmarks() = 0;
175 virtual void reset(const QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup) override;
176
177 void createReports(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports) override;
178 virtual bool runTradeDetail(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports) override;
179 ore::data::TimePeriod covariancePeriod() const override { return btArgs_->benchmarkPeriod_; }
180 void addPnlCalculators(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports) override;
181
182 void handleSensiResults(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports,
183 const QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup,
184 const QuantLib::ext::shared_ptr<ore::analytics::TradeGroupBase>& tradeGroup) override;
185
186 void handleFullRevalResults(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports,
187 const QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup,
188 const QuantLib::ext::shared_ptr<ore::analytics::TradeGroupBase>& tradeGroup) override;
189
190 virtual void adjustFullRevalPnls(std::vector<QuantLib::Real>& pnls, std::vector<QuantLib::Real>& bmPnls,
192 const std::vector<QuantLib::Real>& foSensiPnls,
193 const std::vector<QuantLib::Real>& bmFoSensiPnls,
194 const ore::analytics::TradePnLStore& foTradePnls,
195 const QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup){};
196
197 //! Add a row to the detail report
198 virtual void addDetailRow(const QuantLib::ext::shared_ptr<BacktestReports>& reports, const Data& data, bool isCall,
199 QuantLib::Real im, const QuantLib::Date& start, const QuantLib::Date& end, bool isFull, QuantLib::Real pnl,
200 const std::string& result, const std::string& tradeId = "") const = 0;
201
202 //! Add a row to the summary report
203 virtual void addSummaryRow(const QuantLib::ext::shared_ptr<BacktestReports>& reports, const Data& data, bool isCall,
204 QuantLib::Real im, QuantLib::Size observations,
205 bool isFull, QuantLib::Size exceptions, const std::vector<QuantLib::Size>& ragBounds,
206 const VarBenchmarks& sensiBenchmarks, const VarBenchmarks& fullBenchmarks) const = 0;
207
208 //! Calculate and update the benchmarks
209 virtual void calculateBenchmarks(VarBenchmarks& benchmarks, QuantLib::Real confidence, const bool isCall,
210 const QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup,
211 std::set<std::pair<std::string, QuantLib::Size>>& tradeIdIdxPairs);
212
213 void writeReports(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports,
214 const QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup,
215 const QuantLib::ext::shared_ptr<ore::analytics::TradeGroupBase>& tradeGroup) override;
216
217 std::vector<ore::data::TimePeriod> timePeriods() override;
218
219 private:
220 /*! Calculate the number of exceptions given the current \p data and the associated
221 P&L vector \p pnls for both call and post sides. The parameter
222 \p isFull is <code>true</code> if pnls come from a full revaluation and <code>false</code>
223 if they are sensitivity based.
224
225 The parameters \p tradeIds and \p tradePnls are used if we are writing a trade level backtest
226 detail report.
227 */
228 SummaryResults calculateSummary(const QuantLib::ext::shared_ptr<BacktestReports>& reports, const Data& data,
229 bool isFull,
230 const std::vector<QuantLib::Real>& pnls, const std::vector<std::string>& tradeIds, const TradePnLStore& tradePnls);
231};
232
234public:
235 BacktestPNLCalculator(ore::data::TimePeriod pnlPeriod, const bool& writePnl, MarketRiskBacktest* backtest,
236 const QuantLib::ext::shared_ptr<MarketRiskBacktest::BacktestReports>& reports)
237 : PNLCalculator(pnlPeriod), writePnl_(writePnl), backtest_(backtest), reports_(reports) {}
238
239 void writePNL(QuantLib::Size scenarioIdx, bool isCall, const RiskFactorKey& key_1,
240 QuantLib::Real shift_1, QuantLib::Real delta, QuantLib::Real gamma, QuantLib::Real deltaPnl,
241 QuantLib::Real gammaPnl, const RiskFactorKey& key_2 = RiskFactorKey(),
242 QuantLib::Real shift_2 = 0.0, const std::string& tradeId = "") override;
243
244 const TradePnLStore& tradePnls() { return tradePnls_; }
246
247private:
248 const bool& writePnl_ = false;
250 QuantLib::ext::shared_ptr<MarketRiskBacktest::BacktestReports> reports_;
251};
252
253} // namespace analytics
254} // namespace ore
BacktestPNLCalculator(ore::data::TimePeriod pnlPeriod, const bool &writePnl, MarketRiskBacktest *backtest, const QuantLib::ext::shared_ptr< MarketRiskBacktest::BacktestReports > &reports)
QuantLib::ext::shared_ptr< MarketRiskBacktest::BacktestReports > reports_
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
void add(ReportType type, const QuantLib::ext::shared_ptr< ore::data::Report > &report)
void add(const QuantLib::ext::shared_ptr< ore::data::Report > &report)
ReportType
Report types that can be populated during a SIMM backtest.
ore::analytics::TradePnLStore tradePnls_
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.
VarType
VAR types used as a benchmark against which SIMM can be compared.
ore::analytics::TradePnLStore sensiTradePnls_
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_
ore::data::TimePeriod covariancePeriod() const override
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
virtual std::string counterparty(const std::string &tradeId) const =0
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)
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
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 &currency="", 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_
virtual const std::vector< std::tuple< std::string, ore::data::Report::ReportType, QuantLib::Size > > summaryColumns()=0
std::vector< QuantLib::ext::shared_ptr< ore::data::Report > > reports_
std::vector< std::vector< QuantLib::Real > > TradePnLStore
Data types stored in the scenario class.
Definition: scenario.hpp:48
Class for generating portfolio P&Ls based on historical scenarios.
Class for generating sensi pnl.
Base class for a market risk report.
std::vector< std::vector< QuantLib::Real > > TradePnLStore
Scenario Filter classes.
Class for calculating the shift multiple between two scenarios for a given key.
Base class for sensitivity record streamer.
std::set< std::string > postTradeIds_
Post side trade IDs to be considered in the backtest. Other trades' PnLs will be removed from the tot...
ore::data::TimePeriod backtestPeriod_
Time period over which to perform the backtest.
QuantLib::Real confidence_
Confidence level in the SIMM backtest.
BacktestArgs(ore::data::TimePeriod btPeriod, ore::data::TimePeriod bmPeriod, QuantLib::Real conf=0.99, QuantLib::Real exThres=0.01, bool tdc=false, const std::set< std::string > &callTradeIds={}, const std::set< std::string > &postTradeIds={})
std::vector< QuantLib::Real > ragLevels_
Confidence levels that feed in to defining the stop light bounds.
ore::data::TimePeriod benchmarkPeriod_
Time period over which to calculate the benchmark VAR.
std::set< std::string > callTradeIds_
Call side trade IDs to be considered in the backtest. Other trades' PnLs will be removed from the tot...
QuantLib::Real exceptionThreshold_
Amount by which absolute P&L value must exceed 0 for exception counting.
QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > riskGroup
QuantLib::ext::shared_ptr< ore::analytics::TradeGroupBase > tradeGroup
Used to store results for writing rows in the summary report.
VarBenchmark(VarType type, QuantLib::ext::shared_ptr< ore::analytics::VarCalculator > calculator, QuantLib::Real var=0.0)
QuantLib::ext::shared_ptr< ore::analytics::VarCalculator > calculator
Base class for a var calculation.