Skip to content

Commit bf28a9c

Browse files
committed
Merge remote-tracking branch 'origin/master' into feature/QPR-13646
2 parents 8b32e85 + eec46db commit bf28a9c

18 files changed

Lines changed: 368 additions & 143 deletions

Docs/UserGuide/pricing/pricingengines.tex

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,10 @@ \subsection{Product Type: IndexCreditDefaultSwap}
18231823
\item Curve: Index, Underlying
18241824
\item SensitivityDecomposition: Underlying, NotionalWeighted, LossWeighted, DeltaWeighted
18251825
\item SensitivityTemplate [optional]: the sensitivity template to use
1826+
\item CalibrateUnderlyingCurves [optional]: Only applies when Curve is set to Underlying.
1827+
If true, it apply a spread to the the individual constituent curves to match the index CDS spread.
1828+
This ensures that pricing the index CDS using underlying curves produces the same NPV as pricing with the index curve directly. Defaults to false.
1829+
(See Calibration of default curves for index tranches for details.)
18261830
\end{itemize}
18271831

18281832
\begin{longlisting}
@@ -1835,6 +1839,7 @@ \subsection{Product Type: IndexCreditDefaultSwap}
18351839
<Parameter name="Curve">Index</Parameter>
18361840
<Parameter name="SensitivityDecomposition">DeltaWeighted</Parameter>
18371841
<Parameter name="SensitivityTemplate">IR_Analytical</Parameter>
1842+
<Parameter name="CalibrateUnderlyingCurves">false</Parameter>
18381843
</EngineParameters>
18391844
</Product>
18401845
\end{minted}
@@ -1867,6 +1872,10 @@ \subsection{Product Type: IndexCreditDefaultSwapOption}
18671872
\item FepCurve: Index, Underlying
18681873
\item SensitivityDecomposition: Underlying, NotionalWeighted, LossWeighted, DeltaWeighted
18691874
\item SensitivityTemplate [optional]: the sensitivity template to use
1875+
\item CalibrateUnderlyingCurves [optional]: Only applies when Curve or FepCurve is set to Underlying.
1876+
If true, it apply a spread to the the individual constituent curves to match the index CDS spread.
1877+
This ensures that pricing the index CDS using underlying curves produces the same NPV as pricing with the index curve directly. Defaults to false.
1878+
(See Calibration of default curves for index tranches for details.)
18701879
\end{itemize}
18711880

18721881
\begin{longlisting}
@@ -1898,6 +1907,10 @@ \subsection{Product Type: IndexCreditDefaultSwapOption}
18981907
\item FepCurve: Index, Underlying
18991908
\item SensitivityDecomposition: Underlying, NotionalWeighted, LossWeighted, DeltaWeighted
19001909
\item SensitivityTemplate [optional]: the sensitivity template to use
1910+
\item CalibrateUnderlyingCurves [optional]: Only applies when Curve or FepCurve is set to Underlying.
1911+
If true, it apply a spread to the the individual constituent curves to match the index CDS spread.
1912+
This ensures that pricing the index CDS using underlying curves produces the same NPV as pricing with the index curve directly. Defaults to false.
1913+
(See Calibration of default curves for index tranches for details.)
19011914
\end{itemize}
19021915

19031916
\begin{longlisting}

Docs/UserGuide/tradedata/extendedfxforwardswap.tex

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ \subsubsection{Extended Fx Forward Swap}
22

33
Extended Fx Forward Swap are represented as scripted trades, refer to appendix A for an introduction. Listing \ref{lst:extendedfxforwardswap} shows the structure of an example.
44

5+
An Extended Fx Forward Swap is like an FxAccumulator with regular and conditional observation and settlement dates. After the regular observation dates a European barrier is applied on the Extension Decision Date. If the barrier is hit the trade terminates, otherwise the trade continues with cashflows generated on the conditional observation dates.
6+
57
\begin{listing}[H]
68
\begin{minted}[fontsize=\footnotesize]{xml}
79
<Trade id="ExtendedForward">
@@ -63,6 +65,13 @@ \subsubsection{Extended Fx Forward Swap}
6365
<Date>2020-03-31</Date>
6466
<Date>2020-04-30</Date>
6567
<Date>2020-05-29</Date>
68+
\end{minted}
69+
\caption{Extended Fx Forward Swap Representation}
70+
\label{lst:extendedfxforwardswap}
71+
\end{listing}
72+
73+
\begin{listing}[H]
74+
\begin{minted}[fontsize=\footnotesize]{xml}
6675
<Date>2020-06-30</Date>
6776
<Date>2020-07-31</Date>
6877
<Date>2020-08-31</Date>
@@ -115,8 +124,8 @@ \subsubsection{Extended Fx Forward Swap}
115124
</ScriptedTradeData>
116125
</Trade>
117126
\end{minted}
118-
\caption{Extended Fx Forward Swap Representation}
119-
\label{lst:extendedfxforwardswap}
127+
\caption{Extended Fx Forward Swap Representation, continued}
128+
\label{lst:extendedfxforwardswap2}
120129
\end{listing}
121130
122131
The meanings and allowable values of the elements in the \verb+Extended Fx Forward Swap+ representation follow below.

Docs/UserGuide/tradedata/totalReturnSwap.tex

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@ \subsubsection{Generic Total Return Swap / Contract for Difference (CFD)}
5555
\item CBO: See \ref{ss:CBOData}, the trade data is given in a CBOData sub node.
5656
\item CommodityPosition: See \ref{ss:commodity_position}, the trade data is given in a CommodityPositionData sub node.
5757
\item ConvertibleBond: See \ref{ss:convertible_bond}, the trade data is given in a ConvertibleBondData sub
58-
node. When using reference data, a TRS on a convertible bond can also be captured as a TRS on a bond, i.e. there is
59-
no need to distinguish between a TRS on a Bond and a TRS on a convertible Bond in this case, the pricer will figure
58+
node. When using reference data, a TRS on a Convertible Bond can also be captured as a TRS on a Bond, i.e. there is
59+
no need to distinguish between a TRS on a Bond and a TRS on a Convertible Bond in this case, the pricer will figure
6060
out which underlying to set up based on the type of reference data that is set up for the ISIN referenced in the
6161
security id field.
62+
\item CallableBond: See \ref{ss:callable_bond}, the trade data is given in a CallableBond sub node. When using reference data,
63+
a TRS on a Callable Bond can also be captured as a TRS on a bond, i.e. there is no need to distinguish between a TRS on a Bond and a TRS on a Callable Bond.
64+
The pricer will figure out which underlying to set up based on the type of reference data that is set up for the ISIN referenced in the security id field.
6265
\item EquityPosition: See \ref{ss:equity_position}, the trade data is given in a EquityPositionData sub
6366
node. Notice that the equities given in the basket must be available as quoted market data. To represent a TRS on an Equity Futures position, one or multiple EquityPosition underlyings are used, where the equity positions cover the underlying equity of the futures position.
6467

@@ -324,6 +327,32 @@ \subsubsection{Generic Total Return Swap / Contract for Difference (CFD)}
324327
\label{lst:trsdata}
325328
\end{listing}
326329

330+
331+
\begin{listing}[H]
332+
%\hrule\medskip
333+
\begin{minted}[fontsize=\footnotesize]{xml}
334+
<TotalReturnSwapData>
335+
<UnderlyingData>
336+
<Trade>
337+
<TradeType>CallableBond</TradeType>
338+
<CallableBondData>
339+
<BondData>
340+
<SecurityId>ISIN:XS0123456789</SecurityId>
341+
<BondNotional>100000000</BondNotional>
342+
</BondData>
343+
</CallableBondData>
344+
</Trade>
345+
</UnderlyingData>
346+
<!-- omitting ReturnData, FundingData, AdditionalCashflowData -->
347+
</TotalReturnSwapData>
348+
</Trade>
349+
\end{minted}
350+
\caption{Generic Total Return Swap with Callable Bond underlying}
351+
\label{lst:trsdata15}
352+
\end{listing}
353+
354+
355+
327356
\begin{listing}[H]
328357
%\hrule\medskip
329358
\begin{minted}[fontsize=\footnotesize]{xml}

Docs/UserGuide/tradedata/var_and_vol_derivatives.tex

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
\subsubsection{Exotic Variance and Volatility Derivatives}
1+
\subsubsection*{Exotic Variance and Volatility Derivatives}
22
\label{SubSectionExoticVarianceSwap}
33

44
These are vanilla variance/volatility swaps and options on an underlying with some additional payoff features,
@@ -54,7 +54,7 @@ \subsubsection{Exotic Variance and Volatility Derivatives}
5454

5555
Trade input and the associated payoff script are described in the following for 12 supported variations.
5656

57-
\subsubsection*{Variance Option}
57+
\subsubsection{Variance Option}
5858

5959
The traditional trade representation is as follows, using an EQ underlying in this example:
6060

@@ -191,7 +191,7 @@ \subsubsection*{Variance Option}
191191
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
192192
\end{itemize}
193193

194-
\subsubsection*{Variance Swap with KI/KO Barrier}
194+
\subsubsection{Variance Swap with KI/KO Barrier}
195195

196196
The traditional trade representation is as follows, using an FX underlying in this example:
197197

@@ -360,7 +360,7 @@ \subsubsection*{Variance Swap with KI/KO Barrier}
360360
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
361361
\end{itemize}
362362

363-
\subsubsection*{Dual European Binary Option with Volatility and Spot KO Barrier}
363+
\subsubsection{Dual European Binary Option with Volatility and Spot KO Barrier}
364364

365365
The traditional trade representation is as follows, using an EQ underlying in this example:
366366

@@ -474,7 +474,7 @@ \subsubsection*{Dual European Binary Option with Volatility and Spot KO Barrier}
474474
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
475475
\end{itemize}
476476

477-
\subsubsection*{Corridor Variance Swap}
477+
\subsubsection{Corridor Variance Swap}
478478

479479
The traditional trade representation is as follows, using an FX underlying in this example:
480480

@@ -649,7 +649,7 @@ \subsubsection*{Corridor Variance Swap}
649649
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
650650
\end{itemize}
651651

652-
\subsubsection*{Indexed Corridor Variance Swap}
652+
\subsubsection{Indexed Corridor Variance Swap}
653653

654654
The traditional trade representation is as follows, using EQ underlyings in this example:
655655

@@ -820,7 +820,7 @@ \subsubsection*{Indexed Corridor Variance Swap}
820820
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
821821
\end{itemize}
822822

823-
\subsubsection*{Corridor Variance Swap with KI/KO Barrier}
823+
\subsubsection{Corridor Variance Swap with KI/KO Barrier}
824824

825825
The traditional trade representation is as follows, using an EQ underlying in this example:
826826

@@ -1008,7 +1008,7 @@ \subsubsection*{Corridor Variance Swap with KI/KO Barrier}
10081008
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
10091009
\end{itemize}
10101010

1011-
\subsubsection*{Conditional Variance Swap 01}
1011+
\subsubsection{Conditional Variance Swap 01}
10121012

10131013
The traditional trade representation is as follows, using an FX underlying in this example:
10141014

@@ -1187,7 +1187,7 @@ \subsubsection*{Conditional Variance Swap 01}
11871187
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
11881188
\end{itemize}
11891189

1190-
\subsubsection*{Conditional Variance Swap 02}
1190+
\subsubsection{Conditional Variance Swap 02}
11911191

11921192
The traditional trade representation is as follows, using an FX underlying in this example:
11931193

@@ -1372,7 +1372,7 @@ \subsubsection*{Conditional Variance Swap 02}
13721372
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
13731373
\end{itemize}
13741374

1375-
\subsubsection*{Pairwise Variance Swap}
1375+
\subsubsection{Pairwise Variance Swap}
13761376

13771377
The \lstinline!FxPairwiseVarianceSwap! and \lstinline!EquityPairwiseVarianceSwap! trade types
13781378
have trade data containers (respectively):
@@ -1664,7 +1664,7 @@ \subsubsection*{Pairwise Variance Swap}
16641664
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
16651665
\end{itemize}
16661666

1667-
\subsubsection*{Variance Dispersion Swap}
1667+
\subsubsection{Variance Dispersion Swap}
16681668

16691669
The traditional trade representation is as follows, using EQ underlyings in this example:
16701670

@@ -1875,7 +1875,7 @@ \subsubsection*{Variance Dispersion Swap}
18751875
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
18761876
\end{itemize}
18771877

1878-
\subsubsection*{Corridor Variance Dispersion Swap}
1878+
\subsubsection{Corridor Variance Dispersion Swap}
18791879

18801880
This instrument is a variance dispersion swap with a corridor feature, where variance is accrued only when the
18811881
the price of the first underlying of each pair of underlyings (between the first and second basket) falls within
@@ -2106,7 +2106,7 @@ \subsubsection*{Corridor Variance Dispersion Swap}
21062106
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
21072107
\end{itemize}
21082108

2109-
\subsubsection*{KO Corridor Variance Dispersion Swap}
2109+
\subsubsection{KO Corridor Variance Dispersion Swap}
21102110

21112111
This instrument is a variance dispersion swap with a double-barrier knock-out and a corridor feature.
21122112

@@ -2387,7 +2387,7 @@ \subsubsection*{KO Corridor Variance Dispersion Swap}
23872387
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
23882388
\end{itemize}
23892389

2390-
\subsubsection*{Pairwise Geometric Variance Dispersion Swap}
2390+
\subsubsection{Pairwise Geometric Variance Dispersion Swap}
23912391

23922392
The traditional trade representation is as follows, using EQ underlyings in this example:
23932393

@@ -2569,7 +2569,7 @@ \subsubsection*{Pairwise Geometric Variance Dispersion Swap}
25692569
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
25702570
\end{itemize}
25712571

2572-
\subsubsection*{Gamma Swap}
2572+
\subsubsection{Gamma Swap}
25732573

25742574
The traditional trade representation is as follows, using EQ underlyings in this example:
25752575

@@ -2668,7 +2668,7 @@ \subsubsection*{Gamma Swap}
26682668
Allowable values: See Table \ref{tab:currency} for allowable currency codes.
26692669
\end{itemize}
26702670

2671-
\subsubsection*{Basket Variance Swap}
2671+
\subsubsection{Basket Variance Swap}
26722672

26732673
The \lstinline!FxBasketVarianceSwap! and \lstinline!EquityBasketVarianceSwap! \lstinline!CommodityBasketVarianceSwap! trade types
26742674
have trade data containers (respectively):

OREAnalytics/orea/engine/marketriskreport.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <ored/marketdata/todaysmarket.hpp>
2020
#include <ored/portfolio/trade.hpp>
2121
#include <ored/utilities/to_string.hpp>
22+
#include <orea/app/structuredanalyticserror.hpp>
2223
#include <orea/cube/cubewriter.hpp>
2324
#include <orea/cube/inmemorycube.hpp>
2425
#include <orea/cube/npvcube.hpp>
@@ -316,6 +317,14 @@ void MarketRiskReport::calculate(const ext::shared_ptr<MarketRiskReport::Reports
316317

317318
writePnl_ = tradeGroup->allLevel() && riskGroup->allLevel();
318319
tradeIdIdxPairs_ = tradeIdGroups_.at(tradeGroupKey(tradeGroup));
320+
if (tradeIdIdxPairs_.size() == 0) {
321+
StructuredAnalyticsErrorMessage(
322+
"Market Risk Backtest", "No trades for tradeGroup",
323+
"No trades to process for RiskGroup: " + riskGroup->to_string() + ", TradeGroup: "
324+
+ tradeGroup->to_string())
325+
.log();
326+
continue;
327+
}
319328

320329
// populate the tradeIds
321330
transform(tradeIdIdxPairs_.begin(), tradeIdIdxPairs_.end(), back_inserter(tradeIds_),

OREData/ored/marketdata/basecorrelationcurve.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -509,8 +509,7 @@ void BaseCorrelationCurve::buildFromUpfronts(const Date& asof, const BaseCorrela
509509
dpts.push_back(creditCurve->curve());
510510
}
511511

512-
Handle<DefaultProbabilityTermStructure> indexCurve;
513-
Handle<Quote> indexRecovery;
512+
514513
Handle<YieldTermStructure> discountCurve;
515514
// check if curveID has term suffix already (e.g. "RED:ABCDEFGH_5Y"), if so use that, otherwise use term from config
516515
auto p = ore::data::splitCurveIdWithTenor(config.curveID());
@@ -525,12 +524,9 @@ void BaseCorrelationCurve::buildFromUpfronts(const Date& asof, const BaseCorrela
525524
QL_REQUIRE(indexCreditCurve != nullptr,
526525
"Can not imply base correlation, index credit curve " << indexNameWithTerm << " missing");
527526
discountCurve = indexCreditCurve->rateCurve();
528-
indexCurve = indexCreditCurve->curve();
529-
indexRecovery = indexCreditCurve->recovery();
530-
527+
531528
if (config.calibrateConstituentsToIndexSpread()) {
532-
auto curveCalibration = ext::make_shared<QuantExt::CreditIndexConstituentCurveCalibration>(
533-
config.startDate(), term, config.indexSpread(), indexRecovery, indexCurve, discountCurve);
529+
auto curveCalibration = ext::make_shared<QuantExt::CreditIndexConstituentCurveCalibration>(indexCreditCurve);
534530

535531
auto calibrationResults = curveCalibration->calibratedCurves(
536532
basketData.remainingNames, basketData.remainingWeights, dpts, recoveryRates);

OREData/ored/marketdata/defaultcurve.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,11 +336,12 @@ void DefaultCurve::buildCdsCurve(const std::string& curveID, const DefaultCurveC
336336
refData.tenor = Period(cdsConv->frequency());
337337
refData.calendar = cdsConv->calendar();
338338
refData.convention = cdsConv->paymentConvention();
339-
refData.termConvention = cdsConv->paymentConvention();
339+
refData.termConvention = Unadjusted;
340340
refData.rule = cdsConv->rule();
341341
refData.payConvention = cdsConv->paymentConvention();
342342
refData.dayCounter = cdsConv->dayCounter();
343-
refData.lastPeriodDayCounter = cdsConv->lastPeriodDayCounter();
343+
if (cdsConv->lastPeriodDayCounter() != DayCounter())
344+
refData.lastPeriodDayCounter = cdsConv->lastPeriodDayCounter();
344345
refData.cashSettlementDays = cdsConv->upfrontSettlementDays();
345346

346347
// If the configuration instructs us to imply a default from the market data, we do it here.

OREData/ored/portfolio/bondtotalreturnswap.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@ void BondTRS::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactor
8383

8484
QuantLib::ext::shared_ptr<BondIndex> bondIndex;
8585

86-
auto bondType = getBondReferenceDatumType(bondData_.securityId(), engineFactoryOverride->referenceData());
87-
8886
BondIndexBuilder bondIndexBuilder;
8987

9088
Real bondNotional = bondData_.bondNotional();
9189

9290
try {
9391

92+
auto bondType = getBondReferenceDatumType(bondData_.securityId(), engineFactoryOverride->referenceData());
93+
9494
if (bondType.empty() || bondType == BondReferenceDatum::TYPE) {
9595

9696
// vanilla bond underlying
@@ -123,6 +123,7 @@ void BondTRS::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactor
123123
// try to fill some fields for trade matching purposes although the trade build itself failed already
124124
npvCurrency_ = fundingLegData_.currency();
125125
notionalCurrency_ = bondData_.currency();
126+
notional_ = 1.0;
126127
for (auto const& d : bondData_.coupons()) {
127128
try {
128129
auto s = makeSchedule(d.schedule());

0 commit comments

Comments
 (0)