Skip to content

Commit 23c48c9

Browse files
farahkhashmanGitlab CI
authored andcommitted
Merge branch 'feature/QPR-13744b' into 'master'
Resolve QPR-13744 unit test fixes Closes QPR-13744 See merge request qs/oreplus!3125
1 parent d7e5a97 commit 23c48c9

17 files changed

Lines changed: 255 additions & 61 deletions

OREAnalytics/test/testmarket.cpp

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ parRateCurve(const Date& asof, const vector<QuantLib::ext::shared_ptr<QuantExt::
210210
TestMarket::TestMarket(Date asof, bool swapVolCube) : MarketImpl(false) {
211211

212212
TestConfigurationObjects::setConventions();
213-
213+
214214
asof_ = asof;
215215

216216
// build discount
@@ -356,7 +356,7 @@ TestMarket::TestMarket(Date asof, bool swapVolCube) : MarketImpl(false) {
356356
recoveryRates_[make_pair(Market::defaultConfiguration, "dc2")] =
357357
Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.4));
358358
recoveryRates_[make_pair(Market::defaultConfiguration, "BondIssuer0")] =
359-
Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0));
359+
Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.0));
360360
recoveryRates_[make_pair(Market::defaultConfiguration, "BondIssuer1")] =
361361
Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.4));
362362

@@ -384,15 +384,15 @@ TestMarket::TestMarket(Date asof, bool swapVolCube) : MarketImpl(false) {
384384

385385
cdsVols_[make_pair(Market::defaultConfiguration, "dc")] =
386386
Handle<QuantExt::CreditVolCurve>(QuantLib::ext::make_shared<QuantExt::CreditVolCurveWrapper>(flatRateFxv(0.12)));
387-
387+
388388
Handle<IborIndex> hGBP(ore::data::parseIborIndex(
389389
"GBP-LIBOR-6M", yieldCurves_[make_tuple(Market::defaultConfiguration, YieldCurveType::Discount, "GBP")]));
390390
// FIXME: We have defined that above already
391391
iborIndices_[make_pair(Market::defaultConfiguration, "GBP-LIBOR-6M")] = hGBP;
392392

393393
// Some test cases need a different definition of UKRPI index, curve and vol structure
394394
// We there fore added the new UKROi as UKRP1 and keep the "original" below.
395-
395+
396396
// build inflation indices
397397
auto zeroIndex = Handle<ZeroInflationIndex>(QuantLib::ext::make_shared<UKRPI>(flatZeroInflationCurve(0.02, 0.01)));
398398
zeroInflationIndices_[make_pair(Market::defaultConfiguration, "UKRP1")] = zeroIndex;
@@ -436,23 +436,12 @@ TestMarket::TestMarket(Date asof, bool swapVolCube) : MarketImpl(false) {
436436
euii->addFixing(fixingDatesEUHICPXT[i], fixingRatesEUHICPXT[i], true);
437437
};
438438

439-
vector<Date> datesZCII = {asof_,
440-
asof_ + 1 * Years,
441-
asof_ + 2 * Years,
442-
asof_ + 3 * Years,
443-
asof_ + 4 * Years,
444-
asof_ + 5 * Years,
445-
asof_ + 6 * Years,
446-
asof_ + 7 * Years,
447-
asof_ + 8 * Years,
448-
asof_ + 9 * Years,
449-
asof_ + 10 * Years,
450-
asof_ + 12 * Years,
451-
asof_ + 15 * Years,
439+
vector<Date> datesZCII = {asof_ + 1 * Years, asof_ + 2 * Years, asof_ + 3 * Years, asof_ + 4 * Years,
440+
asof_ + 5 * Years, asof_ + 6 * Years, asof_ + 7 * Years, asof_ + 8 * Years,
441+
asof_ + 9 * Years, asof_ + 10 * Years, asof_ + 12 * Years, asof_ + 15 * Years,
452442
asof_ + 20 * Years};
453443

454-
vector<Rate> ratesZCII = {2.825, 2.9425, 2.975, 2.983, 3.0, 3.01, 3.008,
455-
3.009, 3.013, 3.0445, 3.044, 3.09, 3.109, 3.108};
444+
vector<Rate> ratesZCII = {2.9425, 2.975, 2.983, 3.0, 3.01, 3.008, 3.009, 3.013, 3.0445, 3.044, 3.09, 3.109, 3.108};
456445

457446
zeroInflationIndices_[make_pair(Market::defaultConfiguration, "EUHICPXT")] =
458447
makeZeroInflationIndex("EUHICPXT", datesZCII, ratesZCII, euii,
@@ -555,7 +544,7 @@ Handle<CPICapFloorTermPriceSurface> TestMarket::flatRateCps(Handle<ZeroInflation
555544
cPrice, fPrice));
556545
return Handle<CPICapFloorTermPriceSurface>(ts);
557546
}
558-
547+
559548
Handle<QuantLib::CPIVolatilitySurface> TestMarket::flatCpiVolSurface(Volatility v) {
560549
Natural settleDays = 0;
561550
Calendar cal = TARGET();
@@ -578,9 +567,19 @@ Handle<ZeroInflationIndex> TestMarket::makeZeroInflationIndex(string index, vect
578567
vector<QuantLib::ext::shared_ptr<BootstrapHelper<ZeroInflationTermStructure>>> instruments;
579568
for (Size i = 0; i < dates.size(); i++) {
580569
Handle<Quote> quote(QuantLib::ext::shared_ptr<Quote>(new SimpleQuote(rates[i] / 100.0)));
581-
QuantLib::ext::shared_ptr<BootstrapHelper<ZeroInflationTermStructure>> anInstrument(new ZeroCouponInflationSwapHelper(
582-
quote, Period(2, Months), dates[i], TARGET(), ModifiedFollowing, ActualActual(ActualActual::ISDA), ii, CPI::AsIndex, yts));
583-
anInstrument->unregisterWith(Settings::instance().evaluationDate());
570+
QuantLib::ext::shared_ptr<BootstrapHelper<ZeroInflationTermStructure>> anInstrument(
571+
new ZeroCouponInflationSwapHelper(quote, Period(2, Months), dates[i], TARGET(), ModifiedFollowing,
572+
ActualActual(ActualActual::ISDA), ii, CPI::AsIndex, yts, asof_));
573+
574+
// Remove the helper's observation of the inflation index. This has the effect that the
575+
// PiecewiseZeroInflationCurve created below will also not observe the index. It will only get recalculated
576+
// if the initial market quotes change or if the initial nominal yield curve changes. Observation of the index
577+
// was interfering with scenario generation. The PiecewiseZeroInflationCurve was getting recalculated on the
578+
// first time grid date t_1 i.e. was not using the t_0 calculated curve.
579+
anInstrument->unregisterWithAll();
580+
anInstrument->registerWith(yts);
581+
anInstrument->registerWith(quote);
582+
584583
instruments.push_back(anInstrument);
585584
};
586585
// we can use historical or first ZCIIS for this
@@ -607,9 +606,25 @@ Handle<YoYInflationIndex> TestMarket::makeYoYInflationIndex(string index, vector
607606
for (Size i = 0; i < dates.size(); i++) {
608607
Handle<Quote> quote(QuantLib::ext::shared_ptr<Quote>(new SimpleQuote(rates[i] / 100.0)));
609608
QL_DEPRECATED_DISABLE_WARNING
610-
QuantLib::ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure>> anInstrument(new YearOnYearInflationSwapHelper(
611-
quote, Period(2, Months), dates[i], TARGET(), ModifiedFollowing, ActualActual(ActualActual::ISDA), ii, yts));
609+
QuantLib::ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure>> anInstrument(
610+
new YearOnYearInflationSwapHelper(quote, Period(2, Months), dates[i], TARGET(), ModifiedFollowing,
611+
ActualActual(ActualActual::ISDA), ii, yts, asof_));
612612
QL_DEPRECATED_ENABLE_WARNING
613+
614+
// Remove the helper's observation of the inflation index. This has the effect that the
615+
// PiecewiseYoYInflationCurve created below will also not observe the index. It will only get recalculated
616+
// if the initial market quotes change or if the initial nominal yield curve changes.
617+
// Note: QuantLib needs a change so that if swap start is provided in the helper above then updateDates_ on
618+
// the RelativeDateBootstrapHelper should be false and hence the helper does not observe Settings
619+
// evaluationDate. Without this fix, the unregister here does this also.
620+
// These changes are needed to allow ObservationModeTest/testDefer to pass. Without them
621+
// YearOnYearInflationSwapHelper::initializeDates() gets called due to evaluation date changes, the yyiis_
622+
// member gets reassigned but the original value is still in the deferredObervers_. The testDefer test then
623+
// crashes when deferredObserver->update(); is called in ObservableSettings::enableUpdates() with
624+
// deferredObserver null.
625+
anInstrument->unregisterWithAll();
626+
anInstrument->registerWith(yts);
627+
anInstrument->registerWith(quote);
613628
instruments.push_back(anInstrument);
614629
};
615630
// we can use historical or first ZCIIS for this
@@ -702,7 +717,7 @@ TestMarketParCurves::TestMarketParCurves(const Date& asof) : MarketImpl(false) {
702717
vector<Real> parRates(parInst.size(), parRate);
703718
createDiscountCurve(ccy, parInst, parTenor, parRates);
704719
}
705-
720+
706721
// add fx rates
707722
// add fx rates
708723
std::map<std::string, QuantLib::Handle<QuantLib::Quote>> quotes;
@@ -1127,7 +1142,7 @@ void TestMarketParCurves::createZeroInflationIndex(const string& idxName, const
11271142
yieldCurve(YieldCurveType::Discount, ccy, Market::defaultConfiguration)));
11281143
}
11291144
QuantLib::ext::shared_ptr<ZeroInflationTermStructure> zeroCurve;
1130-
1145+
11311146
Date baseDate = QuantExt::ZeroInflation::curveBaseDate(false, asof_, conv->observationLag(), zii->frequency(), zii);
11321147
zeroCurve = QuantLib::ext::shared_ptr<PiecewiseZeroInflationCurve<Linear>>(
11331148
new PiecewiseZeroInflationCurve<Linear>(asof_, baseDate, conv->observationLag(), zii->frequency(), conv->dayCounter(), instruments));
@@ -1784,7 +1799,7 @@ TestConfigurationObjects::setupSensitivityScenarioData(bool hasSwapVolCube, bool
17841799
return sensiData;
17851800
};
17861801

1787-
1802+
17881803
QuantLib::ext::shared_ptr<ore::analytics::ScenarioSimMarketParameters> TestConfigurationObjects::setupSimMarketData2() {
17891804
QuantLib::ext::shared_ptr<ore::analytics::ScenarioSimMarketParameters> simMarketData(
17901805
new ore::analytics::ScenarioSimMarketParameters());

OREData/ored/marketdata/inflationcurve.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,12 @@ InflationCurve::CurveBuildResults
307307
zcq->quote(), convention->observationLag(), maturity, convention->fixCalendar(),
308308
convention->fixConvention(), convention->dayCounter(), index, observationInterpolation, nominalTs,
309309
swapStart);
310-
instrument->unregisterWith(Settings::instance().evaluationDate());
310+
311+
// Unregister with inflation index. See PR #326 on github for details.
312+
instrument->unregisterWithAll();
313+
instrument->registerWith(nominalTs);
314+
instrument->registerWith(zcq->quote());
315+
311316
helpers.push_back(instrument);
312317
results.pillarDates.push_back(instrument->pillarDate());
313318
results.mdQuoteLabels.push_back(md->name());
@@ -413,7 +418,12 @@ InflationCurve::CurveBuildResults
413418
auto instrument = QuantLib::ext::make_shared<YearOnYearInflationSwapHelper>(
414419
quote, convention->observationLag(), maturity, convention->fixCalendar(), convention->fixConvention(),
415420
convention->dayCounter(), index, nominalTs, swapStart);
416-
instrument->unregisterWith(Settings::instance().evaluationDate());
421+
422+
// Unregister with inflation index (and evaluationDate). See PR #326 on github for details.
423+
instrument->unregisterWithAll();
424+
instrument->registerWith(nominalTs);
425+
instrument->registerWith(quote);
426+
417427
results.pillarDates.push_back(instrument->pillarDate());
418428
helpers.push_back(instrument);
419429
results.mdQuoteLabels.push_back(md->name());

OREData/ored/utilities/xmlutils.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,15 @@ vector<XMLNode*> XMLUtils::getChildrenNodes(XMLNode* node, const string& name) {
452452
return res;
453453
}
454454

455+
vector<XMLNode*> XMLUtils::getAnyChildrenNodes(XMLNode* node, const std::vector<string>& names) {
456+
vector<XMLNode*> res;
457+
for (auto const& n : names) {
458+
auto tmp = getChildrenNodes(node, n);
459+
res.insert(res.end(), tmp.begin(), tmp.end());
460+
}
461+
return res;
462+
}
463+
455464
vector<XMLNode*> XMLUtils::getChildrenNodesWithAttributes(XMLNode* parent, const string& names, const string& name,
456465
const string& attrName, vector<string>& attrs,
457466
bool mandatory) {

OREData/ored/utilities/xmlutils.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ class XMLUtils {
252252
//! Returns all the children with a given name
253253
// To get all children, set name equal to ""
254254
static vector<XMLNode*> getChildrenNodes(XMLNode* node, const string& name);
255+
static vector<XMLNode*> getAnyChildrenNodes(XMLNode* node, const std::vector<string>& names);
255256

256257
static vector<XMLNode*> getChildrenNodesWithAttributes(XMLNode* node, const string& names, const string& name,
257258
const string& attrName, vector<string>& attrs,

OREData/test/localvol.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ void testCalibrationInstrumentRepricing(const Model::Type type, const std::vecto
7575
params.regressionOrder = 1;
7676
auto localVol = QuantLib::ext::make_shared<BlackScholes>(
7777
type, size, "EUR", process->riskFreeRate(), "EQ-DUMMY", "EUR", builder.model(), simDates,
78-
QuantLib::ext::make_shared<IborFallbackConfig>(IborFallbackConfig::defaultConfig()), "LocalVol",
78+
QuantLib::ext::make_shared<IborFallbackConfig>(IborFallbackConfig::defaultConfig()), "Smile",
7979
std::vector<Real>{}, params);
8080

8181
// loop over the calibration options and price them in the local vol model using MC
@@ -205,8 +205,8 @@ BOOST_AUTO_TEST_CASE(testSabrVols) {
205205

206206
auto process = QuantLib::ext::make_shared<GeneralizedBlackScholesProcess>(spot, q, r, vol);
207207

208-
testCalibrationInstrumentRepricing(Model::Type::MC, expiries, moneyness, process, 20, 10000, 0.30);
209-
testCalibrationInstrumentRepricing(Model::Type::FD, expiries, moneyness, process, 20, 100, 0.30);
208+
testCalibrationInstrumentRepricing(Model::Type::MC, expiries, moneyness, process, 20, 10000, 0.35);
209+
testCalibrationInstrumentRepricing(Model::Type::FD, expiries, moneyness, process, 20, 100, 0.35);
210210
}
211211

212212
BOOST_AUTO_TEST_SUITE_END()

QuantExt/qle/termstructures/averageoisratehelper.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ AverageOISRateHelper::AverageOISRateHelper(
5959

6060
void AverageOISRateHelper::initializeDates() {
6161

62-
averageOIS_ = MakeAverageOIS(swapTenor_, overnightIndex_, onTenor_, quote().empty() ? 0.0 : quote()->value(),
63-
fixedTenor_, fixedDayCounter_, spotLagTenor_)
62+
averageOIS_ = MakeAverageOIS(swapTenor_, overnightIndex_, onTenor_,
63+
quote().empty() || !quote()->isValid() ? 0.0 : quote()->value(), fixedTenor_,
64+
fixedDayCounter_, spotLagTenor_)
6465
.withFixedCalendar(fixedCalendar_)
6566
.withFixedConvention(fixedConvention_)
6667
.withFixedTerminationDateConvention(fixedConvention_)

QuantExt/qle/termstructures/basistwoswaphelper.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ void BasisTwoSwapHelper::initializeDates() {
7575
of the atm swap rate in MakeVanillaSwap operator ...(). If it is
7676
Null, you get an exception because the discountRelinkableHandle_
7777
is initially empty. */
78-
longSwap_ = MakeVanillaSwap(swapTenor_, longIndex_, quote().empty() || !longMinusShort_ ? 0.0 : quote()->value())
78+
longSwap_ = MakeVanillaSwap(swapTenor_, longIndex_,
79+
quote().empty() || !quote()->isValid() || !longMinusShort_ ? 0.0 : quote()->value())
7980
.withDiscountingTermStructure(discountRelinkableHandle_)
8081
.withFixedLegDayCount(longFixedDayCount_)
8182
.withFixedLegTenor(Period(longFixedFrequency_))
@@ -84,7 +85,8 @@ void BasisTwoSwapHelper::initializeDates() {
8485
.withFixedLegCalendar(calendar_)
8586
.withFloatingLegCalendar(calendar_);
8687

87-
shortSwap_ = MakeVanillaSwap(swapTenor_, shortIndex_, quote().empty() || longMinusShort_ ? 0.0 : quote()->value())
88+
shortSwap_ = MakeVanillaSwap(swapTenor_, shortIndex_,
89+
quote().empty() || !quote()->isValid() || longMinusShort_ ? 0.0 : quote()->value())
8890
.withDiscountingTermStructure(discountRelinkableHandle_)
8991
.withFixedLegDayCount(shortFixedDayCount_)
9092
.withFixedLegTenor(Period(shortFixedFrequency_))

QuantExt/qle/termstructures/brlcdiratehelper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ void BRLCdiRateHelper::initializeDates() {
6464

6565
// Create the BRL CDI swap
6666
swap_ = QuantLib::ext::make_shared<BRLCdiSwap>(OvernightIndexedSwap::Payer, 1.0, startDate, endDate,
67-
quote().empty() ? 0.01 : quote()->value(), brlCdiIndex_, 0.0,
68-
telescopicValueDates_);
67+
quote().empty() || !quote()->isValid() ? 0.01 : quote()->value(),
68+
brlCdiIndex_, 0.0, telescopicValueDates_);
6969

7070
// Set the pricing engine
7171
swap_->setPricingEngine(QuantLib::ext::make_shared<DiscountingSwapEngine>(discountRelinkableHandle_));

QuantExt/qle/termstructures/crossccybasismtmresetswaphelper.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,9 @@ void CrossCcyBasisMtMResetSwapHelper::initializeDates() {
155155

156156
swap_ = QuantLib::ext::make_shared<CrossCcyBasisMtMResetSwap>(
157157
foreignNominal, foreignCurrency_, foreignLegSchedule, foreignCcyIndex_,
158-
!spreadOnForeignCcy_ || quote().empty() ? 0.0 : quote()->value(), domesticCurrency_, domesticLegSchedule,
159-
domesticCcyIndex_, spreadOnForeignCcy_ || quote().empty() ? 0.0 : quote()->value(), fxIdx, true,
158+
!spreadOnForeignCcy_ || quote().empty() || !quote()->isValid() ? 0.0 : quote()->value(), domesticCurrency_,
159+
domesticLegSchedule, domesticCcyIndex_,
160+
spreadOnForeignCcy_ || quote().empty() || !quote()->isValid() ? 0.0 : quote()->value(), fxIdx, true,
160161
foreignPaymentLag_, domesticPaymentLag_, foreignIncludeSpread_, foreignLookback_, foreignFixingDays_,
161162
foreignRateCutoff_, foreignIsAveraged_, domesticIncludeSpread_, domesticLookback_, domesticFixingDays_,
162163
domesticRateCutoff_, domesticIsAveraged_, telescopicValueDates_);

QuantExt/qle/termstructures/crossccybasisswaphelper.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,11 @@ void CrossCcyBasisSwapHelper::initializeDates() {
147147

148148
/* Arbitrarily set the spread leg as the pay leg */
149149
swap_ = QuantLib::ext::make_shared<CrossCcyBasisSwap>(
150-
spreadLegNominal, spreadLegCurrency_, spreadLegSchedule, spreadIndex_, quote().empty() ? 0.0 : quote()->value(),
151-
spreadGearing_, flatLegNominal, flatLegCurrency_, flatLegSchedule, flatIndex_, spreadOnFlatLeg_, flatGearing_,
152-
paymentLag_, flatPaymentLag_, includeSpread_, lookback_, fixingDays_, rateCutoff_, isAveraged_,
153-
flatIncludeSpread_, flatLookback_, flatFixingDays_, flatRateCutoff_, flatIsAveraged_, telescopicValueDates_);
150+
spreadLegNominal, spreadLegCurrency_, spreadLegSchedule, spreadIndex_,
151+
quote().empty() || !quote()->isValid() ? 0.0 : quote()->value(), spreadGearing_, flatLegNominal,
152+
flatLegCurrency_, flatLegSchedule, flatIndex_, spreadOnFlatLeg_, flatGearing_, paymentLag_, flatPaymentLag_,
153+
includeSpread_, lookback_, fixingDays_, rateCutoff_, isAveraged_, flatIncludeSpread_, flatLookback_,
154+
flatFixingDays_, flatRateCutoff_, flatIsAveraged_, telescopicValueDates_);
154155

155156
QuantLib::ext::shared_ptr<PricingEngine> engine;
156157
if (flatIsDomestic_) {

0 commit comments

Comments
 (0)