Skip to content

Commit 46a4590

Browse files
pcaspersjenkins
authored andcommitted
Merge branch 'QPR-12893' into 'master'
Resolve QPR-12893 Return Configuration for SIMM Backtest Closes QPR-12893 See merge request qs/oreplus!2736
1 parent 8d6b2ea commit 46a4590

15 files changed

Lines changed: 688 additions & 251 deletions
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
%--------------------------------------------------------
2+
\subsection{Historical Return Configuration} \label{sec:historicalreturnconfiguration}
3+
%--------------------------------------------------------
4+
5+
The \lstinline|ReturnConfiguration| allows the user to specify, for each risk factor type, how historical returns are computed in historical scenario generation and backtesting. This configuration controls the return type (e.g., log, absolute, relative) and an optional displacement for each risk factor. Additionally, it is possible to override the default return configuration for specific names (e.g., for a particular equity or commodity).
6+
7+
The root element is \lstinline|ReturnConfiguration|, which contains one or more
8+
\lstinline|<Return>| blocks. Each \lstinline|Return| must have a
9+
\lstinline|key| attribute, either the risk factor key type for the default configuration (e.g., \texttt{DiscountCurve}, \texttt{FXSpot}, \texttt{EquitySpot}, etc.). or the risk factor key type plus the underlying name for a specific override (e.g \texttt{EquitySpot/EQUITY1}.
10+
11+
\begin{listing}
12+
\begin{minted}[fontsize=\footnotesize]{xml}
13+
<ReturnConfiguration>
14+
<Return key="DiscountCurve">
15+
<Type>Log</Type>
16+
<Displacement>0.0</Displacement>
17+
</Return>
18+
<Return key="EquitySpot">
19+
<Type>Relative</Type>
20+
<Displacement>0.0</Displacement>
21+
</Return>
22+
<Return key="EquitySpot/EQUITY_1">
23+
<Type>Absolute</Type>
24+
<Displacement>0.0</Displacement>
25+
</Return>
26+
<!-- ... more configurations ... -->
27+
</ReturnConfiguration>
28+
\end{minted}
29+
\caption{Historical return configuration}
30+
\label{lst:historical_return_configuration}
31+
\end{listing}
32+
33+
\subsubsection*{Elements and Attributes}
34+
35+
\begin{itemize}
36+
\item \lstinline|Return key="..."|: Specifies the configuration for a risk factor type. The \lstinline|key| attribute must match a valid risk factor key type or the specific key type and name.
37+
\begin{itemize}
38+
\item \lstinline|Type|: The return type. Allowed values are \texttt{Log}, \texttt{Absolute}, and \texttt{Relative}.
39+
\item \lstinline|Displacement|: The displacement value (floating point). Used to avoid division by zero or negative values in relative/log returns.
40+
\end{itemize}
41+
\end{itemize}
42+
43+
\subsubsection*{Notes}
44+
45+
\begin{itemize}
46+
\item If no override is specified for a particular name, the default return configuration for the risk factor type is used.
47+
\item The displacement should be set to a small positive value if the risk factor can approach zero, to avoid numerical issues.
48+
\end{itemize}

Docs/UserGuide/userguide.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ \section*{Document History}
6767
\include{parameterisation/conventions}
6868
%referenced from conventions
6969
\include{tradecomponents/scheduledata}
70+
\include{parameterisation/historicalreturnconfiguration}
7071
\include{parameterisation/collateralbalances}
7172
\include{parameterisation/counterpartyinformation}
7273

OREAnalytics/orea/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ scenario/cvascenarioloader.cpp
130130
scenario/deltascenario.cpp
131131
scenario/deltascenariofactory.cpp
132132
scenario/historicalscenariogenerator.cpp
133+
scenario/historicalscenarioreturn.cpp
133134
scenario/lgmscenariogenerator.cpp
134135
scenario/scenario.cpp
135136
scenario/scenariofilereader.cpp
@@ -344,6 +345,7 @@ scenario/cvascenarioloader.hpp
344345
scenario/deltascenario.hpp
345346
scenario/deltascenariofactory.hpp
346347
scenario/historicalscenariogenerator.hpp
348+
scenario/historicalscenarioreturn.hpp
347349
scenario/lgmscenariogenerator.hpp
348350
scenario/scenario.hpp
349351
scenario/scenariofactory.hpp

OREAnalytics/orea/app/analytics/pnlexplainanalytic.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ void PnlExplainAnalyticImpl::runAnalytic(const QuantLib::ext::shared_ptr<ore::da
118118

119119
QuantLib::ext::shared_ptr<HistoricalScenarioLoader> scenarioLoader =
120120
QuantLib::ext::make_shared<HistoricalScenarioLoader>(histScens, pnlDates);
121-
121+
122122
auto zeroScenarios = QuantLib::ext::make_shared<HistoricalScenarioGenerator>(
123-
scenarioLoader, QuantLib::ext::make_shared<SimpleScenarioFactory>(), adjFactors,
124-
ReturnConfiguration(), "hs_");
123+
scenarioLoader, QuantLib::ext::make_shared<SimpleScenarioFactory>(),
124+
QuantLib::ext::make_shared<ReturnConfiguration>(), adjFactors, "hs_");
125125

126126
zeroScenarios->baseScenario() = t0Scenario;
127127

@@ -155,9 +155,10 @@ void PnlExplainAnalyticImpl::runAnalytic(const QuantLib::ext::shared_ptr<ore::da
155155
} else
156156
scenarios = zeroScenarios;
157157
} else {
158-
auto scenarios = buildHistoricalScenarioGenerator(inputs_->scenarioReader(), adjFactors, pnlDates,
159-
analytic()->configurations().simMarketParams,
160-
analytic()->configurations().todaysMarketParams);
158+
auto defaultReturnConfig = QuantLib::ext::make_shared<ReturnConfiguration>();
159+
auto scenarios = buildHistoricalScenarioGenerator(
160+
inputs_->scenarioReader(), adjFactors, pnlDates, analytic()->configurations().simMarketParams,
161+
analytic()->configurations().todaysMarketParams, defaultReturnConfig);
161162
scenarios->baseScenario() = t0Scenario;
162163
}
163164

OREAnalytics/orea/app/analytics/varanalytic.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,12 @@ void ParametricVarAnalyticImpl::setVarReport(const QuantLib::ext::shared_ptr<ore
111111
if (auto adjLoader = QuantLib::ext::dynamic_pointer_cast<AdjustedInMemoryLoader>(loader))
112112
adjFactors = QuantLib::ext::make_shared<ore::data::AdjustmentFactors>(adjLoader->adjustmentFactors());
113113

114-
auto scenarios = buildHistoricalScenarioGenerator(inputs_->scenarioReader(), adjFactors,
115-
benchmarkVarPeriod, inputs_->mporCalendar(), inputs_->mporDays(), analytic()->configurations().simMarketParams,
116-
analytic()->configurations().todaysMarketParams, inputs_->mporOverlappingPeriods());
114+
auto defaultReturnConfig = QuantLib::ext::make_shared<ReturnConfiguration>();
115+
116+
auto scenarios = buildHistoricalScenarioGenerator(
117+
inputs_->scenarioReader(), adjFactors, benchmarkVarPeriod, inputs_->mporCalendar(), inputs_->mporDays(),
118+
analytic()->configurations().simMarketParams, analytic()->configurations().todaysMarketParams,
119+
defaultReturnConfig, inputs_->mporOverlappingPeriods());
117120

118121
if (inputs_->outputHistoricalScenarios())
119122
ReportWriter().writeHistoricalScenarios(
@@ -155,12 +158,14 @@ void HistoricalSimulationVarAnalyticImpl::setVarReport(
155158
QuantLib::ext::shared_ptr<ore::data::AdjustmentFactors> adjFactors;
156159
if (auto adjLoader = QuantLib::ext::dynamic_pointer_cast<AdjustedInMemoryLoader>(loader))
157160
adjFactors = QuantLib::ext::make_shared<ore::data::AdjustmentFactors>(adjLoader->adjustmentFactors());
158-
159-
auto scenarios =
160-
buildHistoricalScenarioGenerator(inputs_->scenarioReader(), adjFactors, benchmarkVarPeriod, inputs_->mporCalendar(),
161-
inputs_->mporDays(), analytic()->configurations().simMarketParams,
162-
analytic()->configurations().todaysMarketParams, inputs_->mporOverlappingPeriods());
163-
161+
162+
auto defaultReturnConfig = QuantLib::ext::make_shared<ReturnConfiguration>();
163+
164+
auto scenarios = buildHistoricalScenarioGenerator(
165+
inputs_->scenarioReader(), adjFactors, benchmarkVarPeriod, inputs_->mporCalendar(), inputs_->mporDays(),
166+
analytic()->configurations().simMarketParams, analytic()->configurations().todaysMarketParams,
167+
defaultReturnConfig, inputs_->mporOverlappingPeriods());
168+
164169
if (inputs_->outputHistoricalScenarios())
165170
ore::analytics::ReportWriter().writeHistoricalScenarios(
166171
scenarios->scenarioLoader(),

OREAnalytics/orea/app/reportwriter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,7 @@ void ReportWriter::writeHistoricalScenarioDetails(
17831783
.addColumn("ScenarioValue1", double(), 8)
17841784
.addColumn("ScenarioValue2", double(), 8)
17851785
.addColumn("ShiftType", string())
1786+
.addColumn("Displacement", double(), 8)
17861787
.addColumn("Return", double(), 8)
17871788
.addColumn("ScenarioValue", double(), 8);
17881789

@@ -1800,6 +1801,7 @@ void ReportWriter::writeHistoricalScenarioDetails(
18001801
.add(d.scenarioValue1)
18011802
.add(d.scenarioValue2)
18021803
.add(ore::data::to_string(d.returnType))
1804+
.add(d.displacement)
18031805
.add(d.returnValue)
18041806
.add(d.scenarioValue);
18051807
}

OREAnalytics/orea/orea.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
#include <orea/scenario/deltascenario.hpp>
147147
#include <orea/scenario/deltascenariofactory.hpp>
148148
#include <orea/scenario/historicalscenariogenerator.hpp>
149+
#include <orea/scenario/historicalscenarioreturn.hpp>
149150
#include <orea/scenario/lgmscenariogenerator.hpp>
150151
#include <orea/scenario/scenario.hpp>
151152
#include <orea/scenario/scenariofactory.hpp>

0 commit comments

Comments
 (0)