Skip to content

Commit 8c1813c

Browse files
committed
Add wildcard support for direct segments
1 parent 5922252 commit 8c1813c

2 files changed

Lines changed: 101 additions & 8 deletions

File tree

OREData/ored/marketdata/yieldcurve.cpp

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -892,34 +892,63 @@ void YieldCurve::buildDiscountCurve() {
892892
boost::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
893893
boost::shared_ptr<Convention> convention;
894894

895-
for (Size i = 0; i < discountQuoteIDs.size(); ++i) {
896-
boost::shared_ptr<MarketDatum> marketQuote = loader_.get(discountQuoteIDs[i], asofDate_);
895+
vector<string> quotes;
896+
quotes.reserve(discountQuoteIDs.size()); // Reserve space for efficiency
897+
898+
std::transform(discountQuoteIDs.begin(), discountQuoteIDs.end(), std::back_inserter(quotes),
899+
[](const std::pair<string, bool>& pair) {
900+
return pair.first; // Extract only the quote part
901+
});
902+
903+
auto wildcard = getUniqueWildcard(quotes);
904+
905+
std::set<boost::shared_ptr<MarketDatum>> marketData;
906+
if (wildcard) {
907+
marketData = loader_.get(*wildcard, asofDate_);
908+
} else {
909+
std::ostringstream ss;
910+
ss << MarketDatum::InstrumentType::DISCOUNT << "/" << MarketDatum::QuoteType::RATE << "/" << currency_ << "/*";
911+
// valuta / curve namn
912+
Wildcard w(ss.str());
913+
marketData = loader_.get(w, asofDate_);
914+
}
915+
916+
for (const auto& marketQuote : marketData) {
897917
if (marketQuote) {
898918
QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::DISCOUNT,
899919
"Market quote not of type Discount.");
900920
boost::shared_ptr<DiscountQuote> discountQuote = boost::dynamic_pointer_cast<DiscountQuote>(marketQuote);
901921

902-
if(discountQuote->date() != Date()){
922+
// filtering
923+
if (!wildcard) {
924+
vector<string>::const_iterator it = find(quotes.begin(), quotes.end(), discountQuote->name());
925+
if (it == quotes.end())
926+
continue;
927+
}
928+
929+
930+
if (discountQuote->date() != Date()) {
903931

904932
data[discountQuote->date()] = discountQuote->quote()->value();
905933

906-
} else if (discountQuote->tenor() != Period()){
934+
} else if (discountQuote->tenor() != Period()) {
907935

908-
if(!convention)
936+
if (!convention)
909937
convention = conventions->get(discountCurveSegment->conventionsID());
910-
boost::shared_ptr<ZeroRateConvention> zeroConvention = boost::dynamic_pointer_cast<ZeroRateConvention>(convention);
938+
boost::shared_ptr<ZeroRateConvention> zeroConvention =
939+
boost::dynamic_pointer_cast<ZeroRateConvention>(convention);
911940
QL_REQUIRE(zeroConvention, "could not cast to ZeroRateConvention");
912941

913942
Calendar cal = zeroConvention->tenorCalendar();
914943
BusinessDayConvention rollConvention = zeroConvention->rollConvention();
915944
Date date = cal.adjust(cal.adjust(asofDate_, rollConvention) + discountQuote->tenor(), rollConvention);
916-
DLOG("YieldCurve::buildDiscountCurve - tenor " << discountQuote->tenor() << " to date " << io::iso_date(date));
945+
DLOG("YieldCurve::buildDiscountCurve - tenor " << discountQuote->tenor() << " to date "
946+
<< io::iso_date(date));
917947
data[date] = discountQuote->quote()->value();
918948

919949
} else {
920950
QL_FAIL("YieldCurve::buildDiscountCurve - neither date nor tenor recognised");
921951
}
922-
923952
}
924953
}
925954

OREData/test/yieldcurve.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,70 @@ BOOST_AUTO_TEST_CASE(testBootstrapAndFixings) {
246246
BOOST_CHECK_NO_THROW(YieldCurve jpyYieldCurve(asof, spec, curveConfigs, loader));
247247
}
248248

249+
BOOST_AUTO_TEST_CASE(testBootstrapAndFixingsDirectYc) {
250+
251+
Date asof(13, October, 2023);
252+
Settings::instance().evaluationDate() = asof;
253+
254+
YieldCurveSpec spec("EUR", "EUR-CURVE");
255+
256+
CurveConfigurations curveConfigs;
257+
258+
vector<string> quotes;
259+
quotes.emplace_back("DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/2023-10-14");
260+
quotes.emplace_back("DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/2023-10-15");
261+
262+
vector<boost::shared_ptr<YieldCurveSegment>> segments{boost::make_shared<DirectYieldCurveSegment>(
263+
"Discount", "", quotes)};
264+
265+
boost::shared_ptr<YieldCurveConfig> yCConfig =
266+
boost::make_shared<YieldCurveConfig>("EUR-CURVE", "ORE YieldCurve built from EUR-CURVE_2023-10-13", "EUR", "", segments);
267+
curveConfigs.add(CurveSpec::CurveType::Yield, "EUR-CURVE", yCConfig);
268+
269+
vector<string> data{"2023-10-12 DISCOUNT/RATE/EUR/STINA-CURVE_2023-10-12/2023-10-13 0.77",
270+
"2023-10-12 DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-12/2023-10-12 0.88",
271+
"2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/2023-10-13 1.0",
272+
"2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/2023-10-14 0.99",
273+
"2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/2023-10-15 0.98",
274+
"2023-10-13 COMMODITY_FWD/PRICE/GOLD/USD/2023-10-31 1158.8",
275+
"2023-10-13 COMMODITY_FWD/PRICE/GOLD/USD/2023-11-01 1160.9",
276+
"2023-10-13 COMMODITY_FWD/PRICE/GOLD/USD/2023-11-02 1163.4"};
277+
MarketDataLoader loader(data);
278+
279+
BOOST_CHECK_NO_THROW(YieldCurve yieldCurve(asof, spec, curveConfigs, loader));
280+
}
281+
282+
BOOST_AUTO_TEST_CASE(testBootstrapAndFixingsDirectYcWildChar) {
283+
284+
Date asof(13, October, 2023);
285+
Settings::instance().evaluationDate() = asof;
286+
287+
YieldCurveSpec spec("EUR", "EUR-CURVE");
288+
289+
CurveConfigurations curveConfigs;
290+
291+
vector<string> quotes;
292+
quotes.emplace_back("DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/*");
293+
294+
vector<boost::shared_ptr<YieldCurveSegment>> segments{
295+
boost::make_shared<DirectYieldCurveSegment>("Discount", "", quotes)};
296+
297+
boost::shared_ptr<YieldCurveConfig> yCConfig = boost::make_shared<YieldCurveConfig>(
298+
"EUR-CURVE", "ORE YieldCurve built from EUR-CURVE_2023-10-13", "EUR", "", segments);
299+
curveConfigs.add(CurveSpec::CurveType::Yield, "EUR-CURVE", yCConfig);
300+
301+
vector<string> data{"2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/2023-10-13 1.0",
302+
"2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/2023-10-14 0.99",
303+
"2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE_2023-10-13/2023-10-15 0.98",
304+
"2023-10-13 EQUITY_FWD/PRICE/SP5/USD/1Y 1500.00",
305+
"2023-10-13 EQUITY_FWD/PRICE/SP5/USD/20231014 1500.00",
306+
"2023-10-13 EQUITY_DIVIDEND/RATE/SP5/USD/20231015 0.00",
307+
"2023-10-13 EQUITY_DIVIDEND/RATE/SP5/USD/2Y 0.00"};
308+
MarketDataLoader loader(data);
309+
310+
BOOST_CHECK_NO_THROW(YieldCurve yieldCurve(asof, spec, curveConfigs, loader));
311+
}
312+
249313
// Test ARS-IN-USD failures using the old QuantLib::IterativeBootstrap parameters
250314
BOOST_DATA_TEST_CASE(testBootstrapARSinUSDFailures, bdata::make(curveConfigFiles), curveConfigFile) {
251315

0 commit comments

Comments
 (0)