Skip to content

Commit 342dd94

Browse files
committed
Merge remote-tracking branch 'origin/master' into gh_206_210_master
2 parents 8aa160d + be41ba6 commit 342dd94

38 files changed

Lines changed: 1423 additions & 996 deletions

Docs/UserGuide/tradedata/swaption.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ \subsubsection{Swaption}
66
component sub-node. These trade components are outlined in section \ref{ss:option_data} and section
77
\ref{ss:leg_data}.\\
88
\vspace{5mm}
9-
Supported swaption exercise styles are \emph{European} and \emph{Bermudan}. Swaptions of both exercise styles can have an arbitrary number of legs, with
9+
Supported swaption exercise styles are \emph{European}, \emph{Bermudan}, \emph{American}. Swaptions of all exercise styles can have an arbitrary number of legs, with
1010
each leg represented by a \lstinline!LegData! sub-node. Cross currency swaptions are not supported for either exercise style, i.e. the Currency element must
1111
have the same value for all \lstinline!LegData! sub-nodes of a swaption. There must be at least one full coupon period after the exercise date for European
1212
Swaptions, and after the last exercise date for Bermudan Swaptions. See Table \ref{tab:swaption_requirements} for further details on requirements for

Examples/Example_15/ExpectedOutput/npv.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#TradeId,TradeType,Maturity,MaturityTime,NPV,NpvCurrency,NPV(Base),BaseCurrency,Notional,NotionalCurrency,Notional(Base),NettingSet,CounterParty
2-
BERMUDAN_SWAPTION,Swaption,2038-10-01,22.652317,-3115851.065563,EUR,-3115851.065563,EUR,10000000.00,EUR,10000000.00,CPTY_A,CPTY_A
2+
BERMUDAN_SWAPTION,Swaption,2038-10-01,22.652317,-3115844.394193,EUR,-3115844.394193,EUR,10000000.00,EUR,10000000.00,CPTY_A,CPTY_A
33
BOND,Bond,2021-02-03,4.994783,12902649.282760,EUR,12902649.282760,EUR,10000000.00,EUR,10000000.00,CPTY_A,CPTY_A
44
Bond_Floating,Bond,2021-02-03,4.994783,10765048.489931,EUR,10765048.489931,EUR,10000000.00,EUR,10000000.00,,CPTY_C
55
CAP_EUR,CapFloor,2026-02-09,10.011221,-6881.951398,EUR,-6881.951398,EUR,1000000.00,EUR,1000000.00,CPTY_A,CPTY_A

Examples/Example_15/ExpectedOutput/scenario.csv

Lines changed: 382 additions & 382 deletions
Large diffs are not rendered by default.

Examples/Example_15/ExpectedOutput/sensitivity.csv

Lines changed: 80 additions & 80 deletions
Large diffs are not rendered by default.

Examples/Example_15/ExpectedOutput/stresstest.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#TradeId,ScenarioLabel,Base NPV,Scenario NPV,Sensitivity
2-
BERMUDAN_SWAPTION,parallel_rates,-3100941.24,-2043549.12,1057392.12
3-
BERMUDAN_SWAPTION,twist,-3100941.24,-3165028.92,-64087.68
2+
BERMUDAN_SWAPTION,parallel_rates,-3100934.56,-2043542.97,1057391.59
3+
BERMUDAN_SWAPTION,twist,-3100934.56,-3165020.59,-64086.03
44
BOND,parallel_rates,12902111.76,12614454.85,-287656.90
55
BOND,twist,12902111.76,12801562.04,-100549.71
66
Bond_Floating,parallel_rates,10765631.07,10511973.88,-253657.19

Examples/Example_15/ExpectedOutput/var.csv

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
#Portfolio,RiskClass,RiskType,Quantile_0.010000,Quantile_0.050000,Quantile_0.950000,Quantile_0.990000
2-
(all),(all),(all),-51235590.702637,-36273022.490219,35954247.490219,50916815.702637
2+
(all),(all),(all),-51235588.420345,-36273020.290624,35954249.290624,50916817.420345
33
PF1,(all),(all),-50726701.680738,-35873450.367032,35826125.367032,50679376.680738
4-
PF2,(all),(all),-6496762.740931,-4633322.329692,4361872.329692,6225312.740931
5-
(all),(all),DeltaGamma,-51228597.857258,-36266113.235621,35960753.235621,50923237.857258
4+
PF2,(all),(all),-6496758.482691,-4633318.732994,4361872.732994,6225312.482691
5+
(all),(all),DeltaGamma,-51228597.579535,-36266113.039256,35960753.039256,50923237.579535
66
PF1,(all),DeltaGamma,-50726701.680738,-35873450.367032,35826125.367032,50679376.680738
7-
PF2,(all),DeltaGamma,-6487763.642587,-4624994.545862,4366959.545862,6229728.642587
8-
(all),(all),Vega,-177437.215274,-127422.632151,114007.632151,164022.215274
9-
PF2,(all),Vega,-177437.215274,-127422.632151,114007.632151,164022.215274
10-
(all),InterestRate,(all),-36990503.836512,-26202194.865752,25875101.865752,36663410.836512
7+
PF2,(all),DeltaGamma,-6487761.420238,-4624992.974542,4366957.974542,6229726.420238
8+
(all),(all),Vega,-177433.848212,-127419.665564,114008.665564,164022.848212
9+
PF2,(all),Vega,-177433.848212,-127419.665564,114008.665564,164022.848212
10+
(all),InterestRate,(all),-36990501.444995,-26202192.588929,25875103.588929,36663412.444995
1111
PF1,InterestRate,(all),-36286970.228997,-25662864.686621,25621789.686621,36245895.228997
12-
PF2,InterestRate,(all),-6495322.849454,-4634438.067121,4348420.067121,6209304.849454
13-
(all),InterestRate,DeltaGamma,-36983211.482402,-26195003.828212,25881803.828212,36670011.482402
12+
PF2,InterestRate,(all),-6495318.588113,-4634434.468231,4348420.468231,6209304.588113
13+
(all),InterestRate,DeltaGamma,-36983211.097219,-26195003.555867,25881803.555867,36670011.097219
1414
PF1,InterestRate,DeltaGamma,-36286970.228997,-25662864.686621,25621789.686621,36245895.228997
15-
PF2,InterestRate,DeltaGamma,-6486370.984829,-4626073.665994,4353948.665994,6214245.984829
16-
(all),InterestRate,Vega,-166550.351677,-119795.045528,105902.045528,152657.351677
17-
PF2,InterestRate,Vega,-166550.351677,-119795.045528,105902.045528,152657.351677
15+
PF2,InterestRate,DeltaGamma,-6486368.759528,-4626072.092586,4353947.092586,6214243.759528
16+
(all),InterestRate,Vega,-166546.889318,-119792.011561,105903.011561,152657.889318
17+
PF2,InterestRate,Vega,-166546.889318,-119792.011561,105903.011561,152657.889318
1818
(all),Inflation,(all),-304149.096627,-215013.224331,215263.224331,304399.096627
1919
PF1,Inflation,(all),-304149.096627,-215013.224331,215263.224331,304399.096627
2020
(all),Inflation,DeltaGamma,-304149.096627,-215013.224331,215263.224331,304399.096627

Examples/Input/pricingengine.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,29 @@
6464
<Parameter name="nx">10</Parameter>
6565
</EngineParameters>
6666
</Product>
67+
<Product type="AmericanSwaption">
68+
<Model>LGM</Model>
69+
<ModelParameters>
70+
<Parameter name="Calibration">Bootstrap</Parameter>
71+
<Parameter name="CalibrationStrategy">CoterminalATM</Parameter>
72+
<Parameter name="Reversion">0.03</Parameter>
73+
<Parameter name="ReversionType">HullWhite</Parameter>
74+
<Parameter name="Volatility">0.01</Parameter>
75+
<Parameter name="VolatilityType">Hagan</Parameter>
76+
<!-- shift horizon as ratio of maturity time -->
77+
<Parameter name="ShiftHorizon">0.5</Parameter>
78+
<Parameter name="Tolerance">0.0001</Parameter>
79+
<Parameter name="ReferenceCalibrationGrid">400,3M</Parameter>
80+
<Parameter name="ExerciseTimeStepsPerYear">24</Parameter>
81+
</ModelParameters>
82+
<Engine>FD</Engine>
83+
<EngineParameters>
84+
<Parameter name="Scheme">Douglas</Parameter>
85+
<Parameter name="StateGridPoints">64</Parameter>
86+
<Parameter name="TimeStepsPerYear">24</Parameter>
87+
<Parameter name="MesherEpsilon">1E-4</Parameter>
88+
</EngineParameters>
89+
</Product>
6790
<Product type="CapFloor">
6891
<Model>IborCapModel</Model>
6992
<ModelParameters/>

OREAnalytics/orea/engine/amcvaluationengine.cpp

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@
2727
#include <ored/model/crossassetmodelbuilder.hpp>
2828
#include <ored/portfolio/enginefactory.hpp>
2929
#include <ored/portfolio/structuredtradeerror.hpp>
30+
#include <ored/utilities/to_string.hpp>
3031

3132
#include <qle/indexes/fallbackiborindex.hpp>
3233
#include <qle/instruments/payment.hpp>
3334
#include <qle/methods/multipathgeneratorbase.hpp>
3435
#include <qle/methods/multipathvariategenerator.hpp>
35-
#include <qle/pricingengines/mcmultilegbaseengine.hpp>
3636
#include <qle/models/lgmimpliedyieldtermstructure.hpp>
37+
#include <qle/pricingengines/mcmultilegbaseengine.hpp>
3738

3839
#include <ql/instruments/compositeinstrument.hpp>
3940

@@ -222,7 +223,6 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
222223
McEngineStats::instance().calc_timer.start();
223224
McEngineStats::instance().calc_timer.stop();
224225

225-
226226
auto extractAmcCalculator = [&amcCalculators, &tradeId, &tradeLabel, &tradeType, &effectiveMultiplier,
227227
&currencyIndex, &tradeFees, &model,
228228
&outputCube](const std::pair<std::string, boost::shared_ptr<Trade>>& trade,
@@ -235,7 +235,7 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
235235
tradeId.push_back(id->second);
236236
} else {
237237
QL_FAIL("AMCValuationEngine: trade id '" << trade.first
238-
<< "' is not present in output cube - internal error.");
238+
<< "' is not present in output cube - internal error.");
239239
}
240240
tradeLabel.push_back(trade.first);
241241
tradeType.push_back(trade.second->tradeType());
@@ -261,8 +261,7 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
261261
auto inst = trade.second->instrument()->qlInstrument(true);
262262
QL_REQUIRE(inst != nullptr,
263263
"instrument has no ql instrument, this is not supported by the amc valuation engine.");
264-
Real multiplier = trade.second->instrument()->multiplier() *
265-
trade.second->instrument()->multiplier2();
264+
Real multiplier = trade.second->instrument()->multiplier() * trade.second->instrument()->multiplier2();
266265

267266
// handle composite trades
268267
if (auto cInst = boost::dynamic_pointer_cast<CompositeInstrument>(inst)) {
@@ -428,7 +427,8 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
428427
auto res = simulatePathInterface2(amcCalculators[j], pathTimes, paths, allTimes, false, tradeLabel[j],
429428
tradeType[j]);
430429
Real v = outputCube->getT0(tradeId[j], 0);
431-
outputCube->setT0(v + res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
430+
outputCube->setT0(v +
431+
res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
432432
numRatio(model, irStateBuffer, currencyIndex[j], 0, 0.0, 0) *
433433
effectiveMultiplier[j] +
434434
resFee[0][0],
@@ -437,7 +437,8 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
437437
Real t = sgd->getGrid()->timeGrid()[k];
438438
for (Size i = 0; i < outputCube->samples(); ++i) {
439439
Real v = outputCube->get(tradeId[j], k - 1, i, 0);
440-
outputCube->set(v + res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
440+
outputCube->set(v +
441+
res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
441442
numRatio(model, irStateBuffer, currencyIndex[j], k, t, i) *
442443
effectiveMultiplier[j] +
443444
resFee[k][i],
@@ -454,31 +455,44 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
454455
auto resLag = simulatePathInterface2(amcCalculators[j], pathTimes, paths, closeOutTimes, true,
455456
tradeLabel[j], tradeType[j]);
456457
Real v = outputCube->getT0(tradeId[j], 0);
457-
outputCube->setT0(v + res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
458+
outputCube->setT0(v +
459+
res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
458460
numRatio(model, irStateBuffer, currencyIndex[j], 0, 0.0, 0) *
459461
effectiveMultiplier[j] +
460462
resFee[0][0],
461463
tradeId[j], 0);
462464
int dateIndex = -1;
465+
std::map<QuantLib::Date, std::pair<double, size_t>> dateIndexCache;
463466
for (Size k = 0; k < sgd->getGrid()->dates().size(); ++k) {
464467
Real t = sgd->getGrid()->timeGrid()[k + 1];
465-
Real tm = sgd->getGrid()->timeGrid()[k];
468+
466469
if (sgd->getGrid()->isCloseOutDate()[k]) {
467-
QL_REQUIRE(dateIndex >= 0, "first date in grid must be a valuation date");
470+
Date closeOutDate = sgd->getGrid()->dates()[k];
471+
Date valuationDate = sgd->getGrid()->valuationDateFromCloseOutDate(closeOutDate);
472+
auto dateIndexIt = dateIndexCache.find(valuationDate);
473+
QL_REQUIRE(dateIndexIt != dateIndexCache.end(),
474+
"The valuation date (" << ore::data::to_string(valuationDate)
475+
<< ") needs to before the corresponding close out date ("
476+
<< ore::data::to_string(closeOutDate) << ")");
477+
auto [timeValueDate, timeIndexValueDate] = dateIndexIt->second;
468478
for (Size i = 0; i < outputCube->samples(); ++i) {
469479
Real v = outputCube->get(tradeId[j], dateIndex, i, 1);
470-
outputCube->set(v + resLag[dateIndex + 1][i] * fx(fxBuffer, currencyIndex[j], k + 1, i) *
471-
num(model, irStateBuffer, currencyIndex[j], k + 1, tm, i) *
472-
effectiveMultiplier[j] +
473-
resFee[dateIndex + 1][i],
474-
tradeId[j], dateIndex, i, 1);
480+
outputCube->set(
481+
v +
482+
resLag[dateIndex + 1][i] * fx(fxBuffer, currencyIndex[j], k + 1, i) *
483+
num(model, irStateBuffer, currencyIndex[j], k + 1, timeValueDate, i) *
484+
effectiveMultiplier[j] +
485+
resFee[dateIndex + 1][i],
486+
tradeId[j], timeIndexValueDate, i, 1);
475487
}
476488
}
477489
if (sgd->getGrid()->isValuationDate()[k]) {
478-
++dateIndex;
490+
Date valuationDate = sgd->getGrid()->dates()[k];
491+
dateIndexCache[valuationDate] = std::make_pair(t, ++dateIndex);
479492
for (Size i = 0; i < outputCube->samples(); ++i) {
480-
Real v = outputCube->get(tradeId[j], dateIndex, i, 1);
481-
outputCube->set(v + res[dateIndex + 1][i] * fx(fxBuffer, currencyIndex[j], k + 1, i) *
493+
Real v = outputCube->get(tradeId[j], dateIndex, i, 0);
494+
outputCube->set(v +
495+
res[dateIndex + 1][i] * fx(fxBuffer, currencyIndex[j], k + 1, i) *
482496
numRatio(model, irStateBuffer, currencyIndex[j], k + 1, t, i) *
483497
effectiveMultiplier[j] +
484498
resFee[dateIndex + 1][i],
@@ -492,28 +506,39 @@ void runCoreEngine(const boost::shared_ptr<ore::data::Portfolio>& portfolio,
492506
tradeType[j]);
493507
Real v = outputCube->getT0(tradeId[j], 0);
494508
outputCube->setT0(v + res[0].at(0) * fx(fxBuffer, currencyIndex[j], 0, 0) *
495-
numRatio(model, irStateBuffer, currencyIndex[j], 0, 0.0, 0) *
496-
effectiveMultiplier[j],
509+
numRatio(model, irStateBuffer, currencyIndex[j], 0, 0.0, 0) *
510+
effectiveMultiplier[j],
497511
tradeId[j], 0);
512+
std::map<QuantLib::Date, std::pair<double, size_t>> dateIndexCache;
498513
int dateIndex = -1;
499514
for (Size k = 1; k < res.size(); ++k) {
500515
Real t = sgd->getGrid()->timeGrid()[k];
501516
if (sgd->getGrid()->isCloseOutDate()[k - 1]) {
502-
QL_REQUIRE(dateIndex >= 0, "first date in grid must be a valuation date");
517+
Date closeOutDate = sgd->getGrid()->dates()[k - 1];
518+
Date valuationDate = sgd->getGrid()->valuationDateFromCloseOutDate(closeOutDate);
519+
auto dateIndexIt = dateIndexCache.find(valuationDate);
520+
QL_REQUIRE(dateIndexIt != dateIndexCache.end(),
521+
"The valuation date (" << ore::data::to_string(valuationDate)
522+
<< ") needs to before the corresponding close out date ("
523+
<< ore::data::to_string(closeOutDate) << ")");
524+
auto [_, timeIndexValueDate] = dateIndexIt->second;
503525
for (Size i = 0; i < outputCube->samples(); ++i) {
504526
Real v = outputCube->get(tradeId[j], dateIndex, i, 1);
505-
outputCube->set(v + res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
527+
outputCube->set(v +
528+
res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
506529
num(model, irStateBuffer, currencyIndex[j], k, t, i) *
507530
effectiveMultiplier[j] +
508531
resFee[k][i],
509-
tradeId[j], dateIndex, i, 1);
532+
tradeId[j], timeIndexValueDate, i, 1);
510533
}
511534
}
512535
if (sgd->getGrid()->isValuationDate()[k - 1]) {
513-
++dateIndex;
536+
Date valuationDate = sgd->getGrid()->dates()[k - 1];
537+
dateIndexCache[valuationDate] = std::make_pair(t, ++dateIndex);
514538
for (Size i = 0; i < outputCube->samples(); ++i) {
515539
Real v = outputCube->get(tradeId[j], dateIndex, i, 0);
516-
outputCube->set(v + res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
540+
outputCube->set(v +
541+
res[k][i] * fx(fxBuffer, currencyIndex[j], k, i) *
517542
numRatio(model, irStateBuffer, currencyIndex[j], k, t, i) *
518543
effectiveMultiplier[j] +
519544
resFee[k][i],

0 commit comments

Comments
 (0)