Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Types | Public Member Functions | List of all members
YieldCurve Class Reference

Wrapper class for building yield term structures. More...

#include <ored/marketdata/yieldcurve.hpp>

+ Collaboration diagram for YieldCurve:

Public Types

enum class  InterpolationVariable { Zero , Discount , Forward }
 Supported interpolation variables. More...
 
enum class  InterpolationMethod {
  Linear , LogLinear , NaturalCubic , FinancialCubic ,
  ConvexMonotone , Quadratic , LogQuadratic , LogNaturalCubic ,
  LogFinancialCubic , LogCubicSpline , Hermite , CubicSpline ,
  DefaultLogMixedLinearCubic , MonotonicLogMixedLinearCubic , KrugerLogMixedLinearCubic , LogMixedLinearCubicNaturalSpline ,
  ExponentialSplines , NelsonSiegel , Svensson
}
 Supported interpolation methods. More...
 

Public Member Functions

 YieldCurve (Date asof, YieldCurveSpec curveSpec, const CurveConfigurations &curveConfigs, const Loader &loader, const map< string, QuantLib::ext::shared_ptr< YieldCurve > > &requiredYieldCurves=map< string, QuantLib::ext::shared_ptr< YieldCurve > >(), const map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &requiredDefaultCurves=map< string, QuantLib::ext::shared_ptr< DefaultCurve > >(), const FXTriangulation &fxTriangulation=FXTriangulation(), const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceData=nullptr, const IborFallbackConfig &iborfallbackConfig=IborFallbackConfig::defaultConfig(), const bool preserveQuoteLinkage=false, const bool buildCalibrationInfo=true, const Market *market=nullptr)
 Constructor. More...
 

Inspectors

Date asofDate_
 
Currency currency_
 
YieldCurveSpec curveSpec_
 
DayCounter zeroDayCounter_
 
bool extrapolation_
 
QuantLib::ext::shared_ptr< YieldCurvediscountCurve_
 
const Loaderloader_
 
RelinkableHandle< YieldTermStructure > h_
 
QuantLib::ext::shared_ptr< YieldTermStructure > p_
 
QuantLib::ext::shared_ptr< YieldCurveCalibrationInfocalibrationInfo_
 
QuantLib::ext::shared_ptr< YieldCurveConfigcurveConfig_
 
vector< QuantLib::ext::shared_ptr< YieldCurveSegment > > curveSegments_
 
InterpolationVariable interpolationVariable_
 
InterpolationMethod interpolationMethod_
 
Size mixedInterpolationSize_ = 0
 
map< string, QuantLib::ext::shared_ptr< YieldCurve > > requiredYieldCurves_
 
map< string, QuantLib::ext::shared_ptr< DefaultCurve > > requiredDefaultCurves_
 
const FXTriangulationfxTriangulation_
 
const QuantLib::ext::shared_ptr< ReferenceDataManagerreferenceData_
 
IborFallbackConfig iborFallbackConfig_
 
const bool preserveQuoteLinkage_
 
bool buildCalibrationInfo_
 
const Marketmarket_
 
const Handle< YieldTermStructure > & handle () const
 
YieldCurveSpec curveSpec () const
 
const Date & asofDate () const
 
const Currency & currency () const
 
QuantLib::ext::shared_ptr< YieldCurveCalibrationInfocalibrationInfo () const
 
void buildDiscountCurve ()
 
void buildZeroCurve ()
 
void buildZeroSpreadedCurve ()
 
void buildBootstrappedCurve ()
 
void buildDiscountRatioCurve ()
 Build a yield curve that uses QuantExt::DiscountRatioModifiedCurve. More...
 
void buildFittedBondCurve ()
 Build a yield curve that uses QuantLib::FittedBondCurve. More...
 
void buildWeightedAverageCurve ()
 Build a yield curve that uses QuantExt::WeightedYieldTermStructure. More...
 
void buildYieldPlusDefaultCurve ()
 Build a yield curve that uses QuantExt::YieldPlusDefaultYieldTermStructure. More...
 
void buildIborFallbackCurve ()
 Build a yield curve that uses QuantExt::IborFallbackCurve. More...
 
void buildBondYieldShiftedCurve ()
 Build a yield curve that uses QuantExt::bondYieldShiftedCurve. More...
 
QuantLib::ext::shared_ptr< YieldCurvegetYieldCurve (const std::string &ccy, const std::string &id) const
 Return the yield curve with the given id from the requiredYieldCurves_ map. More...
 
QuantLib::ext::shared_ptr< YieldTermStructure > piecewisecurve (vector< QuantLib::ext::shared_ptr< RateHelper > > instruments)
 
void addDeposits (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addFutures (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addFras (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addOISs (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addSwaps (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addAverageOISs (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addTenorBasisSwaps (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addTenorBasisTwoSwaps (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addBMABasisSwaps (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addFXForwards (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addCrossCcyBasisSwaps (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
void addCrossCcyFixFloatSwaps (const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
 
QuantLib::ext::shared_ptr< FXSpotQuotegetFxSpotQuote (string spotId)
 

Detailed Description

Wrapper class for building yield term structures.

Given yield curve specification and its configuration this class will actually build a QuantLib yield termstructure.

Definition at line 61 of file yieldcurve.hpp.

Member Enumeration Documentation

◆ InterpolationVariable

enum class InterpolationVariable
strong

Supported interpolation variables.

Enumerator
Zero 
Discount 
Forward 

Definition at line 64 of file yieldcurve.hpp.

◆ InterpolationMethod

enum class InterpolationMethod
strong

Supported interpolation methods.

Enumerator
Linear 
LogLinear 
NaturalCubic 
FinancialCubic 
ConvexMonotone 
Quadratic 
LogQuadratic 
LogNaturalCubic 
LogFinancialCubic 
LogCubicSpline 
Hermite 
CubicSpline 
DefaultLogMixedLinearCubic 
MonotonicLogMixedLinearCubic 
KrugerLogMixedLinearCubic 
LogMixedLinearCubicNaturalSpline 
ExponentialSplines 
NelsonSiegel 
Svensson 

Definition at line 67 of file yieldcurve.hpp.

67 {
68 Linear,
78 Hermite,
84 ExponentialSplines, // fitted bond curves only
85 NelsonSiegel, // fitted bond curves only
86 Svensson // fitted bond curves only
87 };

Constructor & Destructor Documentation

◆ YieldCurve()

YieldCurve ( Date  asof,
YieldCurveSpec  curveSpec,
const CurveConfigurations curveConfigs,
const Loader loader,
const map< string, QuantLib::ext::shared_ptr< YieldCurve > > &  requiredYieldCurves = map<string, QuantLib::ext::shared_ptr<YieldCurve>>(),
const map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &  requiredDefaultCurves = map<string, QuantLib::ext::shared_ptr<DefaultCurve>>(),
const FXTriangulation fxTriangulation = FXTriangulation(),
const QuantLib::ext::shared_ptr< ReferenceDataManager > &  referenceData = nullptr,
const IborFallbackConfig iborfallbackConfig = IborFallbackConfig::defaultConfig(),
const bool  preserveQuoteLinkage = false,
const bool  buildCalibrationInfo = true,
const Market market = nullptr 
)

Constructor.

Parameters
asofValuation date
curveSpecYield curve specification
curveConfigsRepository of yield curve configurations
loaderMarket data loader
requiredYieldCurvesMap of underlying yield curves if required
requiredDefaultCurvesMap of underlying default curves if required
fxTriangulationFxTriangultion to get FX rate from cross if needed
referenceDataoptional pointer to reference data, needed to build fitted bond curves
iborfallbackConfigibor fallback config
preserveQuoteLinkageif true keep qloader quotes linked to yield ts, otherwise detach them
buildCalibrationInfobuild calibration info
marketmarket object to look up external discount curves

Definition at line 277 of file yieldcurve.cpp.

284 : asofDate_(asof), curveSpec_(curveSpec), loader_(loader), requiredYieldCurves_(requiredYieldCurves),
285 requiredDefaultCurves_(requiredDefaultCurves), fxTriangulation_(fxTriangulation), referenceData_(referenceData),
286 iborFallbackConfig_(iborFallbackConfig), preserveQuoteLinkage_(preserveQuoteLinkage),
287 buildCalibrationInfo_(buildCalibrationInfo), market_(market) {
288
289 try {
290
292 QL_REQUIRE(curveConfig_, "No yield curve configuration found "
293 "for config ID "
295 currency_ = parseCurrency(curveConfig_->currency());
296
297 /* If discount curve is not the curve being built, look for it in the map that is passed in. */
298 string discountCurveID = curveConfig_->discountCurveID();
299 if (discountCurveID != curveConfig_->curveID() && !discountCurveID.empty()) {
300 discountCurveID = yieldCurveKey(currency_, discountCurveID, asofDate_);
301 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
302 it = requiredYieldCurves_.find(discountCurveID);
303 if (it != requiredYieldCurves_.end()) {
304 discountCurve_ = it->second;
305 } else {
306 QL_FAIL("The discount curve, " << discountCurveID
307 << ", required in the building "
308 "of the curve, "
309 << curveSpec_.name() << ", was not found.");
310 }
311 }
312
313 curveSegments_ = curveConfig_->curveSegments();
316 zeroDayCounter_ = parseDayCounter(curveConfig_->zeroDayCounter());
317 extrapolation_ = curveConfig_->extrapolation();
318
320 DLOG("Building DiscountCurve " << curveSpec_);
322 } else if (curveSegments_[0]->type() == YieldCurveSegment::Type::Zero) {
323 DLOG("Building ZeroCurve " << curveSpec_);
325 } else if (curveSegments_[0]->type() == YieldCurveSegment::Type::ZeroSpread) {
326 DLOG("Building ZeroSpreadedCurve " << curveSpec_);
329 DLOG("Building discount ratio yield curve " << curveSpec_);
331 } else if (curveSegments_[0]->type() == YieldCurveSegment::Type::FittedBond) {
332 DLOG("Building FittedBondCurve " << curveSpec_);
335 DLOG("Building WeightedAverageCurve " << curveSpec_);
338 DLOG("Building YieldPlusDefaultCurve " << curveSpec_);
340 } else if (curveSegments_[0]->type() == YieldCurveSegment::Type::IborFallback) {
341 DLOG("Building IborFallbackCurve " << curveSpec_);
344 DLOG("Building BondYieldShiftedCurve " << curveSpec_);
346 } else {
347 DLOG("Bootstrapping YieldCurve " << curveSpec_);
349 }
350
351 h_.linkTo(p_);
352 if (extrapolation_) {
353 h_->enableExtrapolation();
354 }
355
356 // populate shared calibration info
357
359 if (calibrationInfo_ == nullptr)
360 calibrationInfo_ = QuantLib::ext::make_shared<YieldCurveCalibrationInfo>();
361 calibrationInfo_->dayCounter = zeroDayCounter_.name();
362 calibrationInfo_->currency = currency_.code();
363 if (calibrationInfo_->pillarDates.empty()) {
365 calibrationInfo_->pillarDates.push_back(asofDate_ + p);
366 }
367 for (auto const& d : calibrationInfo_->pillarDates) {
368 calibrationInfo_->zeroRates.push_back(p_->zeroRate(d, zeroDayCounter_, Continuous));
369 calibrationInfo_->discountFactors.push_back(p_->discount(d));
370 calibrationInfo_->times.push_back(p_->timeFromReference(d));
371 }
372 }
373
374 } catch (QuantLib::Error& e) {
375 QL_FAIL("yield curve building failed for curve " << curveSpec_.curveConfigID() << " on date "
376 << io::iso_date(asof) << ": " << e.what());
377 } catch (std::exception& e) {
378 QL_FAIL(e.what());
379 } catch (...) {
380 QL_FAIL("unknown error");
381 }
382
383 // force bootstrap so that errors are thrown during the build, not later
384 h_->discount(QL_EPSILON);
385
386 DLOG("Yield curve " << curveSpec_.name() << " built");
387}
const std::string & curveConfigID() const
Definition: curvespec.hpp:83
string name() const
returns the unique curve name
Definition: curvespec.hpp:78
QuantLib::ext::shared_ptr< YieldTermStructure > p_
Definition: yieldcurve.hpp:139
void buildBondYieldShiftedCurve()
Build a yield curve that uses QuantExt::bondYieldShiftedCurve.
const bool preserveQuoteLinkage_
Definition: yieldcurve.hpp:172
void buildDiscountRatioCurve()
Build a yield curve that uses QuantExt::DiscountRatioModifiedCurve.
DayCounter zeroDayCounter_
Definition: yieldcurve.hpp:132
map< string, QuantLib::ext::shared_ptr< DefaultCurve > > requiredDefaultCurves_
Definition: yieldcurve.hpp:168
void buildYieldPlusDefaultCurve()
Build a yield curve that uses QuantExt::YieldPlusDefaultYieldTermStructure.
void buildFittedBondCurve()
Build a yield curve that uses QuantLib::FittedBondCurve.
RelinkableHandle< YieldTermStructure > h_
Definition: yieldcurve.hpp:138
const QuantLib::ext::shared_ptr< ReferenceDataManager > referenceData_
Definition: yieldcurve.hpp:170
const Market * market_
Definition: yieldcurve.hpp:174
YieldCurveSpec curveSpec_
Definition: yieldcurve.hpp:131
QuantLib::ext::shared_ptr< YieldCurveConfig > curveConfig_
Definition: yieldcurve.hpp:162
const FXTriangulation & fxTriangulation_
Definition: yieldcurve.hpp:169
void buildIborFallbackCurve()
Build a yield curve that uses QuantExt::IborFallbackCurve.
YieldCurveSpec curveSpec() const
Definition: yieldcurve.hpp:121
const Loader & loader_
Definition: yieldcurve.hpp:137
InterpolationVariable interpolationVariable_
Definition: yieldcurve.hpp:164
map< string, QuantLib::ext::shared_ptr< YieldCurve > > requiredYieldCurves_
Definition: yieldcurve.hpp:167
InterpolationMethod interpolationMethod_
Definition: yieldcurve.hpp:165
IborFallbackConfig iborFallbackConfig_
Definition: yieldcurve.hpp:171
QuantLib::ext::shared_ptr< YieldCurveCalibrationInfo > calibrationInfo_
Definition: yieldcurve.hpp:140
vector< QuantLib::ext::shared_ptr< YieldCurveSegment > > curveSegments_
Definition: yieldcurve.hpp:163
void buildWeightedAverageCurve()
Build a yield curve that uses QuantExt::WeightedYieldTermStructure.
QuantLib::ext::shared_ptr< YieldCurve > discountCurve_
Definition: yieldcurve.hpp:134
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:290
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
Definition: parsers.cpp:209
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
YieldCurve::InterpolationVariable parseYieldCurveInterpolationVariable(const string &s)
Helper function for parsing interpolation variable.
Definition: yieldcurve.cpp:223
YieldCurve::InterpolationMethod parseYieldCurveInterpolationMethod(const string &s)
Helper function for parsing interpolation method.
Definition: yieldcurve.cpp:180
static const std::vector< QuantLib::Period > defaultPeriods
vector< string > curveConfigs
+ Here is the call graph for this function:

Member Function Documentation

◆ handle()

const Handle< YieldTermStructure > & handle ( ) const

Definition at line 120 of file yieldcurve.hpp.

120{ return h_; }
+ Here is the caller graph for this function:

◆ curveSpec()

YieldCurveSpec curveSpec ( ) const

Definition at line 121 of file yieldcurve.hpp.

121{ return curveSpec_; }

◆ asofDate()

const Date & asofDate ( ) const

Definition at line 122 of file yieldcurve.hpp.

122{ return asofDate_; }

◆ currency()

const Currency & currency ( ) const

Definition at line 123 of file yieldcurve.hpp.

123{ return currency_; }

◆ calibrationInfo()

QuantLib::ext::shared_ptr< YieldCurveCalibrationInfo > calibrationInfo ( ) const

Definition at line 125 of file yieldcurve.hpp.

125{ return calibrationInfo_; }

◆ buildDiscountCurve()

void buildDiscountCurve ( )
private

Definition at line 1090 of file yieldcurve.cpp.

1090 {
1091
1092 QL_REQUIRE(curveSegments_.size() <= 1, "More than one discount curve "
1093 "segment not supported yet.");
1094 QL_REQUIRE(curveSegments_[0]->type() == YieldCurveSegment::Type::Discount,
1095 "The curve segment is not of type Discount.");
1096
1097 // Create the (date, discount) pairs.
1098 map<Date, DiscountFactor> data;
1099 QuantLib::ext::shared_ptr<DirectYieldCurveSegment> discountCurveSegment =
1100 QuantLib::ext::dynamic_pointer_cast<DirectYieldCurveSegment>(curveSegments_[0]);
1101 auto discountQuoteIDs = discountCurveSegment->quotes();
1102
1103 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1104 QuantLib::ext::shared_ptr<Convention> convention;
1105
1106 vector<string> quotes;
1107 quotes.reserve(discountQuoteIDs.size()); // Reserve space for efficiency
1108
1109 std::transform(discountQuoteIDs.begin(), discountQuoteIDs.end(), std::back_inserter(quotes),
1110 [](const std::pair<string, bool>& pair) {
1111 return pair.first; // Extract only the quote part
1112 });
1113
1114 auto wildcard = getUniqueWildcard(quotes);
1115
1116 std::set<QuantLib::ext::shared_ptr<MarketDatum>> marketData;
1117 if (wildcard) {
1118 marketData = loader_.get(*wildcard, asofDate_);
1119 } else {
1120 std::ostringstream ss;
1122 Wildcard w(ss.str());
1123 marketData = loader_.get(w, asofDate_);
1124 }
1125
1126 for (const auto& marketQuote : marketData) {
1127 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::DISCOUNT,
1128 "Market quote not of type Discount.");
1129 QuantLib::ext::shared_ptr<DiscountQuote> discountQuote = QuantLib::ext::dynamic_pointer_cast<DiscountQuote>(marketQuote);
1130
1131 // filtering
1132 if (!wildcard) {
1133 vector<string>::const_iterator it = find(quotes.begin(), quotes.end(), discountQuote->name());
1134 if (it == quotes.end())
1135 continue;
1136 }
1137
1138 if (discountQuote->date() != Date()) {
1139
1140 data[discountQuote->date()] = discountQuote->quote()->value();
1141
1142 } else if (discountQuote->tenor() != Period()) {
1143
1144 if (!convention)
1145 convention = conventions->get(discountCurveSegment->conventionsID());
1146 QuantLib::ext::shared_ptr<ZeroRateConvention> zeroConvention =
1147 QuantLib::ext::dynamic_pointer_cast<ZeroRateConvention>(convention);
1148 QL_REQUIRE(zeroConvention, "could not cast to ZeroRateConvention");
1149
1150 Calendar cal = zeroConvention->tenorCalendar();
1151 BusinessDayConvention rollConvention = zeroConvention->rollConvention();
1152 Date date = cal.adjust(cal.adjust(asofDate_, rollConvention) + discountQuote->tenor(), rollConvention);
1153 DLOG("YieldCurve::buildDiscountCurve - tenor " << discountQuote->tenor() << " to date "
1154 << io::iso_date(date));
1155 data[date] = discountQuote->quote()->value();
1156
1157 } else {
1158 QL_FAIL("YieldCurve::buildDiscountCurve - neither date nor tenor recognised");
1159 }
1160 }
1161
1162 // Some logging and checks
1163 QL_REQUIRE(data.size() > 0, "No market data found for curve spec " << curveSpec_.name() << " with as of date "
1164 << io::iso_date(asofDate_));
1165 if (!wildcard) {
1166 QL_REQUIRE(data.size() == quotes.size(), "Found " << data.size() << " quotes, but "
1167 << quotes.size()
1168 << " quotes given in config " << curveConfig_->curveID());
1169 }
1170
1171 if (data.begin()->first > asofDate_) {
1172 DLOG("Insert discount curve point at time zero for " << curveSpec_.name());
1173 data[asofDate_] = 1.0;
1174 }
1175
1176 QL_REQUIRE(data.size() > 1, "The single discount quote provided "
1177 "should be associated with a date greater than as of date.");
1178
1179 // First build a temporary discount curve
1180 vector<Date> dates;
1181 vector<DiscountFactor> discounts;
1182 map<Date, DiscountFactor>::iterator it;
1183 for (it = data.begin(); it != data.end(); ++it) {
1184 dates.push_back(it->first);
1185 discounts.push_back(it->second);
1186 DLOG("Add discount curve point for " << curveSpec_.name() << ": " << io::iso_date(dates.back()) << " "
1187 << discounts.back());
1188 }
1189
1190 QL_REQUIRE(dates.size() == discounts.size(), "Date and discount vectors differ in size.");
1191
1192 QuantLib::ext::shared_ptr<YieldTermStructure> tempDiscCurve =
1194
1195 // Now build curve with requested conventions
1197 p_ = tempDiscCurve;
1199 vector<Rate> zeroes;
1200 for (Size i = 0; i < dates.size(); ++i) {
1201 Rate zero = tempDiscCurve->zeroRate(dates[i], zeroDayCounter_, Continuous);
1202 zeroes.push_back(zero);
1203 }
1205 } else {
1206 QL_FAIL("Unknown yield curve interpolation variable.");
1207 }
1208}
virtual QuantLib::ext::shared_ptr< MarketDatum > get(const std::string &name, const QuantLib::Date &d) const
get quote by its unique name, throws if not existent, override in derived classes for performance
Definition: loader.cpp:24
@ data
Definition: log.hpp:77
QuantLib::ext::shared_ptr< YieldTermStructure > discountcurve(const vector< Date > &dates, const vector< DiscountFactor > &dfs, const DayCounter &dayCounter, YieldCurve::InterpolationMethod interpolationMethod, Size n)
Create a Interpolated Discount Curve and apply interpolators.
Definition: yieldcurve.cpp:166
QuantLib::ext::shared_ptr< YieldTermStructure > zerocurve(const vector< Date > &dates, const vector< Rate > &yields, const DayCounter &dayCounter, YieldCurve::InterpolationMethod interpolationMethod, Size n)
Create a Interpolated Zero Curve and apply interpolators.
Definition: yieldcurve.cpp:160
boost::optional< Wildcard > getUniqueWildcard(const C &c)
checks if at most one element in C has a wild card and returns it in this case
Definition: wildcard.hpp:65
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildZeroCurve()

void buildZeroCurve ( )
private

Definition at line 845 of file yieldcurve.cpp.

845 {
846
847 QL_REQUIRE(curveSegments_.size() <= 1, "More than one zero curve "
848 "segment not supported yet.");
849 QL_REQUIRE(curveSegments_[0]->type() == YieldCurveSegment::Type::Zero, "The curve segment is not of type Zero.");
850
851 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
852
853 // Fill a vector of zero quotes.
854 vector<QuantLib::ext::shared_ptr<ZeroQuote>> zeroQuotes;
855 QuantLib::ext::shared_ptr<DirectYieldCurveSegment> zeroCurveSegment =
856 QuantLib::ext::dynamic_pointer_cast<DirectYieldCurveSegment>(curveSegments_[0]);
857 auto zeroQuoteIDs = zeroCurveSegment->quotes();
858
859 for (Size i = 0; i < zeroQuoteIDs.size(); ++i) {
860 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(zeroQuoteIDs[i], asofDate_);
861 if (marketQuote) {
862 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::ZERO,
863 "Market quote not of type zero.");
864 QuantLib::ext::shared_ptr<ZeroQuote> zeroQuote = QuantLib::ext::dynamic_pointer_cast<ZeroQuote>(marketQuote);
865 zeroQuotes.push_back(zeroQuote);
866 }
867 }
868
869 // Create the (date, zero) pairs.
870 map<Date, Rate> data;
871 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(curveSegments_[0]->conventionsID());
872 QL_REQUIRE(convention, "No conventions found with ID: " << curveSegments_[0]->conventionsID());
873 QL_REQUIRE(convention->type() == Convention::Type::Zero, "Conventions ID does not give zero rate conventions.");
874 QuantLib::ext::shared_ptr<ZeroRateConvention> zeroConvention = QuantLib::ext::dynamic_pointer_cast<ZeroRateConvention>(convention);
875 DayCounter quoteDayCounter = zeroConvention->dayCounter();
876 for (Size i = 0; i < zeroQuotes.size(); ++i) {
877 QL_REQUIRE(quoteDayCounter == zeroQuotes[i]->dayCounter(),
878 "The day counter should be the same between the conventions"
879 "and the quote.");
880 if (!zeroQuotes[i]->tenorBased()) {
881 data[zeroQuotes[i]->date()] = zeroQuotes[i]->quote()->value();
882 } else {
883 QL_REQUIRE(zeroConvention->tenorBased(), "Using tenor based "
884 "zero rates without tenor based zero rate conventions.");
885 Date zeroDate = asofDate_;
886 if (zeroConvention->spotLag() > 0) {
887 zeroDate = zeroConvention->spotCalendar().advance(zeroDate, zeroConvention->spotLag() * Days);
888 }
889 zeroDate = zeroConvention->tenorCalendar().advance(zeroDate, zeroQuotes[i]->tenor(),
890 zeroConvention->rollConvention(), zeroConvention->eom());
891 data[zeroDate] = zeroQuotes[i]->quote()->value();
892 }
893 }
894
895 QL_REQUIRE(data.size() > 0, "No market data found for curve spec " << curveSpec_.name() << " with as of date "
896 << io::iso_date(asofDate_));
897
898 // \todo review - more flexible (flat vs. linear extrap)?
899 if (data.begin()->first > asofDate_) {
900 Rate rate = data.begin()->second;
901 data[asofDate_] = rate;
902 DLOG("Insert zero curve point at time zero for " << curveSpec_.name() << ": "
903 << "date " << QuantLib::io::iso_date(asofDate_) << ", "
904 << "zero " << fixed << setprecision(4) << data[asofDate_]);
905 }
906
907 QL_REQUIRE(data.size() > 1, "The single zero rate quote provided "
908 "should be associated with a date greater than as of date.");
909
910 // First build temporary curves
911 vector<Date> dates;
912 vector<Rate> zeroes, discounts;
913 dates.push_back(data.begin()->first);
914 zeroes.push_back(data.begin()->second);
915 discounts.push_back(1.0);
916
917 Compounding zeroCompounding = zeroConvention->compounding();
918 Frequency zeroCompoundingFreq = zeroConvention->compoundingFrequency();
919 map<Date, Rate>::iterator it;
920 for (it = ++data.begin(); it != data.end(); ++it) {
921 dates.push_back(it->first);
922 InterestRate tempRate(it->second, quoteDayCounter, zeroCompounding, zeroCompoundingFreq);
923 Time t = quoteDayCounter.yearFraction(asofDate_, it->first);
924 /* Convert zero rate to continuously compounded if necessary */
925 if (zeroCompounding == Continuous) {
926 zeroes.push_back(it->second);
927 } else {
928 zeroes.push_back(tempRate.equivalentRate(Continuous, NoFrequency, t));
929 }
930 discounts.push_back(tempRate.discountFactor(t));
931 DLOG("Add zero curve point for " << curveSpec_.name() << ": " << io::iso_date(dates.back()) << " " << fixed
932 << setprecision(4) << zeroes.back() << " / " << discounts.back());
933 }
934
935 QL_REQUIRE(dates.size() == zeroes.size(), "Date and zero vectors differ in size.");
936 QL_REQUIRE(dates.size() == discounts.size(), "Date and discount vectors differ in size.");
937
938 // Now build curve with requested conventions
940 QuantLib::ext::shared_ptr<YieldTermStructure> tempCurve =
941 zerocurve(dates, zeroes, quoteDayCounter, interpolationMethod_);
942 zeroes.clear();
943 for (Size i = 0; i < dates.size(); ++i) {
944 Rate zero = tempCurve->zeroRate(dates[i], zeroDayCounter_, Continuous);
945 zeroes.push_back(zero);
946 }
949 QuantLib::ext::shared_ptr<YieldTermStructure> tempCurve =
950 discountcurve(dates, discounts, quoteDayCounter, interpolationMethod_);
951 discounts.clear();
952 for (Size i = 0; i < dates.size(); ++i) {
953 DiscountFactor discount = tempCurve->discount(dates[i]);
954 discounts.push_back(discount);
955 }
957 } else {
958 QL_FAIL("Unknown yield curve interpolation variable.");
959 }
960}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildZeroSpreadedCurve()

void buildZeroSpreadedCurve ( )
private

Definition at line 962 of file yieldcurve.cpp.

962 {
963 QL_REQUIRE(curveSegments_.size() <= 1, "More than one zero spreaded curve "
964 "segment not supported yet.");
966 "The curve segment is not of type Zero Spread.");
967
968 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
969
970 // Fill a vector of zero spread quotes.
971 vector<QuantLib::ext::shared_ptr<ZeroQuote>> quotes;
972 QuantLib::ext::shared_ptr<ZeroSpreadedYieldCurveSegment> segment =
973 QuantLib::ext::dynamic_pointer_cast<ZeroSpreadedYieldCurveSegment>(curveSegments_[0]);
974 auto quoteIDs = segment->quotes();
975
976 Date today = Settings::instance().evaluationDate();
977 vector<Date> dates;
978 vector<Handle<Quote>> quoteHandles;
979 for (Size i = 0; i < quoteIDs.size(); ++i) {
980 if (QuantLib::ext::shared_ptr<MarketDatum> md = loader_.get(quoteIDs[i], asofDate_)) {
981 QL_REQUIRE(md->instrumentType() == MarketDatum::InstrumentType::ZERO, "Market quote not of type zero.");
982 QL_REQUIRE(md->quoteType() == MarketDatum::QuoteType::YIELD_SPREAD,
983 "Market quote not of type yield spread.");
984 QuantLib::ext::shared_ptr<ZeroQuote> zeroQuote = QuantLib::ext::dynamic_pointer_cast<ZeroQuote>(md);
985 quotes.push_back(zeroQuote);
986 dates.push_back(zeroQuote->tenorBased() ? today + zeroQuote->tenor() : zeroQuote->date());
987 quoteHandles.push_back(zeroQuote->quote());
988 }
989 }
990
991 QL_REQUIRE(!quotes.empty(),
992 "Cannot build curve with spec " << curveSpec_.name() << " because there are no spread quotes");
993
994 string referenceCurveID = segment->referenceCurveID();
995 QuantLib::ext::shared_ptr<YieldCurve> referenceCurve;
996 if (referenceCurveID != curveConfig_->curveID() && !referenceCurveID.empty()) {
997 referenceCurveID = yieldCurveKey(currency_, referenceCurveID, asofDate_);
998 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
999 it = requiredYieldCurves_.find(referenceCurveID);
1000 if (it != requiredYieldCurves_.end()) {
1001 referenceCurve = it->second;
1002 } else {
1003 QL_FAIL("The reference curve, " << referenceCurveID
1004 << ", required in the building "
1005 "of the curve, "
1006 << curveSpec_.name() << ", was not found.");
1007 }
1008 }
1009
1010 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1011 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
1012 QL_REQUIRE(convention->type() == Convention::Type::Zero, "Conventions ID does not give zero rate conventions.");
1013 QuantLib::ext::shared_ptr<ZeroRateConvention> zeroConvention = QuantLib::ext::dynamic_pointer_cast<ZeroRateConvention>(convention);
1014 DayCounter quoteDayCounter = zeroConvention->dayCounter();
1015 Compounding comp = zeroConvention->compounding();
1016 Frequency freq = zeroConvention->compoundingFrequency();
1017
1018 p_ = QuantLib::ext::shared_ptr<YieldTermStructure>(new PiecewiseZeroSpreadedTermStructure(
1019 referenceCurve->handle(), quoteHandles, dates, comp, freq, quoteDayCounter));
1020}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildBootstrappedCurve()

void buildBootstrappedCurve ( )
private

Definition at line 1210 of file yieldcurve.cpp.

1210 {
1211
1212 QL_REQUIRE(!curveSegments_.empty(), "no curve segments defined.");
1213
1214 /* Loop over segments and add helpers for each segment. */
1215
1216 DLOG("Building instrument sets for yield curve segments 0..." << curveSegments_.size() - 1);
1217
1218 std::vector<vector<QuantLib::ext::shared_ptr<RateHelper>>> instrumentsPerSegment(curveSegments_.size());
1219
1220 for (Size i = 0; i < curveSegments_.size(); ++i) {
1221 switch (curveSegments_[i]->type()) {
1223 addDeposits(curveSegments_[i], instrumentsPerSegment[i]);
1224 break;
1226 addFras(curveSegments_[i], instrumentsPerSegment[i]);
1227 break;
1229 addFutures(curveSegments_[i], instrumentsPerSegment[i]);
1230 break;
1232 addOISs(curveSegments_[i], instrumentsPerSegment[i]);
1233 break;
1235 addSwaps(curveSegments_[i], instrumentsPerSegment[i]);
1236 break;
1238 addAverageOISs(curveSegments_[i], instrumentsPerSegment[i]);
1239 break;
1241 addTenorBasisSwaps(curveSegments_[i], instrumentsPerSegment[i]);
1242 break;
1244 addTenorBasisTwoSwaps(curveSegments_[i], instrumentsPerSegment[i]);
1245 break;
1247 addBMABasisSwaps(curveSegments_[i], instrumentsPerSegment[i]);
1248 break;
1250 addFXForwards(curveSegments_[i], instrumentsPerSegment[i]);
1251 break;
1253 addCrossCcyBasisSwaps(curveSegments_[i], instrumentsPerSegment[i]);
1254 break;
1256 addCrossCcyFixFloatSwaps(curveSegments_[i], instrumentsPerSegment[i]);
1257 break;
1258 default:
1259 QL_FAIL("Yield curve segment type not recognized.");
1260 break;
1261 }
1262 }
1263
1264 /* If we have two instruments with identical pillar dates wthin a segment, remove the earlier one */
1265
1266 for (Size i = 0; i < curveSegments_.size(); ++i) {
1267 for (auto it = instrumentsPerSegment[i].begin(); it != instrumentsPerSegment[i].end();) {
1268 if (std::next(it, 1) != instrumentsPerSegment[i].end() &&
1269 (*it)->pillarDate() == (*std::next(it, 1))->pillarDate()) {
1270 DLOG("Removing instrument with pillar date "
1271 << (*it)->pillarDate() << " in segment #" << i
1272 << " because the next instrument in the same segment has the same pillar date");
1273 it = instrumentsPerSegment[i].erase(it);
1274 } else
1275 ++it;
1276 }
1277 }
1278
1279 /* Determine min and max pillar date in each segment */
1280
1281 std::vector<std::pair<Date, Date>> minMaxDatePerSegment(curveSegments_.size(),
1282 std::make_pair(Date::maxDate(), Date::minDate()));
1283 for (Size i = 0; i < curveSegments_.size(); ++i) {
1284 if (!instrumentsPerSegment[i].empty()) {
1285 auto [minIt, maxIt] =
1286 std::minmax_element(instrumentsPerSegment[i].begin(), instrumentsPerSegment[i].end(),
1287 [](const QuantLib::ext::shared_ptr<RateHelper>& h, const QuantLib::ext::shared_ptr<RateHelper>& j) {
1288 return h->pillarDate() < h->pillarDate();
1289 });
1290 minMaxDatePerSegment[i] = std::make_pair((*minIt)->pillarDate(), (*maxIt)->pillarDate());
1291 }
1292 }
1293
1294 /* If there are two segments with different priorities and overlapping instruments, remove instruments as
1295 * appropriate */
1296
1297 for (Size i = 0; i < curveSegments_.size(); ++i) {
1298 if (i < curveSegments_.size() - 1 && curveSegments_[i]->priority() > curveSegments_[i + 1]->priority()) {
1299 for (auto it = instrumentsPerSegment[i].begin(); it != instrumentsPerSegment[i].end();) {
1300 if ((*it)->pillarDate() > minMaxDatePerSegment[i + 1].first - curveSegments_[i]->minDistance()) {
1301 DLOG("Removing instrument in segment #"
1302 << i << " (priority " << curveSegments_[i]->priority() << ") because its pillar date "
1303 << (*it)->pillarDate() << " > " << minMaxDatePerSegment[i + 1].first
1304 << " (min pillar date in segment #" << (i + 1) << ", priority "
1305 << curveSegments_[i + 1]->priority() << ") minus " << curveSegments_[i]->minDistance()
1306 << " (min distance in segment #" << i << ")");
1307 it = instrumentsPerSegment[i].erase(it);
1308 } else
1309 ++it;
1310 }
1311 }
1312 if (i > 0 && curveSegments_[i - 1]->priority() < curveSegments_[i]->priority()) {
1313 for (auto it = instrumentsPerSegment[i].begin(); it != instrumentsPerSegment[i].end();) {
1314 if ((*it)->pillarDate() < minMaxDatePerSegment[i - 1].second + curveSegments_[i - 1]->minDistance()) {
1315 DLOG("Removing instrument in segment #"
1316 << i << " (priority " << curveSegments_[i]->priority() << ") because its pillar date "
1317 << (*it)->pillarDate() << " < " << minMaxDatePerSegment[i - 1].second
1318 << " (max pillar date in segment #" << (i - 1) << ", priority "
1319 << curveSegments_[i - 1]->priority() << ") plus " << curveSegments_[i - 1]->minDistance()
1320 << " (min distance in segment #" << (i - 1) << ")");
1321 it = instrumentsPerSegment[i].erase(it);
1322 } else
1323 ++it;
1324 }
1325 }
1326 }
1327
1328 /* Set mixed interpolation size using the specified cutoff for the number of segments */
1329
1331 for (Size i = 0; i < curveConfig_->mixedInterpolationCutoff(); ++i)
1332 mixedInterpolationSize_ += instrumentsPerSegment[i].size();
1333
1334 /* Now put all remaining instruments into a single vector. */
1335
1336 vector<QuantLib::ext::shared_ptr<RateHelper>> instruments;
1337 for (Size i = 0; i < curveSegments_.size(); ++i) {
1338 instruments.insert(instruments.end(), instrumentsPerSegment[i].begin(), instrumentsPerSegment[i].end());
1339 DLOG("Adding " << instrumentsPerSegment[i].size() << " instruments for segment #" << i);
1340 }
1341
1342 /* Build the bootstrapped curve from the instruments. */
1343
1344 DLOG("Bootstrapping with " << instruments.size() << " instruments");
1345 QL_REQUIRE(instruments.size() > 0,
1346 "Empty instrument list for date = " << io::iso_date(asofDate_) << " and curve = " << curveSpec_.name());
1347 p_ = piecewisecurve(instruments);
1348}
void addDeposits(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addCrossCcyBasisSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addTenorBasisSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addOISs(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addFutures(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addBMABasisSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addFras(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addTenorBasisTwoSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addFXForwards(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addCrossCcyFixFloatSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
QuantLib::ext::shared_ptr< YieldTermStructure > piecewisecurve(vector< QuantLib::ext::shared_ptr< RateHelper > > instruments)
Definition: yieldcurve.cpp:390
void addAverageOISs(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
Size size(const ValueType &v)
Definition: value.cpp:145
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildDiscountRatioCurve()

void buildDiscountRatioCurve ( )
private

Build a yield curve that uses QuantExt::DiscountRatioModifiedCurve.

Definition at line 1350 of file yieldcurve.cpp.

1350 {
1351 QL_REQUIRE(curveSegments_.size() == 1, "A discount ratio curve must contain exactly one segment");
1353 "The curve segment is not of type 'DiscountRatio'.");
1354
1355 QuantLib::ext::shared_ptr<DiscountRatioYieldCurveSegment> segment =
1356 QuantLib::ext::dynamic_pointer_cast<DiscountRatioYieldCurveSegment>(curveSegments_[0]);
1357
1358 // Find the underlying curves in the reference curves
1359 QuantLib::ext::shared_ptr<YieldCurve> baseCurve = getYieldCurve(segment->baseCurveCurrency(), segment->baseCurveId());
1360 QL_REQUIRE(baseCurve, "The base curve '" << segment->baseCurveId() << "' cannot be empty");
1361
1362 QuantLib::ext::shared_ptr<YieldCurve> numCurve =
1363 getYieldCurve(segment->numeratorCurveCurrency(), segment->numeratorCurveId());
1364 QL_REQUIRE(numCurve, "The numerator curve '" << segment->numeratorCurveId() << "' cannot be empty");
1365
1366 QuantLib::ext::shared_ptr<YieldCurve> denCurve =
1367 getYieldCurve(segment->denominatorCurveCurrency(), segment->denominatorCurveId());
1368 QL_REQUIRE(denCurve, "The denominator curve '" << segment->denominatorCurveId() << "' cannot be empty");
1369
1370 p_ = QuantLib::ext::make_shared<DiscountRatioModifiedCurve>(baseCurve->handle(), numCurve->handle(), denCurve->handle());
1371}
QuantLib::ext::shared_ptr< YieldCurve > getYieldCurve(const std::string &ccy, const std::string &id) const
Return the yield curve with the given id from the requiredYieldCurves_ map.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildFittedBondCurve()

void buildFittedBondCurve ( )
private

Build a yield curve that uses QuantLib::FittedBondCurve.

Definition at line 1386 of file yieldcurve.cpp.

1386 {
1387 QL_REQUIRE(curveSegments_.size() == 1, "FittedBond curve must contain exactly one segment.");
1388 QL_REQUIRE(curveSegments_[0]->type() == YieldCurveSegment::Type::FittedBond,
1389 "The curve segment is not of type 'FittedBond'.");
1390
1391 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1392
1393 QuantLib::ext::shared_ptr<FittedBondYieldCurveSegment> curveSegment =
1394 QuantLib::ext::dynamic_pointer_cast<FittedBondYieldCurveSegment>(curveSegments_[0]);
1395 QL_REQUIRE(curveSegment != nullptr, "could not cast to FittedBondYieldCurveSegment, this is unexpected");
1396
1397 // init calibration info for this curve
1398
1399 auto calInfo = QuantLib::ext::make_shared<FittedBondCurveCalibrationInfo>();
1401 calInfo->dayCounter = zeroDayCounter_.name();
1402 calInfo->currency = currency_.code();
1403 }
1404
1405 // build vector of bond helpers
1406
1407 auto quoteIDs = curveSegment->quotes();
1408 std::vector<QuantLib::ext::shared_ptr<QuantLib::Bond>> bonds;
1409 std::vector<QuantLib::ext::shared_ptr<BondHelper>> helpers;
1410 std::vector<Real> marketPrices, marketYields;
1411 std::vector<std::string> securityIDs;
1412 std::vector<Date> securityMaturityDates;
1413 Date lastMaturity = Date::minDate(), firstMaturity = Date::maxDate();
1414
1415 // not really relevant, we just need a working engine configuration so that the bond can be built
1416 // the pricing engine here is _not_ used during the curve fitting, for this a local engine is
1417 // set up within FittedBondDiscountCurve
1418 auto engineData = QuantLib::ext::make_shared<EngineData>();
1419 engineData->model("Bond") = "DiscountedCashflows";
1420 engineData->engine("Bond") = "DiscountingRiskyBondEngine";
1421 engineData->engineParameters("Bond") = {{"TimestepPeriod", "6M"}};
1422
1423 std::map<std::string, Handle<YieldTermStructure>> iborCurveMapping;
1424 for (auto const& c : curveSegment->iborIndexCurves()) {
1425 auto index = parseIborIndex(c.first);
1426 auto key = yieldCurveKey(index->currency(), c.second, asofDate_);
1427 auto y = requiredYieldCurves_.find(key);
1428 QL_REQUIRE(y != requiredYieldCurves_.end(), "required yield curve '" << key << "' for iborIndex '" << c.first
1429 << "' not provided for fitted bond curve");
1430 iborCurveMapping[c.first] = y->second->handle();
1431 }
1432
1433 auto engineFactory =
1434 QuantLib::ext::make_shared<EngineFactory>(engineData, QuantLib::ext::make_shared<FittedBondCurveHelperMarket>(iborCurveMapping),
1435 std::map<MarketContext, string>(), referenceData_, iborFallbackConfig_);
1436
1437 for (Size i = 0; i < quoteIDs.size(); ++i) {
1438 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(quoteIDs[i], asofDate_);
1439 if (marketQuote) {
1440 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::BOND &&
1441 marketQuote->quoteType() == MarketDatum::QuoteType::PRICE,
1442 "Market quote not of type Bond / Price.");
1443 QuantLib::ext::shared_ptr<BondPriceQuote> bondQuote = QuantLib::ext::dynamic_pointer_cast<BondPriceQuote>(marketQuote);
1444 QL_REQUIRE(bondQuote, "market quote has type bond quote, but can not be casted, this is unexpected.");
1445 auto m = [](Real x) { return 100.0 * x; };
1446 Handle<Quote> rescaledBondQuote(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(bondQuote->quote(), m));
1447 string securityID = bondQuote->securityID();
1448
1449 QL_REQUIRE(referenceData_ != nullptr, "reference data required to build fitted bond curve");
1450 auto res = BondFactory::instance().build(engineFactory, referenceData_, securityID);
1451 auto qlInstr = res.bond;
1452 // skip bonds with settlement date <= curve reference date or which are otherwise non-tradeable
1453 if (qlInstr->settlementDate() > asofDate_ && QuantLib::BondFunctions::isTradable(*qlInstr)) {
1454 bonds.push_back(qlInstr);
1455 helpers.push_back(QuantLib::ext::make_shared<BondHelper>(rescaledBondQuote, qlInstr));
1456 Date thisMaturity = qlInstr->maturityDate();
1457 lastMaturity = std::max(lastMaturity, thisMaturity);
1458 firstMaturity = std::min(firstMaturity, thisMaturity);
1459 Real inflationFactor = res.inflationFactor();
1460 Real marketYield = qlInstr->yield(rescaledBondQuote->value() * inflationFactor,
1461 ActualActual(ActualActual::ISDA),
1462 Continuous, NoFrequency);
1463 DLOG("added bond " << securityID << ", maturity = " << QuantLib::io::iso_date(thisMaturity)
1464 << ", clean price = " << rescaledBondQuote->value() * inflationFactor
1465 << ", yield (cont,act/act) = " << marketYield);
1466 marketPrices.push_back(bondQuote->quote()->value() * inflationFactor);
1467 securityIDs.push_back(securityID);
1468 marketYields.push_back(marketYield);
1469 securityMaturityDates.push_back(thisMaturity);
1470 } else {
1471 DLOG("skipped bond " << securityID << " with settlement date "
1472 << QuantLib::io::iso_date(qlInstr->settlementDate()) << ", isTradable = "
1473 << std::boolalpha << QuantLib::BondFunctions::isTradable(*qlInstr));
1474 }
1475 }
1476 }
1477
1478 calInfo->securities = securityIDs;
1479 calInfo->securityMaturityDates = securityMaturityDates;
1480 calInfo->marketPrices = marketPrices;
1481 calInfo->marketYields = marketYields;
1482
1483 // fit bond curve to helpers
1484
1485 QL_REQUIRE(helpers.size() >= 1, "no bonds for fitting bond curve");
1486 DLOG("Fitting bond curve with " << helpers.size() << " bonds.");
1487
1488 Real minCutoffTime = 0.0, maxCutoffTime = QL_MAX_REAL;
1489 if (curveSegment->extrapolateFlat()) {
1490 minCutoffTime = zeroDayCounter_.yearFraction(asofDate_, firstMaturity);
1491 maxCutoffTime = zeroDayCounter_.yearFraction(asofDate_, lastMaturity);
1492 DLOG("extrapolate flat outside " << minCutoffTime << "," << maxCutoffTime);
1493 }
1494
1495 QuantLib::ext::shared_ptr<FittedBondDiscountCurve::FittingMethod> method;
1496 switch (interpolationMethod_) {
1498 method = QuantLib::ext::make_shared<ExponentialSplinesFitting>(true, Array(), ext::shared_ptr<OptimizationMethod>(),
1499 Array(), minCutoffTime, maxCutoffTime);
1500 calInfo->fittingMethod = "ExponentialSplines";
1501 break;
1503 method = QuantLib::ext::make_shared<NelsonSiegelFitting>(Array(), ext::shared_ptr<OptimizationMethod>(), Array(),
1504 minCutoffTime, maxCutoffTime);
1505 calInfo->fittingMethod = "NelsonSiegel";
1506 break;
1508 method = QuantLib::ext::make_shared<SvenssonFitting>(Array(), ext::shared_ptr<OptimizationMethod>(), Array(),
1509 minCutoffTime, maxCutoffTime);
1510 calInfo->fittingMethod = "Svensson";
1511 break;
1512 default:
1513 QL_FAIL("unknown fitting method");
1514 }
1515
1516 QuantLib::ext::shared_ptr<FittedBondDiscountCurve> tmp, current;
1517 Real minError = QL_MAX_REAL;
1518 HaltonRsg halton(method->size(), 42);
1519 // TODO randomised optimisation seeds are only implemented for NelsonSiegel so far
1520 Size trials = 1;
1522 trials = curveConfig_->bootstrapConfig().maxAttempts();
1523 } else {
1524 if (curveConfig_->bootstrapConfig().maxAttempts() > 1) {
1525 WLOG("randomised optimisation seeds not implemented for given interpolation method");
1526 }
1527 }
1528 for (Size i = 0; i < trials; ++i) {
1529 Array guess;
1530 // first guess is the default guess (empty array, will be set to a zero vector in
1531 // FittedBondDiscountCurve::calculate())
1532 if (i == 0) {
1534 // first guess will be based on the last bond yield and first bond yield
1535 guess = Array(4);
1536 Integer maxMaturity = static_cast<Integer>(
1537 std::distance(securityMaturityDates.begin(),
1538 std::max_element(securityMaturityDates.begin(), securityMaturityDates.end())));
1539 Integer minMaturity = static_cast<Integer>(
1540 std::distance(securityMaturityDates.begin(),
1541 std::min_element(securityMaturityDates.begin(), securityMaturityDates.end())));
1542 guess[0] = marketYields[maxMaturity]; // long term yield
1543 guess[1] = marketYields[minMaturity] - guess[0]; // short term component
1544 guess[2] = 0.0;
1545 guess[3] = 5.0;
1546 DLOG("using smart NelsonSiegel guess for trial #" << (i + 1) << ": " << guess);
1547 }
1548 } else {
1549 auto seq = halton.nextSequence();
1550 guess = Array(seq.value.begin(), seq.value.end());
1552 guess[0] = guess[0] * 0.10 - 0.05; // long term yield
1553 guess[1] = guess[1] * 0.10 - 0.05; // short term component
1554 guess[2] = guess[2] * 0.10 - 0.05; // medium term component
1555 guess[3] = guess[3] * 5.0; // decay factor
1556 DLOG("using random NelsonSiegel guess for trial #" << (i + 1) << ": " << guess);
1557 } else {
1558 QL_FAIL("randomised optimisation seed not implemented");
1559 }
1560 }
1561 current = QuantLib::ext::make_shared<FittedBondDiscountCurve>(asofDate_, helpers, zeroDayCounter_, *method, 1.0e-10,
1562 10000, guess);
1563 Real cost = std::sqrt(current->fitResults().minimumCostValue());
1564 if (cost < minError) {
1565 minError = cost;
1566 tmp = current;
1567 }
1568 DLOG("calibration trial #" << (i + 1) << " out of " << trials << ": cost = " << cost
1569 << ", best so far = " << minError);
1570 if (cost < curveConfig_->bootstrapConfig().accuracy()) {
1571 DLOG("reached desired accuracy (" << curveConfig_->bootstrapConfig().accuracy()
1572 << ") - do not attempt more calibrations");
1573 break;
1574 }
1575 }
1576 QL_REQUIRE(tmp, "no best solution found for fitted bond curve - this is unexpected.");
1577
1578 if (Norm2(tmp->fitResults().solution()) < 1.0e-4) {
1579 WLOG("Fit solution is close to 0. The curve fitting should be reviewed.");
1580 }
1581
1582 DLOG("Fitted Bond Curve Summary:");
1583 DLOG(" solution: " << tmp->fitResults().solution());
1584 DLOG(" iterations: " << tmp->fitResults().numberOfIterations());
1585 DLOG(" cost value: " << minError);
1586
1587 std::vector<Real> modelPrices, modelYields;
1588 auto engine = QuantLib::ext::make_shared<DiscountingBondEngine>(Handle<YieldTermStructure>(tmp));
1589 for (Size i = 0; i < bonds.size(); ++i) {
1590 bonds[i]->setPricingEngine(engine);
1591 modelPrices.push_back(bonds[i]->cleanPrice() / 100.0);
1592 modelYields.push_back(bonds[i]->yield(bonds[i]->cleanPrice(), ActualActual(ActualActual::ISDA), Continuous, NoFrequency));
1593 DLOG("bond " << securityIDs[i] << ", model clean price = " << modelPrices.back()
1594 << ", yield (cont,actact) = " << modelYields.back() << ", NPV = " << bonds[i]->NPV());
1595 }
1596
1597 Real tolerance = curveConfig_->bootstrapConfig().globalAccuracy() == Null<Real>()
1598 ? curveConfig_->bootstrapConfig().accuracy()
1599 : curveConfig_->bootstrapConfig().globalAccuracy();
1600 QL_REQUIRE(curveConfig_->bootstrapConfig().dontThrow() || minError < tolerance,
1601 "Fitted Bond Curve cost value (" << minError << ") exceeds tolerance (" << tolerance << ")");
1602
1603 if (extrapolation_)
1604 tmp->enableExtrapolation();
1605
1606 p_ = tmp;
1607
1608 Array solution = tmp->fitResults().solution();
1609
1611 calInfo->modelPrices = modelPrices;
1612 calInfo->modelYields = modelYields;
1613 calInfo->tolerance = tolerance;
1614 calInfo->costValue = minError;
1615 calInfo->solution = std::vector<double>(solution.begin(), solution.end());
1616 calInfo->iterations = static_cast<int>(tmp->fitResults().numberOfIterations());
1617 calibrationInfo_ = calInfo;
1618 }
1619}
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h)
Convert std::string to QuantLib::IborIndex.
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildWeightedAverageCurve()

void buildWeightedAverageCurve ( )
private

Build a yield curve that uses QuantExt::WeightedYieldTermStructure.

Definition at line 1022 of file yieldcurve.cpp.

1022 {
1023 QL_REQUIRE(curveSegments_.size() == 1,
1024 "One segment required for weighted average curve, got " << curveSegments_.size());
1026 "The curve segment is not of type Weighted Average.");
1027 auto segment = QuantLib::ext::dynamic_pointer_cast<WeightedAverageYieldCurveSegment>(curveSegments_[0]);
1028 QL_REQUIRE(segment != nullptr, "expected WeightedAverageYieldCurveSegment, this is unexpected");
1029 auto it1 = requiredYieldCurves_.find(yieldCurveKey(currency_, segment->referenceCurveID1(), asofDate_));
1030 auto it2 = requiredYieldCurves_.find(yieldCurveKey(currency_, segment->referenceCurveID2(), asofDate_));
1031 QL_REQUIRE(it1 != requiredYieldCurves_.end(), "Could not find reference curve1: " << segment->referenceCurveID1());
1032 QL_REQUIRE(it2 != requiredYieldCurves_.end(), "Could not find reference curve2: " << segment->referenceCurveID2());
1033 p_ = QuantLib::ext::make_shared<WeightedYieldTermStructure>(it1->second->handle(), it2->second->handle(),
1034 segment->weight1(), segment->weight2());
1035}
+ Here is the caller graph for this function:

◆ buildYieldPlusDefaultCurve()

void buildYieldPlusDefaultCurve ( )
private

Build a yield curve that uses QuantExt::YieldPlusDefaultYieldTermStructure.

Definition at line 1037 of file yieldcurve.cpp.

1037 {
1038 QL_REQUIRE(curveSegments_.size() == 1,
1039 "One segment required for yield plus default curve, got " << curveSegments_.size());
1041 "The curve segment is not of type Yield Plus Default.");
1042 auto segment = QuantLib::ext::dynamic_pointer_cast<YieldPlusDefaultYieldCurveSegment>(curveSegments_[0]);
1043 QL_REQUIRE(segment != nullptr, "expected YieldPlusDefaultCurveSegment, this is unexpected");
1044 auto it = requiredYieldCurves_.find(yieldCurveKey(currency_, segment->referenceCurveID(), asofDate_));
1045 QL_REQUIRE(it != requiredYieldCurves_.end(), "Could not find reference curve: " << segment->referenceCurveID());
1046 std::vector<Handle<DefaultProbabilityTermStructure>> defaultCurves;
1047 std::vector<Handle<Quote>> recRates;
1048 for (Size i = 0; i < segment->defaultCurveIDs().size(); ++i) {
1049 auto it = requiredDefaultCurves_.find(segment->defaultCurveIDs()[i]);
1050 QL_REQUIRE(it != requiredDefaultCurves_.end(),
1051 "Could not find default curve: " << segment->defaultCurveIDs()[i]);
1052 defaultCurves.push_back(Handle<DefaultProbabilityTermStructure>(it->second->creditCurve()->curve()));
1053 recRates.push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(it->second->recoveryRate())));
1054 }
1055 p_ = QuantLib::ext::make_shared<YieldPlusDefaultYieldTermStructure>(it->second->handle(), defaultCurves, recRates,
1056 segment->weights());
1057}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildIborFallbackCurve()

void buildIborFallbackCurve ( )
private

Build a yield curve that uses QuantExt::IborFallbackCurve.

Definition at line 1059 of file yieldcurve.cpp.

1059 {
1060 QL_REQUIRE(curveSegments_.size() == 1,
1061 "One segment required for ibor fallback curve, got " << curveSegments_.size());
1063 "The curve segment is not of type Ibor Fallback");
1064 auto segment = QuantLib::ext::dynamic_pointer_cast<IborFallbackCurveSegment>(curveSegments_[0]);
1065 QL_REQUIRE(segment != nullptr, "expected IborFallbackCurve, internal error");
1066 auto it = requiredYieldCurves_.find(segment->rfrCurve());
1067 QL_REQUIRE(it != requiredYieldCurves_.end(), "Could not find rfr curve: '" << segment->rfrCurve() << "')");
1068 QL_REQUIRE(
1069 (segment->rfrIndex() && segment->spread()) || iborFallbackConfig_.isIndexReplaced(segment->iborIndex()),
1070 "buildIborFallbackCurve(): ibor index '"
1071 << segment->iborIndex()
1072 << "' must be specified in ibor fallback config, if RfrIndex or Spread is not specified in curve config");
1073 std::string rfrIndexName = segment->rfrIndex() ? *segment->rfrIndex() : iborFallbackConfig_.fallbackData(segment->iborIndex()).rfrIndex;
1074 Real spread = segment->spread() ? *segment->spread() : iborFallbackConfig_.fallbackData(segment->iborIndex()).spread;
1075 // we don't support convention based indices here, this might change with ore ticket 1758
1076 Handle<YieldTermStructure> dummyCurve(QuantLib::ext::make_shared<FlatForward>(asofDate_, 0.0, zeroDayCounter_));
1077 auto originalIndex = parseIborIndex(segment->iborIndex(), dummyCurve);
1078 auto rfrIndex = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(parseIborIndex(rfrIndexName, it->second->handle()));
1079 QL_REQUIRE(rfrIndex, "buidlIborFallbackCurve(): rfr index '"
1080 << rfrIndexName << "' could not be cast to OvernightIndex, is this index name correct?");
1081 DLOG("building ibor fallback curve for '" << segment->iborIndex() << "' with rfrIndex='" << rfrIndexName
1082 << "' and spread=" << spread);
1083 if (auto on = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(originalIndex)) {
1084 p_ = QuantLib::ext::make_shared<OvernightFallbackCurve>(on, rfrIndex, spread, Date::minDate());
1085 } else {
1086 p_ = QuantLib::ext::make_shared<IborFallbackCurve>(originalIndex, rfrIndex, spread, Date::minDate());
1087 }
1088}
const FallbackData & fallbackData(const string &iborIndex) const
bool isIndexReplaced(const string &iborIndex, const QuantLib::Date &asof=QuantLib::Date::maxDate()) const
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildBondYieldShiftedCurve()

void buildBondYieldShiftedCurve ( )
private

Build a yield curve that uses QuantExt::bondYieldShiftedCurve.

Definition at line 1621 of file yieldcurve.cpp.

1621 {
1622 QL_REQUIRE(curveSegments_.size() == 1,
1623 "One segment required for bond yield shifted curve, got " << curveSegments_.size());
1625 "The curve segment is not of type Bond Yield Shifted.");
1626 auto segment = QuantLib::ext::dynamic_pointer_cast<BondYieldShiftedYieldCurveSegment>(curveSegments_[0]);
1627 QL_REQUIRE(segment != nullptr, "expected BondYieldShiftedYieldCurveSegment, this is unexpected");
1628 auto it = requiredYieldCurves_.find(yieldCurveKey(currency_, segment->referenceCurveID(), asofDate_));
1629 QL_REQUIRE(it != requiredYieldCurves_.end(), "Could not find reference curve: " << segment->referenceCurveID());
1630
1631 //prepare parameters
1632 auto quoteIDs = segment->quotes();
1633 QuantLib::ext::shared_ptr<QuantLib::Bond> bond;
1634 string securityID;
1635 Date securityMaturityDate;
1636 Rate bondYield = Null<Real>();
1637 Real thisDuration = Null<Real>();
1638
1639 auto engineData = QuantLib::ext::make_shared<EngineData>();
1640 engineData->model("Bond") = "DiscountedCashflows";
1641 engineData->engine("Bond") = "DiscountingRiskyBondEngine";
1642 engineData->engineParameters("Bond") = {{"TimestepPeriod", "3M"}};
1643
1644 // needed to link the ibors in case bond is a floater
1645 std::map<std::string, Handle<YieldTermStructure>> iborCurveMapping;
1646 for (auto const& c : segment->iborIndexCurves()) {
1647 auto index = parseIborIndex(c.first);
1648 auto key = yieldCurveKey(index->currency(), c.second, asofDate_);
1649 auto y = requiredYieldCurves_.find(key);
1650 QL_REQUIRE(y != requiredYieldCurves_.end(), "required ibor curve '" << key << "' for iborIndex '" << c.first
1651 << "' not provided");
1652 iborCurveMapping[c.first] = y->second->handle();
1653 }
1654
1655 auto engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData,
1656 QuantLib::ext::make_shared<FittedBondCurveHelperMarket>(iborCurveMapping),
1657 std::map<MarketContext, string>(),
1660
1661 QL_REQUIRE(quoteIDs.size() > 0, "at least one bond for shifting of the reference curve required.");
1662
1663 std::vector<Real> bondYields, bondDurations;
1664
1665 for (Size b = 0; b < quoteIDs.size(); ++b) {
1666
1667 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(quoteIDs[b], asofDate_);
1668
1669 QL_REQUIRE(marketQuote != nullptr,"no quotes for the bond " << quoteIDs[b].first << " found. this is unexpected");
1670
1671 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::BOND && marketQuote->quoteType() == MarketDatum::QuoteType::PRICE,
1672 "Market quote not of type Bond / Price.");
1673 QuantLib::ext::shared_ptr<BondPriceQuote> bondQuote = QuantLib::ext::dynamic_pointer_cast<BondPriceQuote>(marketQuote);
1674 QL_REQUIRE(bondQuote, "market quote has type bond quote, but can not be casted, this is unexpected.");
1675 auto m = [bondQuote](Real x) { return x * 100.0; };
1676 Handle<Quote> rescaledBondQuote(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(bondQuote->quote(), m));
1677
1678 securityID = bondQuote->securityID();
1679 QL_REQUIRE(referenceData_ != nullptr, "reference data required to build bond yield shifted curve");
1680
1681 auto res = BondFactory::instance().build(engineFactory, referenceData_, securityID);
1682 auto qlInstr = res.bond;
1683 auto inflationQuoteFactor = res.inflationFactor();
1684
1685 // skip bonds with settlement date <= curve reference date or which are otherwise non-tradeable
1686 if (qlInstr->settlementDate() > asofDate_ && QuantLib::BondFunctions::isTradable(*qlInstr)) {
1687
1688 Date thisMaturity = qlInstr->maturityDate();
1689 bondYield = qlInstr->yield(rescaledBondQuote->value() * inflationQuoteFactor,
1690 ActualActual(ActualActual::ISDA), Continuous, NoFrequency);
1691
1692 thisDuration = QuantLib::BondFunctions::duration(*qlInstr,InterestRate(bondYield,ActualActual(ActualActual::ISDA),Continuous,NoFrequency)
1693 ,Duration::Modified,asofDate_);
1694
1695 DLOG("found bond " << securityID << ", maturity = " << QuantLib::io::iso_date(thisMaturity)
1696 << ", clean price = " << rescaledBondQuote->value() * inflationQuoteFactor
1697 << ", yield (cont,act/act) = " << bondYield
1698 << ", duration = " << thisDuration);
1699
1700 bondYields.push_back(bondYield);
1701 bondDurations.push_back(thisDuration);
1702
1703 DLOG("calculated duration of the bond " << securityID << " is equal to " << thisDuration)
1704
1705 } else {
1706
1707 DLOG("Skipping bond " << securityID
1708 << ", with settlement date " << QuantLib::io::iso_date(qlInstr->settlementDate())
1709 << ", isTradable = " << std::boolalpha << QuantLib::BondFunctions::isTradable(*qlInstr));
1710 }
1711
1712 }
1713
1714 p_ = QuantLib::ext::make_shared<BondYieldShiftedCurveTermStructure>(it->second->handle(), bondYields, bondDurations);
1715
1716}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getYieldCurve()

QuantLib::ext::shared_ptr< YieldCurve > getYieldCurve ( const std::string &  ccy,
const std::string &  id 
) const
private

Return the yield curve with the given id from the requiredYieldCurves_ map.

Definition at line 1373 of file yieldcurve.cpp.

1373 {
1374 if (id != curveConfig_->curveID() && !id.empty()) {
1375 string idLookup = yieldCurveKey(parseCurrency(ccy), id, asofDate_);
1376 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::const_iterator it = requiredYieldCurves_.find(idLookup);
1377 QL_REQUIRE(it != requiredYieldCurves_.end(), "The curve '" << idLookup
1378 << "' required in the building of the curve '"
1379 << curveSpec_.name() << "' was not found.");
1380 return it->second;
1381 } else {
1382 return nullptr;
1383 }
1384}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ piecewisecurve()

QuantLib::ext::shared_ptr< YieldTermStructure > piecewisecurve ( vector< QuantLib::ext::shared_ptr< RateHelper > >  instruments)
private

Definition at line 390 of file yieldcurve.cpp.

390 {
391
392 // Ensure that the instruments are sorted. This is done in IterativeBootstrap, but we need
393 // a sorted instruments vector in the code here as well.
394 std::sort(instruments.begin(), instruments.end(), QuantLib::detail::BootstrapHelperSorter());
395
396 // Get configuration values for bootstrap
397 Real accuracy = curveConfig_->bootstrapConfig().accuracy();
398 Real globalAccuracy = curveConfig_->bootstrapConfig().globalAccuracy();
399 bool dontThrow = curveConfig_->bootstrapConfig().dontThrow();
400 Size maxAttempts = curveConfig_->bootstrapConfig().maxAttempts();
401 Real maxFactor = curveConfig_->bootstrapConfig().maxFactor();
402 Real minFactor = curveConfig_->bootstrapConfig().minFactor();
403 Size dontThrowSteps = curveConfig_->bootstrapConfig().dontThrowSteps();
404
405 QuantLib::ext::shared_ptr<YieldTermStructure> yieldts;
406 switch (interpolationVariable_) {
408 switch (interpolationMethod_) {
410 typedef PiecewiseYieldCurve<ZeroYield, Linear, QuantExt::IterativeBootstrap> my_curve;
411 yieldts = QuantLib::ext::make_shared<my_curve>(
412 asofDate_, instruments, zeroDayCounter_, Linear(),
413 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
414 minFactor, dontThrowSteps));
415 } break;
417 typedef PiecewiseYieldCurve<ZeroYield, LogLinear, QuantExt::IterativeBootstrap> my_curve;
418 yieldts = QuantLib::ext::make_shared<my_curve>(
419 asofDate_, instruments, zeroDayCounter_, LogLinear(),
420 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
421 minFactor, dontThrowSteps));
422 } break;
424 typedef PiecewiseYieldCurve<ZeroYield, Cubic, QuantExt::IterativeBootstrap> my_curve;
425 yieldts = QuantLib::ext::make_shared<my_curve>(
426 asofDate_, instruments, zeroDayCounter_, Cubic(CubicInterpolation::Kruger, true),
427 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
428 minFactor, dontThrowSteps));
429 } break;
431 typedef PiecewiseYieldCurve<ZeroYield, Cubic, QuantExt::IterativeBootstrap> my_curve;
432 yieldts = QuantLib::ext::make_shared<my_curve>(
433 asofDate_, instruments, zeroDayCounter_,
434 Cubic(CubicInterpolation::Kruger, true, CubicInterpolation::SecondDerivative, 0.0,
435 CubicInterpolation::FirstDerivative),
436 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
437 minFactor, dontThrowSteps));
438 } break;
440 typedef PiecewiseYieldCurve<ZeroYield, ConvexMonotone, QuantExt::IterativeBootstrap> my_curve;
441 yieldts = QuantLib::ext::make_shared<my_curve>(
443 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
444 minFactor, dontThrowSteps));
445 } break;
447 typedef PiecewiseYieldCurve<ZeroYield, Cubic, QuantExt::IterativeBootstrap> my_curve;
448 yieldts = QuantLib::ext::make_shared<my_curve>(
449 asofDate_, instruments, zeroDayCounter_, Cubic(CubicInterpolation::Parabolic),
450 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
451 minFactor, dontThrowSteps));
452 } break;
454 typedef PiecewiseYieldCurve<ZeroYield, Cubic, QuantExt::IterativeBootstrap> my_curve;
455 yieldts = QuantLib::ext::make_shared<my_curve>(
456 asofDate_, instruments, zeroDayCounter_,
457 Cubic(CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
458 CubicInterpolation::SecondDerivative, 0.0),
459 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
460 dontThrowSteps));
461 } break;
463 typedef PiecewiseYieldCurve<ZeroYield, QuantExt::Quadratic, QuantExt::IterativeBootstrap> my_curve;
464 yieldts =
465 QuantLib::ext::make_shared<my_curve>(
466 asofDate_, instruments, zeroDayCounter_, QuantExt::Quadratic(1, 0, 1, 0, 1),
467 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
468 minFactor, dontThrowSteps));
469 } break;
471 typedef PiecewiseYieldCurve<ZeroYield, QuantExt::LogQuadratic, QuantExt::IterativeBootstrap> my_curve;
472 yieldts = QuantLib::ext::make_shared<my_curve>(
473 asofDate_, instruments, zeroDayCounter_, QuantExt::LogQuadratic(1, 0, -1, 0, 1),
474 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
475 minFactor, dontThrowSteps));
476 } break;
478 typedef PiecewiseYieldCurve<ZeroYield, LogCubic, QuantExt::IterativeBootstrap> my_curve;
479 yieldts = QuantLib::ext::make_shared<my_curve>(
480 asofDate_, instruments, zeroDayCounter_, LogCubic(CubicInterpolation::Kruger, true),
481 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
482 minFactor, dontThrowSteps));
483 } break;
485 typedef PiecewiseYieldCurve<ZeroYield, LogCubic, QuantExt::IterativeBootstrap> my_curve;
486 yieldts = QuantLib::ext::make_shared<my_curve>(
487 asofDate_, instruments, zeroDayCounter_,
488 LogCubic(CubicInterpolation::Kruger, true, CubicInterpolation::SecondDerivative, 0.0,
489 CubicInterpolation::FirstDerivative),
490 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
491 dontThrowSteps));
492 } break;
494 typedef PiecewiseYieldCurve<ZeroYield, LogCubic, QuantExt::IterativeBootstrap> my_curve;
495 yieldts = QuantLib::ext::make_shared<my_curve>(
496 asofDate_, instruments, zeroDayCounter_,
497 LogCubic(CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
498 CubicInterpolation::SecondDerivative, 0.0),
499 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
500 dontThrowSteps));
501 } break;
503 typedef PiecewiseYieldCurve<ZeroYield, DefaultLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
504 yieldts = QuantLib::ext::make_shared<my_curve>(
506 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
507 minFactor, dontThrowSteps));
508 } break;
510 typedef PiecewiseYieldCurve<ZeroYield, MonotonicLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
511 yieldts = QuantLib::ext::make_shared<my_curve>(
513 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
514 minFactor, dontThrowSteps));
515 } break;
517 typedef PiecewiseYieldCurve<ZeroYield, KrugerLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
518 yieldts = QuantLib::ext::make_shared<my_curve>(
520 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
521 minFactor, dontThrowSteps));
522 } break;
524 typedef PiecewiseYieldCurve<ZeroYield, LogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
525 yieldts = QuantLib::ext::make_shared<my_curve>(
526 asofDate_, instruments, zeroDayCounter_,
527 LogMixedLinearCubic(mixedInterpolationSize_, MixedInterpolation::ShareRanges,
528 CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
529 CubicInterpolation::SecondDerivative, 0.0),
530 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
531 minFactor, dontThrowSteps));
532 } break;
533 default:
534 QL_FAIL("Interpolation method '" << interpolationMethod_ << "' not recognised.");
535 }
536 break;
538 switch (interpolationMethod_) {
540 typedef PiecewiseYieldCurve<Discount, Linear, QuantExt::IterativeBootstrap> my_curve;
541 yieldts = QuantLib::ext::make_shared<my_curve>(
542 asofDate_, instruments, zeroDayCounter_, Linear(),
543 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
544 minFactor, dontThrowSteps));
545 } break;
547 typedef PiecewiseYieldCurve<Discount, LogLinear, QuantExt::IterativeBootstrap> my_curve;
548 yieldts = QuantLib::ext::make_shared<my_curve>(
549 asofDate_, instruments, zeroDayCounter_, LogLinear(),
550 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
551 minFactor, dontThrowSteps));
552 } break;
554 typedef PiecewiseYieldCurve<Discount, Cubic, QuantExt::IterativeBootstrap> my_curve;
555 yieldts = QuantLib::ext::make_shared<my_curve>(
556 asofDate_, instruments, zeroDayCounter_, Cubic(CubicInterpolation::Kruger, true),
557 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
558 minFactor, dontThrowSteps));
559 } break;
561 typedef PiecewiseYieldCurve<Discount, Cubic, QuantExt::IterativeBootstrap> my_curve;
562 yieldts = QuantLib::ext::make_shared<my_curve>(
563 asofDate_, instruments, zeroDayCounter_,
564 Cubic(CubicInterpolation::Kruger, true, CubicInterpolation::SecondDerivative, 0.0,
565 CubicInterpolation::FirstDerivative),
566 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
567 minFactor, dontThrowSteps));
568 } break;
570 typedef PiecewiseYieldCurve<Discount, ConvexMonotone, QuantExt::IterativeBootstrap> my_curve;
571 yieldts = QuantLib::ext::make_shared<my_curve>(
573 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
574 minFactor, dontThrowSteps));
575 } break;
577 typedef PiecewiseYieldCurve<Discount, Cubic, QuantExt::IterativeBootstrap> my_curve;
578 yieldts = QuantLib::ext::make_shared<my_curve>(
579 asofDate_, instruments, zeroDayCounter_, Cubic(CubicInterpolation::Parabolic),
580 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
581 minFactor, dontThrowSteps));
582 } break;
584 typedef PiecewiseYieldCurve<Discount, Cubic, QuantExt::IterativeBootstrap> my_curve;
585 yieldts = QuantLib::ext::make_shared<my_curve>(
586 asofDate_, instruments, zeroDayCounter_,
587 Cubic(CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
588 CubicInterpolation::SecondDerivative, 0.0),
589 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
590 minFactor, dontThrowSteps));
591 } break;
593 typedef PiecewiseYieldCurve<Discount, QuantExt::Quadratic, QuantExt::IterativeBootstrap> my_curve;
594 yieldts = QuantLib::ext::make_shared<my_curve>(
595 asofDate_, instruments, zeroDayCounter_, QuantExt::Quadratic(1, 0, 1, 0, 1),
596 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
597 minFactor, dontThrowSteps));
598 } break;
600 typedef PiecewiseYieldCurve<Discount, QuantExt::LogQuadratic, QuantExt::IterativeBootstrap> my_curve;
601 yieldts = QuantLib::ext::make_shared<my_curve>(
602 asofDate_, instruments, zeroDayCounter_, QuantExt::LogQuadratic(1, 0, -1, 0, 1),
603 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
604 minFactor, dontThrowSteps));
605 } break;
607 typedef PiecewiseYieldCurve<Discount, LogCubic, QuantExt::IterativeBootstrap> my_curve;
608 yieldts = QuantLib::ext::make_shared<my_curve>(
609 asofDate_, instruments, zeroDayCounter_, LogCubic(CubicInterpolation::Kruger, true),
610 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
611 minFactor, dontThrowSteps));
612 } break;
614 typedef PiecewiseYieldCurve<Discount, LogCubic, QuantExt::IterativeBootstrap> my_curve;
615 yieldts = QuantLib::ext::make_shared<my_curve>(
616 asofDate_, instruments, zeroDayCounter_,
617 QuantLib::LogCubic(CubicInterpolation::Kruger, true, CubicInterpolation::SecondDerivative, 0.0,
618 CubicInterpolation::FirstDerivative),
619 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
620 dontThrowSteps));
621 } break;
623 typedef PiecewiseYieldCurve<Discount,LogCubic, QuantExt::IterativeBootstrap> my_curve;
624 yieldts = QuantLib::ext::make_shared<my_curve>(
625 asofDate_, instruments, zeroDayCounter_,
626 LogCubic(CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
627 CubicInterpolation::SecondDerivative, 0.0),
628 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
629 dontThrowSteps));
630 } break;
632 typedef PiecewiseYieldCurve<Discount, DefaultLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
633 yieldts = QuantLib::ext::make_shared<my_curve>(
635 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
636 minFactor, dontThrowSteps));
637 } break;
639 typedef PiecewiseYieldCurve<Discount, MonotonicLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
640 yieldts = QuantLib::ext::make_shared<my_curve>(
642 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
643 minFactor, dontThrowSteps));
644 } break;
646 typedef PiecewiseYieldCurve<Discount, KrugerLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
647 yieldts = QuantLib::ext::make_shared<my_curve>(
649 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
650 minFactor, dontThrowSteps));
651 } break;
653 typedef PiecewiseYieldCurve<Discount, LogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
654 yieldts = QuantLib::ext::make_shared<my_curve>(
655 asofDate_, instruments, zeroDayCounter_,
656 LogMixedLinearCubic(mixedInterpolationSize_, MixedInterpolation::ShareRanges,
657 CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
658 CubicInterpolation::SecondDerivative, 0.0),
659 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
660 minFactor, dontThrowSteps));
661 } break;
662 default:
663 QL_FAIL("Interpolation method '" << interpolationMethod_ << "' not recognised.");
664 }
665 break;
667 switch (interpolationMethod_) {
669 typedef PiecewiseYieldCurve<ForwardRate, Linear, QuantExt::IterativeBootstrap> my_curve;
670 yieldts = QuantLib::ext::make_shared<my_curve>(
671 asofDate_, instruments, zeroDayCounter_, Linear(),
672 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
673 minFactor, dontThrowSteps));
674 } break;
676 typedef PiecewiseYieldCurve<ForwardRate, LogLinear, QuantExt::IterativeBootstrap> my_curve;
677 yieldts = QuantLib::ext::make_shared<my_curve>(
678 asofDate_, instruments, zeroDayCounter_, LogLinear(),
679 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
680 minFactor, dontThrowSteps));
681 } break;
683 typedef PiecewiseYieldCurve<ForwardRate, Cubic, QuantExt::IterativeBootstrap> my_curve;
684 yieldts = QuantLib::ext::make_shared<my_curve>(
685 asofDate_, instruments, zeroDayCounter_, Cubic(CubicInterpolation::Kruger, true),
686 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
687 minFactor, dontThrowSteps));
688 } break;
690 typedef PiecewiseYieldCurve<ForwardRate, Cubic, QuantExt::IterativeBootstrap> my_curve;
691 yieldts = QuantLib::ext::make_shared<my_curve>(
692 asofDate_, instruments, zeroDayCounter_,
693 Cubic(CubicInterpolation::Kruger, true, CubicInterpolation::SecondDerivative, 0.0,
694 CubicInterpolation::FirstDerivative),
695 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
696 minFactor, dontThrowSteps));
697 } break;
699 typedef PiecewiseYieldCurve<ForwardRate, ConvexMonotone, QuantExt::IterativeBootstrap> my_curve;
700 yieldts = QuantLib::ext::make_shared<my_curve>(
702 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
703 minFactor, dontThrowSteps));
704 } break;
706 typedef PiecewiseYieldCurve<ForwardRate, Cubic, QuantExt::IterativeBootstrap> my_curve;
707 yieldts = QuantLib::ext::make_shared<my_curve>(
708 asofDate_, instruments, zeroDayCounter_, Cubic(CubicInterpolation::Parabolic),
709 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
710 minFactor, dontThrowSteps));
711 } break;
713 typedef PiecewiseYieldCurve<ForwardRate, Cubic, QuantExt::IterativeBootstrap> my_curve;
714 yieldts = QuantLib::ext::make_shared<my_curve>(
715 asofDate_, instruments, zeroDayCounter_,
716 Cubic(CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
717 CubicInterpolation::SecondDerivative, 0.0),
718 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
719 minFactor, dontThrowSteps));
720 } break;
722 typedef PiecewiseYieldCurve<ForwardRate, QuantExt::Quadratic, QuantExt::IterativeBootstrap> my_curve;
723 yieldts = QuantLib::ext::make_shared<my_curve>(
724 asofDate_, instruments, zeroDayCounter_, QuantExt::Quadratic(1, 0, 1, 0, 1),
725 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
726 minFactor, dontThrowSteps));
727 } break;
729 typedef PiecewiseYieldCurve<ForwardRate, QuantExt::LogQuadratic, QuantExt::IterativeBootstrap> my_curve;
730 yieldts = QuantLib::ext::make_shared<my_curve>(
731 asofDate_, instruments, zeroDayCounter_, QuantExt::LogQuadratic(1, 0, -1, 0, 1),
732 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
733 minFactor, dontThrowSteps));
734 } break;
736 typedef PiecewiseYieldCurve<ForwardRate, LogCubic, QuantExt::IterativeBootstrap> my_curve;
737 yieldts = QuantLib::ext::make_shared<my_curve>(
738 asofDate_, instruments, zeroDayCounter_, LogCubic(CubicInterpolation::Kruger, true),
739 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
740 dontThrowSteps));
741 } break;
743 typedef PiecewiseYieldCurve<ForwardRate, LogCubic, QuantExt::IterativeBootstrap> my_curve;
744 yieldts = QuantLib::ext::make_shared<my_curve>(
745 asofDate_, instruments, zeroDayCounter_,
746 LogCubic(CubicInterpolation::Kruger, true, CubicInterpolation::SecondDerivative, 0.0,
747 CubicInterpolation::FirstDerivative),
748 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
749 dontThrowSteps));
750 } break;
752 typedef PiecewiseYieldCurve<ForwardRate, LogCubic, QuantExt::IterativeBootstrap> my_curve;
753 yieldts = QuantLib::ext::make_shared<my_curve>(
754 asofDate_, instruments, zeroDayCounter_,
755 LogCubic(CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
756 CubicInterpolation::SecondDerivative, 0.0),
757 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
758 dontThrowSteps));
759 } break;
761 typedef PiecewiseYieldCurve<ForwardRate, DefaultLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
762 yieldts = QuantLib::ext::make_shared<my_curve>(
764 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
765 minFactor, dontThrowSteps));
766 } break;
768 typedef PiecewiseYieldCurve<ForwardRate, MonotonicLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
769 yieldts = QuantLib::ext::make_shared<my_curve>(
771 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
772 minFactor, dontThrowSteps));
773 } break;
775 typedef PiecewiseYieldCurve<ForwardRate, KrugerLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
776 yieldts = QuantLib::ext::make_shared<my_curve>(
778 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
779 minFactor, dontThrowSteps));
780 } break;
782 typedef PiecewiseYieldCurve<ForwardRate, LogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
783 yieldts = QuantLib::ext::make_shared<my_curve>(
784 asofDate_, instruments, zeroDayCounter_,
785 LogMixedLinearCubic(mixedInterpolationSize_, MixedInterpolation::ShareRanges,
786 CubicInterpolation::Spline, false, CubicInterpolation::SecondDerivative, 0.0,
787 CubicInterpolation::SecondDerivative, 0.0),
788 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
789 minFactor, dontThrowSteps));
790 } break;
791 default:
792 QL_FAIL("Interpolation method '" << interpolationMethod_ << "' not recognised.");
793 }
794 break;
795 default:
796 QL_FAIL("Interpolation variable not recognised.");
797 }
798
800 p_ = yieldts;
801 else {
802 // Build fixed zero/discount curve that matches the bootstrapped curve
803 // initially, but does NOT react to quote changes: This is a workaround
804 // for a QuantLib problem, where a fixed reference date piecewise
805 // yield curve reacts to evaluation date changes because the bootstrap
806 // helper recompute their start date (because they are relative date
807 // helper for deposits, fras, swaps, etc.).
808 vector<Date> dates(instruments.size() + 1, asofDate_);
809 vector<Real> zeros(instruments.size() + 1, 0.0);
810 vector<Real> discounts(instruments.size() + 1, 1.0);
811 vector<Real> forwards(instruments.size() + 1, 0.0);
812
813 if (extrapolation_) {
814 yieldts->enableExtrapolation();
815 }
816 for (Size i = 0; i < instruments.size(); i++) {
817 dates[i + 1] = instruments[i]->pillarDate();
818 zeros[i + 1] = yieldts->zeroRate(dates[i + 1], zeroDayCounter_, Continuous);
819 discounts[i + 1] = yieldts->discount(dates[i + 1]);
820 forwards[i + 1] = yieldts->forwardRate(dates[i + 1], dates[i + 1], zeroDayCounter_, Continuous);
821 }
822 zeros[0] = zeros[1];
823 forwards[0] = forwards[1];
830 else
831 QL_FAIL("Interpolation variable not recognised.");
832 }
833
834 // set calibration info
836 calibrationInfo_ = QuantLib::ext::make_shared<PiecewiseYieldCurveCalibrationInfo>();
837 for (Size i = 0; i < instruments.size(); ++i) {
838 calibrationInfo_->pillarDates.push_back(instruments[i]->pillarDate());
839 }
840 }
841
842 return p_;
843}
QuantLib::ext::shared_ptr< YieldTermStructure > forwardcurve(const vector< Date > &dates, const vector< Rate > &forwards, const DayCounter &dayCounter, YieldCurve::InterpolationMethod interpolationMethod, Size n)
Create a Interpolated Forward Curve and apply interpolators.
Definition: yieldcurve.cpp:172
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addDeposits()

void addDeposits ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 1718 of file yieldcurve.cpp.

1719 {
1720
1721 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
1722
1723 // Get the conventions associated with the segment.
1724 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1725 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1726 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
1727 QL_REQUIRE(convention->type() == Convention::Type::Deposit,
1728 "Conventions ID does not give deposit rate conventions.");
1729 QuantLib::ext::shared_ptr<DepositConvention> depositConvention = QuantLib::ext::dynamic_pointer_cast<DepositConvention>(convention);
1730
1731 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> depositSegment =
1732 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
1733 auto depositQuoteIDs = depositSegment->quotes();
1734
1735 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
1736 "Deposit segment does not support pillar choice " << segment->pillarChoice());
1737 for (Size i = 0; i < depositQuoteIDs.size(); i++) {
1738 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(depositQuoteIDs[i], asofDate_);
1739
1740 // Check that we have a valid deposit quote
1741 if (marketQuote) {
1742 QuantLib::ext::shared_ptr<MoneyMarketQuote> depositQuote;
1743 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::MM,
1744 "Market quote not of type Deposit.");
1745 depositQuote = QuantLib::ext::dynamic_pointer_cast<MoneyMarketQuote>(marketQuote);
1746
1747 // Create a deposit helper if we do.
1748 QuantLib::ext::shared_ptr<RateHelper> depositHelper;
1749 Period depositTerm = depositQuote->term();
1750 Period fwdStart = depositQuote->fwdStart();
1751 Natural fwdStartDays = static_cast<Natural>(fwdStart.length());
1752 Handle<Quote> hQuote(depositQuote->quote());
1753
1754 QL_REQUIRE(fwdStart.units() == Days, "The forward start time unit for deposits "
1755 "must be expressed in days.");
1756
1757 if (depositConvention->indexBased()) {
1758 // indexName will have the form ccy-name so examples would be:
1759 // EUR-EONIA, USD-FedFunds, EUR-EURIBOR, USD-LIBOR, etc.
1760 string indexName = depositConvention->index();
1761 QuantLib::ext::shared_ptr<IborIndex> index;
1762 if (isOvernightIndex(indexName)) {
1763 // No need for the term here
1764 index = parseIborIndex(indexName);
1765 } else {
1766 // Note that a depositTerm with units Days here could end up as a string with another unit
1767 // For example:
1768 // 7 * Days will go to ccy-tenor-1W - CNY IR index is a case
1769 // 28 * Days will go to ccy-tenor-4W - MXN TIIE is a case
1770 // parseIborIndex should be able to handle this for appropriate depositTerm values
1771 stringstream ss;
1772 ss << indexName << "-" << io::short_period(depositTerm);
1773 indexName = ss.str();
1774 index = parseIborIndex(indexName);
1775 }
1776 depositHelper = QuantLib::ext::make_shared<DepositRateHelper>(
1777 hQuote, depositTerm, fwdStartDays, index->fixingCalendar(), index->businessDayConvention(),
1778 index->endOfMonth(), index->dayCounter());
1779 } else {
1780 depositHelper = QuantLib::ext::make_shared<DepositRateHelper>(
1781 hQuote, depositTerm, fwdStartDays, depositConvention->calendar(), depositConvention->convention(),
1782 depositConvention->eom(), depositConvention->dayCounter());
1783 }
1784 instruments.push_back(depositHelper);
1785 }
1786 }
1787}
bool isOvernightIndex(const string &indexName)
Return true if the indexName is that of an overnight index, otherwise false.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addFutures()

void addFutures ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 1789 of file yieldcurve.cpp.

1790 {
1791
1792 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
1793
1794 // Get the conventions associated with the segment.
1795 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1796 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1797 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
1798 QL_REQUIRE(convention->type() == Convention::Type::Future,
1799 "Conventions ID does not give deposit rate conventions.");
1800 QuantLib::ext::shared_ptr<FutureConvention> futureConvention = QuantLib::ext::dynamic_pointer_cast<FutureConvention>(convention);
1801
1802 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> futureSegment =
1803 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
1804 auto futureQuoteIDs = futureSegment->quotes();
1805
1806 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
1807 "Future segment does not support pillar choice " << segment->pillarChoice());
1808 for (Size i = 0; i < futureQuoteIDs.size(); i++) {
1809 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(futureQuoteIDs[i], asofDate_);
1810
1811 // Check that we have a valid future quote
1812 if (marketQuote) {
1813
1814 if (auto on = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(futureConvention->index())) {
1815 // Overnight Index Future
1816 QuantLib::ext::shared_ptr<OIFutureQuote> futureQuote;
1817 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::OI_FUTURE,
1818 "Market quote not of type Overnight Index Future.");
1819 futureQuote = QuantLib::ext::dynamic_pointer_cast<OIFutureQuote>(marketQuote);
1820
1821 // check that the tenor of the quote is expressed in months or years, otherwise the date calculations
1822 // below do not make sense
1823 QL_REQUIRE(futureQuote->tenor().units() == Months || futureQuote->tenor().units() == Years,
1824 "Tenor of future quote (" << futureQuote->name()
1825 << ") must be expressed in months or years");
1826
1827 // Create a Overnight index future helper
1828 Date startDate, endDate;
1829 if (futureConvention->dateGenerationRule() == FutureConvention::DateGenerationRule::IMM) {
1830 Date refEnd = Date(1, futureQuote->expiryMonth(), futureQuote->expiryYear());
1831 Date refStart = refEnd - futureQuote->tenor();
1832 startDate = IMM::nextDate(refStart, false);
1833 endDate = IMM::nextDate(refEnd, false);
1834 } else if (futureConvention->dateGenerationRule() ==
1836 endDate = Date(1, futureQuote->expiryMonth(), futureQuote->expiryYear()) + 1 * Months;
1837 startDate = endDate - futureQuote->tenor();
1838 }
1839
1840 if (endDate <= asofDate_) {
1841 DLOG("Skipping the " << io::ordinal(i + 1) << " overnight index future instrument because its "
1842 << "end date, " << io::iso_date(endDate)
1843 << ", is on or before the valuation date, " << io::iso_date(asofDate_) << ".");
1844 continue;
1845 }
1846
1847 QuantLib::ext::shared_ptr<RateHelper> futureHelper = QuantLib::ext::make_shared<OvernightIndexFutureRateHelper>(
1848 futureQuote->quote(), startDate, endDate, on, Handle<Quote>(),
1849 futureConvention->overnightIndexFutureNettingType());
1850 instruments.push_back(futureHelper);
1851
1852 TLOG("adding OI future helper: price=" << futureQuote->quote()->value() << " start=" << startDate
1853 << " end=" << endDate << " nettingType="
1854 << futureConvention->overnightIndexFutureNettingType());
1855
1856 } else {
1857 // MM Future
1858 QuantLib::ext::shared_ptr<MMFutureQuote> futureQuote;
1859 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::MM_FUTURE,
1860 "Market quote not of type Money Market Future.");
1861 futureQuote = QuantLib::ext::dynamic_pointer_cast<MMFutureQuote>(marketQuote);
1862
1863 // Create a MM future helper
1864 QL_REQUIRE(
1865 futureConvention->dateGenerationRule() == FutureConvention::DateGenerationRule::IMM,
1866 "For MM Futures only 'IMM' is allowed as the date generation rule, check the future convention '"
1867 << segment->conventionsID() << "'");
1868 Date refDate(1, futureQuote->expiryMonth(), futureQuote->expiryYear());
1869 Date immDate = IMM::nextDate(refDate, false);
1870
1871 if (immDate < asofDate_) {
1872 DLOG("Skipping the " << io::ordinal(i + 1) << " money market future instrument because its "
1873 << "start date, " << io::iso_date(immDate)
1874 << ", is before the valuation date, " << io::iso_date(asofDate_) << ".");
1875 continue;
1876 }
1877
1878 QuantLib::ext::shared_ptr<RateHelper> futureHelper =
1879 QuantLib::ext::make_shared<FuturesRateHelper>(futureQuote->quote(), immDate, futureConvention->index());
1880
1881 instruments.push_back(futureHelper);
1882 }
1883 }
1884 }
1885}
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addFras()

void addFras ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 1887 of file yieldcurve.cpp.

1888 {
1889
1890 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
1891
1892 // Get the conventions associated with the segment.
1893 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1894 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1895 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
1896 QL_REQUIRE(convention->type() == Convention::Type::FRA, "Conventions ID does not give FRA conventions.");
1897 QuantLib::ext::shared_ptr<FraConvention> fraConvention = QuantLib::ext::dynamic_pointer_cast<FraConvention>(convention);
1898
1899 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> fraSegment =
1900 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
1901 auto fraQuoteIDs = fraSegment->quotes();
1902
1903 for (Size i = 0; i < fraQuoteIDs.size(); i++) {
1904 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(fraQuoteIDs[i], asofDate_);
1905
1906 // Check that we have a valid FRA quote
1907 if (marketQuote) {
1908 QL_REQUIRE((marketQuote->instrumentType() == MarketDatum::InstrumentType::FRA) ||
1909 (marketQuote->instrumentType() == MarketDatum::InstrumentType::IMM_FRA),
1910 "Market quote not of type FRA.");
1911
1912 // Create a FRA helper if we do.
1913
1914 QuantLib::ext::shared_ptr<RateHelper> fraHelper;
1915
1916 if (marketQuote->instrumentType() == MarketDatum::InstrumentType::IMM_FRA) {
1917 QuantLib::ext::shared_ptr<ImmFraQuote> immFraQuote;
1918 immFraQuote = QuantLib::ext::dynamic_pointer_cast<ImmFraQuote>(marketQuote);
1919 Size imm1 = immFraQuote->imm1();
1920 Size imm2 = immFraQuote->imm2();
1921 fraHelper = QuantLib::ext::make_shared<ImmFraRateHelper>(immFraQuote->quote(), imm1, imm2,
1922 fraConvention->index(), fraSegment->pillarChoice());
1923 } else if (marketQuote->instrumentType() == MarketDatum::InstrumentType::FRA) {
1924 QuantLib::ext::shared_ptr<FRAQuote> fraQuote;
1925 fraQuote = QuantLib::ext::dynamic_pointer_cast<FRAQuote>(marketQuote);
1926 Period periodToStart = fraQuote->fwdStart();
1927 fraHelper = QuantLib::ext::make_shared<FraRateHelper>(fraQuote->quote(), periodToStart, fraConvention->index(),
1928 fraSegment->pillarChoice());
1929 } else {
1930 QL_FAIL("Market quote not of type FRA.");
1931 }
1932
1933 instruments.push_back(fraHelper);
1934 }
1935 }
1936}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addOISs()

void addOISs ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 1938 of file yieldcurve.cpp.

1939 {
1940
1941 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
1942
1943 // Get the conventions associated with the segment.
1944 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1945 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1946 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
1947 QL_REQUIRE(convention->type() == Convention::Type::OIS, "Conventions ID does not give OIS conventions.");
1948 QuantLib::ext::shared_ptr<OisConvention> oisConvention = QuantLib::ext::dynamic_pointer_cast<OisConvention>(convention);
1949
1950 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> oisSegment =
1951 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
1952
1953 // If projection curve ID is not the this curve.
1954 string projectionCurveID = oisSegment->projectionCurveID();
1955 QuantLib::ext::shared_ptr<OvernightIndex> onIndex = oisConvention->index();
1956 if (projectionCurveID != curveConfig_->curveID() && !projectionCurveID.empty()) {
1957 projectionCurveID = yieldCurveKey(currency_, projectionCurveID, asofDate_);
1958 QuantLib::ext::shared_ptr<YieldCurve> projectionCurve;
1959 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
1960 it = requiredYieldCurves_.find(projectionCurveID);
1961 if (it != requiredYieldCurves_.end()) {
1962 projectionCurve = it->second;
1963 } else {
1964 QL_FAIL("The projection curve, " << projectionCurveID
1965 << ", required in the building "
1966 "of the curve, "
1967 << curveSpec_.name() << ", was not found.");
1968 }
1969 onIndex = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(onIndex->clone(projectionCurve->handle()));
1970 }
1971
1972 // BRL CDI overnight needs a specialised rate helper so we use this below to switch
1973 QuantLib::ext::shared_ptr<BRLCdi> brlCdiIndex = QuantLib::ext::dynamic_pointer_cast<BRLCdi>(onIndex);
1974
1975 auto oisQuoteIDs = oisSegment->quotes();
1976 for (Size i = 0; i < oisQuoteIDs.size(); i++) {
1977 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(oisQuoteIDs[i], asofDate_);
1978
1979 // Check that we have a valid OIS quote
1980 if (marketQuote) {
1981 QuantLib::ext::shared_ptr<SwapQuote> oisQuote;
1982 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::IR_SWAP,
1983 "Market quote (" << marketQuote->name() << ") not of type swap.");
1984 oisQuote = QuantLib::ext::dynamic_pointer_cast<SwapQuote>(marketQuote);
1985
1986 // Create a swap helper if we do.
1987 Period oisTenor = oisQuote->term();
1988 QuantLib::ext::shared_ptr<RateHelper> oisHelper;
1989 if (brlCdiIndex) {
1990 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
1991 "OIS segment for BRL-CDI does not support pillar choice " << segment->pillarChoice());
1992 oisHelper = QuantLib::ext::make_shared<BRLCdiRateHelper>(
1993 oisTenor, oisQuote->quote(), brlCdiIndex,
1994 discountCurve_ ? discountCurve_->handle() : Handle<YieldTermStructure>(), true);
1995 } else {
1996
1997 if (oisQuote->startDate() == Null<Date>() || oisQuote->maturityDate() == Null<Date>())
1998 oisHelper = QuantLib::ext::make_shared<QuantExt::OISRateHelper>(
1999 oisConvention->spotLag(), oisTenor, oisQuote->quote(), onIndex, oisConvention->fixedDayCounter(),
2000 oisConvention->fixedCalendar(), oisConvention->paymentLag(), oisConvention->eom(),
2001 oisConvention->fixedFrequency(), oisConvention->fixedConvention(),
2002 oisConvention->fixedPaymentConvention(), oisConvention->rule(),
2003 discountCurve_ ? discountCurve_->handle() : Handle<YieldTermStructure>(), true,
2004 oisSegment->pillarChoice());
2005 else {
2006 oisHelper = QuantLib::ext::make_shared<QuantExt::DatedOISRateHelper>(oisQuote->startDate(),
2007 oisQuote->maturityDate(), oisQuote->quote(), onIndex, oisConvention->fixedDayCounter(),
2008 oisConvention->fixedCalendar(), oisConvention->paymentLag(),
2009 oisConvention->fixedFrequency(), oisConvention->fixedConvention(),
2010 oisConvention->fixedPaymentConvention(), oisConvention->rule(),
2011 discountCurve_ ? discountCurve_->handle() : Handle<YieldTermStructure>(), true,
2012 oisSegment->pillarChoice());
2013 }
2014 }
2015 instruments.push_back(oisHelper);
2016 }
2017 }
2018}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addSwaps()

void addSwaps ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 2020 of file yieldcurve.cpp.

2021 {
2022
2023 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
2024
2025 // Get the conventions associated with the segment.
2026 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2027 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2028 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
2029 QL_REQUIRE(convention->type() == Convention::Type::Swap, "Conventions ID does not give swap conventions.");
2030 QuantLib::ext::shared_ptr<IRSwapConvention> swapConvention = QuantLib::ext::dynamic_pointer_cast<IRSwapConvention>(convention);
2031
2032 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> swapSegment =
2033 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
2034 if (swapSegment->projectionCurveID() != curveConfig_->curveID() && !swapSegment->projectionCurveID().empty()) {
2035 QL_FAIL("Solving for discount curve given the projection"
2036 " curve is not implemented yet");
2037 }
2038 auto swapQuoteIDs = swapSegment->quotes();
2039
2040 for (Size i = 0; i < swapQuoteIDs.size(); i++) {
2041 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(swapQuoteIDs[i], asofDate_);
2042
2043 // Check that we have a valid swap quote
2044 if (marketQuote) {
2045 QuantLib::ext::shared_ptr<SwapQuote> swapQuote;
2046 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::IR_SWAP,
2047 "Market quote not of type swap.");
2048 swapQuote = QuantLib::ext::dynamic_pointer_cast<SwapQuote>(marketQuote);
2049 QL_REQUIRE(swapQuote->startDate() == Null<Date>(),
2050 "swap quote with fixed start date is not supported for ibor / subperiods swap instruments");
2051 // Create a swap helper if we do.
2052 Period swapTenor = swapQuote->term();
2053 QuantLib::ext::shared_ptr<RateHelper> swapHelper;
2054 if (swapConvention->hasSubPeriod()) {
2055 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2056 "Subperiod Swap segment does not support pillar choice " << segment->pillarChoice());
2057 swapHelper = QuantLib::ext::make_shared<SubPeriodsSwapHelper>(
2058 swapQuote->quote(), swapTenor, Period(swapConvention->fixedFrequency()),
2059 swapConvention->fixedCalendar(), swapConvention->fixedDayCounter(),
2060 swapConvention->fixedConvention(), Period(swapConvention->floatFrequency()),
2061 swapConvention->index(), swapConvention->index()->dayCounter(),
2062 discountCurve_ ? discountCurve_->handle() : Handle<YieldTermStructure>(),
2063 swapConvention->subPeriodsCouponType());
2064 } else {
2065 swapHelper = QuantLib::ext::make_shared<SwapRateHelper>(
2066 swapQuote->quote(), swapTenor, swapConvention->fixedCalendar(), swapConvention->fixedFrequency(),
2067 swapConvention->fixedConvention(), swapConvention->fixedDayCounter(), swapConvention->index(),
2068 Handle<Quote>(), 0 * Days, discountCurve_ ? discountCurve_->handle() : Handle<YieldTermStructure>(),
2069 Null<Natural>(), swapSegment->pillarChoice());
2070 }
2071
2072 instruments.push_back(swapHelper);
2073 }
2074 }
2075}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addAverageOISs()

void addAverageOISs ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 2077 of file yieldcurve.cpp.

2078 {
2079
2080 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
2081
2082 // Get the conventions associated with the segment.
2083 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2084 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2085 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
2086 QL_REQUIRE(convention->type() == Convention::Type::AverageOIS,
2087 "Conventions ID does not give average OIS conventions.");
2088 QuantLib::ext::shared_ptr<AverageOisConvention> averageOisConvention =
2089 QuantLib::ext::dynamic_pointer_cast<AverageOisConvention>(convention);
2090
2091 QuantLib::ext::shared_ptr<AverageOISYieldCurveSegment> averageOisSegment =
2092 QuantLib::ext::dynamic_pointer_cast<AverageOISYieldCurveSegment>(segment);
2093
2094 // If projection curve ID is not the this curve.
2095 string projectionCurveID = averageOisSegment->projectionCurveID();
2096 QuantLib::ext::shared_ptr<OvernightIndex> onIndex = averageOisConvention->index();
2097 if (projectionCurveID != curveConfig_->curveID() && !projectionCurveID.empty()) {
2098 projectionCurveID = yieldCurveKey(currency_, projectionCurveID, asofDate_);
2099 QuantLib::ext::shared_ptr<YieldCurve> projectionCurve;
2100 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2101 it = requiredYieldCurves_.find(projectionCurveID);
2102 if (it != requiredYieldCurves_.end()) {
2103 projectionCurve = it->second;
2104 } else {
2105 QL_FAIL("The projection curve, " << projectionCurveID
2106 << ", required in the building "
2107 "of the curve, "
2108 << curveSpec_.name() << ", was not found.");
2109 }
2110 onIndex = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(onIndex->clone(projectionCurve->handle()));
2111 }
2112
2113 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2114 "Average OIS segment does not support pillar choice " << segment->pillarChoice());
2115 auto averageOisQuoteIDs = averageOisSegment->quotes();
2116 for (Size i = 0; i < averageOisQuoteIDs.size(); i += 2) {
2117 // we are assuming i = spread, i+1 = rate
2118 QL_REQUIRE(i % 2 == 0, "i is not even");
2119 /* An average OIS quote is a composite of a swap quote and a basis
2120 spread quote. Check first that we have these. */
2121 // Firstly, the rate quote.
2122 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(averageOisQuoteIDs[i], asofDate_);
2123 QuantLib::ext::shared_ptr<SwapQuote> swapQuote;
2124 if (marketQuote) {
2125 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::IR_SWAP,
2126 "Market quote not of type swap.");
2127 swapQuote = QuantLib::ext::dynamic_pointer_cast<SwapQuote>(marketQuote);
2128 QL_REQUIRE(swapQuote->startDate() == Null<Date>(),
2129 "swap quote with fixed start date is not supported for average ois instrument");
2130
2131 // Secondly, the basis spread quote.
2132 marketQuote = loader_.get(averageOisQuoteIDs[i + 1], asofDate_);
2133 QuantLib::ext::shared_ptr<BasisSwapQuote> basisQuote;
2134 if (marketQuote) {
2135 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::BASIS_SWAP,
2136 "Market quote not of type basis swap.");
2137 basisQuote = QuantLib::ext::dynamic_pointer_cast<BasisSwapQuote>(marketQuote);
2138
2139 // Create an average OIS helper if we do.
2140 Period AverageOisTenor = swapQuote->term();
2141 QL_REQUIRE(AverageOisTenor == basisQuote->maturity(),
2142 "The swap "
2143 "and basis swap components of the Average OIS must "
2144 "have the same maturity.");
2145 QuantLib::ext::shared_ptr<RateHelper> averageOisHelper(new QuantExt::AverageOISRateHelper(
2146 swapQuote->quote(), averageOisConvention->spotLag() * Days, AverageOisTenor,
2147 averageOisConvention->fixedTenor(), averageOisConvention->fixedDayCounter(),
2148 averageOisConvention->fixedCalendar(), averageOisConvention->fixedConvention(),
2149 averageOisConvention->fixedPaymentConvention(), onIndex, averageOisConvention->onTenor(),
2150 basisQuote->quote(), averageOisConvention->rateCutoff(),
2151 discountCurve_ ? discountCurve_->handle() : Handle<YieldTermStructure>(), true));
2152
2153 instruments.push_back(averageOisHelper);
2154 }
2155 }
2156 }
2157}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addTenorBasisSwaps()

void addTenorBasisSwaps ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 2159 of file yieldcurve.cpp.

2160 {
2161
2162 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
2163
2164 // Get the conventions associated with the segment.
2165 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2166 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2167 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
2168 QL_REQUIRE(convention->type() == Convention::Type::TenorBasisSwap,
2169 "Conventions ID does not give tenor basis swap conventions.");
2170 QuantLib::ext::shared_ptr<TenorBasisSwapConvention> basisSwapConvention =
2171 QuantLib::ext::dynamic_pointer_cast<TenorBasisSwapConvention>(convention);
2172
2173 QuantLib::ext::shared_ptr<TenorBasisYieldCurveSegment> basisSwapSegment =
2174 QuantLib::ext::dynamic_pointer_cast<TenorBasisYieldCurveSegment>(segment);
2175
2176 // If short index projection curve ID is not this curve.
2177 string receiveCurveID = basisSwapSegment->receiveProjectionCurveID();
2178 QuantLib::ext::shared_ptr<IborIndex> receiveIndex = basisSwapConvention->receiveIndex();
2179 if (receiveCurveID != curveConfig_->curveID() && !receiveCurveID.empty()) {
2180 receiveCurveID = yieldCurveKey(currency_, receiveCurveID, asofDate_);
2181 QuantLib::ext::shared_ptr<YieldCurve> shortCurve;
2182 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2183 it = requiredYieldCurves_.find(receiveCurveID);
2184 if (it != requiredYieldCurves_.end()) {
2185 shortCurve = it->second;
2186 } else {
2187 QL_FAIL("The short side projection curve, " << receiveCurveID
2188 << ", required in the building "
2189 "of the curve, "
2190 << curveSpec_.name() << ", was not found.");
2191 }
2192 receiveIndex = receiveIndex->clone(shortCurve->handle());
2193 }
2194
2195 // If long index projection curve ID is not this curve.
2196 string payCurveID = basisSwapSegment->payProjectionCurveID();
2197 QuantLib::ext::shared_ptr<IborIndex> payIndex = basisSwapConvention->payIndex();
2198 if (payCurveID != curveConfig_->curveID() && !payCurveID.empty()) {
2199 payCurveID = yieldCurveKey(currency_, payCurveID, asofDate_);
2200 QuantLib::ext::shared_ptr<YieldCurve> longCurve;
2201 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2202 it = requiredYieldCurves_.find(payCurveID);
2203 if (it != requiredYieldCurves_.end()) {
2204 longCurve = it->second;
2205 } else {
2206 QL_FAIL("The long side projection curve, " << payCurveID
2207 << ", required in the building "
2208 "of the curve, "
2209 << curveSpec_.name() << ", was not found.");
2210 }
2211 payIndex = payIndex->clone(longCurve->handle());
2212 }
2213
2214 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2215 "Tenor basis swap segment does not support pillar choice " << segment->pillarChoice());
2216 auto basisSwapQuoteIDs = basisSwapSegment->quotes();
2217 for (Size i = 0; i < basisSwapQuoteIDs.size(); i++) {
2218 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(basisSwapQuoteIDs[i], asofDate_);
2219
2220 // Check that we have a valid basis swap quote
2221 if (marketQuote) {
2222 QuantLib::ext::shared_ptr<BasisSwapQuote> basisSwapQuote;
2223 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::BASIS_SWAP,
2224 "Market quote not of type basis swap.");
2225 basisSwapQuote = QuantLib::ext::dynamic_pointer_cast<BasisSwapQuote>(marketQuote);
2226
2227 // Create a tenor basis swap helper if we do.
2228 Period basisSwapTenor = basisSwapQuote->maturity();
2229 QuantLib::ext::shared_ptr<RateHelper> basisSwapHelper;
2230 bool telescopicValueDates = true;
2231 basisSwapHelper.reset(
2232 new TenorBasisSwapHelper(basisSwapQuote->quote(), basisSwapTenor, payIndex, receiveIndex,
2233 discountCurve_ ? discountCurve_->handle() : Handle<YieldTermStructure>(),
2234 basisSwapConvention->spreadOnRec(), basisSwapConvention->includeSpread(),
2235 basisSwapConvention->payFrequency(), basisSwapConvention->receiveFrequency(),
2236 telescopicValueDates, basisSwapConvention->subPeriodsCouponType()));
2237
2238 instruments.push_back(basisSwapHelper);
2239 }
2240 }
2241}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addTenorBasisTwoSwaps()

void addTenorBasisTwoSwaps ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 2243 of file yieldcurve.cpp.

2244 {
2245
2246 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
2247
2248 // Get the conventions associated with the segment.
2249 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2250 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2251 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
2252 QL_REQUIRE(convention->type() == Convention::Type::TenorBasisTwoSwap,
2253 "Conventions ID does not give tenor basis two swap conventions.");
2254 QuantLib::ext::shared_ptr<TenorBasisTwoSwapConvention> basisSwapConvention =
2255 QuantLib::ext::dynamic_pointer_cast<TenorBasisTwoSwapConvention>(convention);
2256
2257 QuantLib::ext::shared_ptr<TenorBasisYieldCurveSegment> basisSwapSegment =
2258 QuantLib::ext::dynamic_pointer_cast<TenorBasisYieldCurveSegment>(segment);
2259
2260 // If short index projection curve ID is not this curve.
2261 string shortCurveID = basisSwapSegment->receiveProjectionCurveID();
2262 QuantLib::ext::shared_ptr<IborIndex> shortIndex = basisSwapConvention->shortIndex();
2263 if (shortCurveID != curveConfig_->curveID() && !shortCurveID.empty()) {
2264 shortCurveID = yieldCurveKey(currency_, shortCurveID, asofDate_);
2265 QuantLib::ext::shared_ptr<YieldCurve> shortCurve;
2266 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2267 it = requiredYieldCurves_.find(shortCurveID);
2268 if (it != requiredYieldCurves_.end()) {
2269 shortCurve = it->second;
2270 } else {
2271 QL_FAIL("The short side projection curve, " << shortCurveID
2272 << ", required in the building "
2273 "of the curve, "
2274 << curveSpec_.name() << ", was not found.");
2275 }
2276 shortIndex = shortIndex->clone(shortCurve->handle());
2277 }
2278
2279 // If long index projection curve ID is not this curve.
2280 string longCurveID = basisSwapSegment->payProjectionCurveID();
2281 QuantLib::ext::shared_ptr<IborIndex> longIndex = basisSwapConvention->longIndex();
2282 if (longCurveID != curveConfig_->curveID() && !longCurveID.empty()) {
2283 longCurveID = yieldCurveKey(currency_, longCurveID, asofDate_);
2284 QuantLib::ext::shared_ptr<YieldCurve> longCurve;
2285 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2286 it = requiredYieldCurves_.find(longCurveID);
2287 if (it != requiredYieldCurves_.end()) {
2288 longCurve = it->second;
2289 } else {
2290 QL_FAIL("The projection curve, " << longCurveID
2291 << ", required in the building "
2292 "of the curve, "
2293 << curveSpec_.name() << ", was not found.");
2294 }
2295 longIndex = longIndex->clone(longCurve->handle());
2296 }
2297
2298 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2299 "Tenor basis two swap segment does not support pillar choice " << segment->pillarChoice());
2300 auto basisSwapQuoteIDs = basisSwapSegment->quotes();
2301 for (Size i = 0; i < basisSwapQuoteIDs.size(); i++) {
2302 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(basisSwapQuoteIDs[i], asofDate_);
2303
2304 // Check that we have a valid basis swap quote
2305 QuantLib::ext::shared_ptr<BasisSwapQuote> basisSwapQuote;
2306 if (marketQuote) {
2307 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::BASIS_SWAP,
2308 "Market quote not of type basis swap.");
2309 basisSwapQuote = QuantLib::ext::dynamic_pointer_cast<BasisSwapQuote>(marketQuote);
2310
2311 // Create a tenor basis swap helper if we do.
2312 Period basisSwapTenor = basisSwapQuote->maturity();
2313 QuantLib::ext::shared_ptr<RateHelper> basisSwapHelper(new BasisTwoSwapHelper(
2314 basisSwapQuote->quote(), basisSwapTenor, basisSwapConvention->calendar(),
2315 basisSwapConvention->longFixedFrequency(), basisSwapConvention->longFixedConvention(),
2316 basisSwapConvention->longFixedDayCounter(), longIndex, basisSwapConvention->shortFixedFrequency(),
2317 basisSwapConvention->shortFixedConvention(), basisSwapConvention->shortFixedDayCounter(), shortIndex,
2318 basisSwapConvention->longMinusShort(),
2319 discountCurve_ ? discountCurve_->handle() : Handle<YieldTermStructure>()));
2320
2321 instruments.push_back(basisSwapHelper);
2322 }
2323 }
2324}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addBMABasisSwaps()

void addBMABasisSwaps ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 2326 of file yieldcurve.cpp.

2327 {
2328
2329 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
2330
2331 // Get the conventions associated with the segment.
2332 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2333 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2334 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
2335 QL_REQUIRE(convention->type() == Convention::Type::BMABasisSwap,
2336 "Conventions ID does not give bma basis swap conventions.");
2337 QuantLib::ext::shared_ptr<BMABasisSwapConvention> bmaBasisSwapConvention =
2338 QuantLib::ext::dynamic_pointer_cast<BMABasisSwapConvention>(convention);
2339
2340 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> bmaBasisSwapSegment =
2341 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
2342 QL_REQUIRE(bmaBasisSwapSegment, "BMA basis swap segment of " + curveSpec_.ccy() + "/" + curveSpec_.curveConfigID() +
2343 " did not successfully cast to a BMA basis swap yield curve segment!");
2344
2345 // TODO: should be checking here whether or not the bma index is forwarding on this curve. either way, we make sure!
2346 QuantLib::ext::shared_ptr<BMAIndexWrapper> bmaIndex = bmaBasisSwapConvention->bmaIndex();
2347 bmaIndex = dynamic_pointer_cast<BMAIndexWrapper>(bmaIndex->clone(handle()));
2348
2349 // If libor index projection curve ID is not this curve.
2350 string liborCurveID = bmaBasisSwapSegment->projectionCurveID();
2351 QuantLib::ext::shared_ptr<IborIndex> liborIndex = bmaBasisSwapConvention->liborIndex();
2352 liborCurveID = yieldCurveKey(currency_, liborCurveID, asofDate_);
2353 QuantLib::ext::shared_ptr<YieldCurve> liborCurve;
2354 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2355 it = requiredYieldCurves_.find(liborCurveID);
2356 if (it != requiredYieldCurves_.end()) {
2357 liborCurve = it->second;
2358 } else {
2359 QL_FAIL("The libor side projection curve, " << liborCurveID
2360 << ", required in the building "
2361 "of the curve, "
2362 << curveSpec_.name() << ", was not found.");
2363 }
2364 liborIndex = liborIndex->clone(liborCurve->handle());
2365
2366 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2367 "BMA swap segment does not support pillar choice " << segment->pillarChoice());
2368 auto bmaBasisSwapQuoteIDs = bmaBasisSwapSegment->quotes();
2369 for (Size i = 0; i < bmaBasisSwapQuoteIDs.size(); i++) {
2370 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(bmaBasisSwapQuoteIDs[i], asofDate_);
2371
2372 // Check that we have a valid bma basis swap quote
2373 if (marketQuote) {
2374 QuantLib::ext::shared_ptr<BMASwapQuote> bmaBasisSwapQuote;
2375 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::BMA_SWAP,
2376 "Market quote not of type bma swap.");
2377 QL_REQUIRE(marketQuote->quoteType() == MarketDatum::QuoteType::RATIO, "Market quote not of type ratio.");
2378 bmaBasisSwapQuote = QuantLib::ext::dynamic_pointer_cast<BMASwapQuote>(marketQuote);
2379
2380 // Create bma basis swap helper if we do.
2381 QuantLib::ext::shared_ptr<RateHelper> bmaSwapHelper;
2382 bmaSwapHelper.reset(new BMASwapRateHelper(bmaBasisSwapQuote->quote(), bmaBasisSwapQuote->maturity(),
2383 bmaIndex->fixingDays(), bmaIndex->fixingCalendar(),
2384 bmaBasisSwapQuote->term(), bmaIndex->businessDayConvention(),
2385 bmaIndex->dayCounter(), bmaIndex->bma(), liborIndex));
2386 instruments.push_back(bmaSwapHelper);
2387 }
2388 }
2389}
const Handle< YieldTermStructure > & handle() const
Definition: yieldcurve.hpp:120
const string & ccy() const
Definition: curvespec.hpp:121
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addFXForwards()

void addFXForwards ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 2391 of file yieldcurve.cpp.

2392 {
2393
2394 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
2395
2396 // Get the conventions associated with the segment.
2397 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2398 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2399 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
2400 QL_REQUIRE(convention->type() == Convention::Type::FX, "Conventions ID does not give FX forward conventions.");
2401
2402 QuantLib::ext::shared_ptr<FXConvention> fxConvention = QuantLib::ext::dynamic_pointer_cast<FXConvention>(convention);
2403
2404 QuantLib::ext::shared_ptr<CrossCcyYieldCurveSegment> fxForwardSegment =
2405 QuantLib::ext::dynamic_pointer_cast<CrossCcyYieldCurveSegment>(segment);
2406
2407 /* Need to retrieve the discount curve in the other currency. These are called the known discount
2408 curve and known discount currency respectively. */
2409 Currency knownCurrency;
2410 if (currency_ == fxConvention->sourceCurrency()) {
2411 knownCurrency = fxConvention->targetCurrency();
2412 } else if (currency_ == fxConvention->targetCurrency()) {
2413 knownCurrency = fxConvention->sourceCurrency();
2414 } else {
2415 QL_FAIL("One of the currencies in the FX forward bootstrap "
2416 "instruments needs to match the yield curve currency.");
2417 }
2418
2419 string knownDiscountID = fxForwardSegment->foreignDiscountCurveID();
2420 Handle<YieldTermStructure> knownDiscountCurve;
2421
2422 if (!knownDiscountID.empty()) {
2423 knownDiscountID = yieldCurveKey(knownCurrency, knownDiscountID, asofDate_);
2424 auto it = requiredYieldCurves_.find(knownDiscountID);
2425 if (it != requiredYieldCurves_.end()) {
2426 knownDiscountCurve = it->second->handle();
2427 } else {
2428 QL_FAIL("The foreign discount curve, " << knownDiscountID
2429 << ", required in the building "
2430 "of the curve, "
2431 << curveSpec_.name() << ", was not found.");
2432 }
2433 } else {
2434 // fall back on the foreign discount curve if no index given
2435 // look up the inccy discount curve - falls back to defualt if no inccy
2436 DLOG("YieldCurve::addFXForwards No discount curve provided for building curve " <<
2437 curveSpec_.name() << ", looking up the inccy curve in the market.")
2438 knownDiscountCurve = market_->discountCurve(knownCurrency.code(), Market::inCcyConfiguration);
2439 }
2440
2441
2442 /* Need to retrieve the market FX spot rate */
2443 string spotRateID = fxForwardSegment->spotRateID();
2444 QuantLib::ext::shared_ptr<FXSpotQuote> fxSpotQuote = getFxSpotQuote(spotRateID);
2445
2446 /* Create an FX spot quote from the retrieved FX spot rate */
2447 Currency fxSpotSourceCcy = parseCurrency(fxSpotQuote->unitCcy());
2448 Currency fxSpotTargetCcy = parseCurrency(fxSpotQuote->ccy());
2449
2450 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2451 "FX Forward segment does not support pillar choice " << segment->pillarChoice());
2452 DLOG("YieldCurve::addFXForwards(), create FX forward quotes and helpers");
2453 auto fxForwardQuoteIDs = fxForwardSegment->quotes();
2454 for (Size i = 0; i < fxForwardQuoteIDs.size(); i++) {
2455 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(fxForwardQuoteIDs[i], asofDate_);
2456
2457 // Check that we have a valid FX forward quote
2458 if (marketQuote) {
2459 QuantLib::ext::shared_ptr<FXForwardQuote> fxForwardQuote;
2460 Handle<Quote> spotFx;
2461
2462 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::FX_FWD,
2463 "Market quote not of type FX forward.");
2464 fxForwardQuote = QuantLib::ext::dynamic_pointer_cast<FXForwardQuote>(marketQuote);
2465
2466 QL_REQUIRE(fxSpotQuote->unitCcy() == fxForwardQuote->unitCcy() &&
2467 fxSpotQuote->ccy() == fxForwardQuote->ccy(),
2468 "Currency mismatch between spot \"" << spotRateID << "\" and fwd \""
2469 << fxForwardQuoteIDs[i].first << "\"");
2470
2471 // QL expects the FX Fwd quote to be per spot, not points. If the quote is an outright, handle conversion to points convention here.
2472
2473 Handle<Quote> qlFXForwardQuote;
2474 if (fxForwardQuote->quoteType() == MarketDatum::QuoteType::PRICE) {
2475 auto m = [f = fxSpotQuote->quote()->value()](Real x) { return x - f; };
2476 qlFXForwardQuote =
2477 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(fxForwardQuote->quote(), m));
2478 } else {
2479 auto m = [p = fxConvention->pointsFactor()](Real x) { return x / p; };
2480 qlFXForwardQuote =
2481 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(fxForwardQuote->quote(), m));
2482 }
2483
2484 Natural spotDays = fxConvention->spotDays();
2485 if (matchFxFwdStringTerm(fxForwardQuote->term(), FXForwardQuote::FxFwdString::ON)) {
2486 // Overnight rate is the spread over todays fx, for settlement on t+1. We need 'todays' rate in order
2487 // to use this to determine yield curve value at t+1.
2488 // If spotDays is 0 it is spread over Spot.
2489 // If spotDays is 1 we can subtract the ON spread from spot to get todays fx.
2490 // If spotDays is 2 we also need Tomorrow next rate to get todays fx.
2491 // If spotDays is greater than 2 we can't use this.
2492 Real tnSpread = Null<Real>();
2493 Real totalSpread = 0.0;
2494 switch (spotDays) {
2495 case 0:
2496 spotFx = fxSpotQuote->quote();
2497 break;
2498 case 1: {
2499 // TODO: this isn't registeredWith the ON basis quote
2500 auto m = [f = qlFXForwardQuote->value()](Real x) { return x - f; };
2501 spotFx = Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(fxSpotQuote->quote(), m));
2502 break;
2503 }
2504 case 2: {
2505 // find the TN quote
2506 for (auto q : loader_.loadQuotes(asofDate_)) {
2507 if (q->instrumentType() == MarketDatum::InstrumentType::FX_FWD) {
2508 auto fxq = QuantLib::ext::dynamic_pointer_cast<FXForwardQuote>(q);
2509 if (fxq && fxSpotQuote->unitCcy() == fxq->unitCcy() && fxSpotQuote->ccy() == fxq->ccy() &&
2511 tnSpread = fxq->quote()->value() / fxConvention->pointsFactor();
2512 break;
2513 }
2514 }
2515 }
2516 if (tnSpread == Null<Real>()) {
2517 WLOG("YieldCurve::AddFxForwards cannot use ON rate, when SpotDays are 2 we also require the TN "
2518 "rate");
2519 continue;
2520 }
2521 totalSpread = tnSpread + qlFXForwardQuote->value();
2522 // TODO: this isn't registeredWith the ON or TN basis quote
2523 auto m2 = [totalSpread](Real x) { return x - totalSpread; };
2524 spotFx = Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m2)>>(fxSpotQuote->quote(), m2));
2525 break;
2526 }
2527 default:
2528 WLOG("YieldCurve::AddFxForwards cannot use ON rate, when SpotDays are " << spotDays <<
2529 ", only valid for SpotDays of 0, 1 or 2.");
2530 continue;
2531 }
2532 } else if (matchFxFwdStringTerm(fxForwardQuote->term(), FXForwardQuote::FxFwdString::TN)) {
2533 // TODO: this isn't registeredWith the TN basis quote
2534 auto m = [f = qlFXForwardQuote->value()](Real x) { return x - f; };
2535 spotFx = Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(fxSpotQuote->quote(), m));
2536 } else {
2537 spotFx = fxSpotQuote->quote();
2538 }
2539
2540 Period fxForwardTenor = fxFwdQuoteTenor(fxForwardQuote->term());
2541 Period fxStartTenor = fxFwdQuoteStartTenor(fxForwardQuote->term(), fxConvention);
2542 bool isFxBaseCurrencyCollateralCurrency = knownCurrency == fxSpotSourceCcy;
2543
2544 QuantLib::ext::shared_ptr<RateHelper> fxForwardHelper(new FxSwapRateHelper(
2545 qlFXForwardQuote, spotFx, fxForwardTenor, fxStartTenor.length(), fxConvention->advanceCalendar(),
2546 fxConvention->convention(), fxConvention->endOfMonth(), isFxBaseCurrencyCollateralCurrency,
2547 knownDiscountCurve));
2548
2549 instruments.push_back(fxForwardHelper);
2550 }
2551 }
2552
2553 DLOG("YieldCurve::addFXForwards() done");
2554}
virtual std::vector< QuantLib::ext::shared_ptr< MarketDatum > > loadQuotes(const QuantLib::Date &) const =0
get all quotes, TODO change the return value to std::set
QuantLib::ext::shared_ptr< FXSpotQuote > getFxSpotQuote(string spotId)
QuantLib::ext::shared_ptr< FXConvention > fxConvention
bool matchFxFwdStringTerm(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term, const FXForwardQuote::FxFwdString &fxfwdString)
QuantLib::Period fxFwdQuoteStartTenor(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term, const QuantLib::ext::shared_ptr< FXConvention > &fxConvention)
QuantLib::Period fxFwdQuoteTenor(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addCrossCcyBasisSwaps()

void addCrossCcyBasisSwaps ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 2556 of file yieldcurve.cpp.

2557 {
2558
2559 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
2560
2561 // Get the conventions associated with the segment.
2562 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2563 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2564 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
2565 QL_REQUIRE(convention->type() == Convention::Type::CrossCcyBasis, "Conventions ID does not give cross currency "
2566 "basis swap conventions.");
2567 QuantLib::ext::shared_ptr<CrossCcyBasisSwapConvention> basisSwapConvention =
2568 QuantLib::ext::dynamic_pointer_cast<CrossCcyBasisSwapConvention>(convention);
2569
2570 /* Is this yield curve on the flat side or spread side */
2571 bool onFlatSide = (currency_ == basisSwapConvention->flatIndex()->currency());
2572
2573 QuantLib::ext::shared_ptr<CrossCcyYieldCurveSegment> basisSwapSegment =
2574 QuantLib::ext::dynamic_pointer_cast<CrossCcyYieldCurveSegment>(segment);
2575
2576 /* Need to retrieve the market FX spot rate */
2577 string spotRateID = basisSwapSegment->spotRateID();
2578 QuantLib::ext::shared_ptr<FXSpotQuote> fxSpotQuote = getFxSpotQuote(spotRateID);
2579
2580 /* Create an FX spot quote from the retrieved FX spot rate */
2581 Currency fxSpotSourceCcy = parseCurrency(fxSpotQuote->unitCcy());
2582 Currency fxSpotTargetCcy = parseCurrency(fxSpotQuote->ccy());
2583
2584 /* Need to retrieve the discount curve in the other (foreign) currency. */
2585 string foreignDiscountID = basisSwapSegment->foreignDiscountCurveID();
2586 Currency foreignCcy = fxSpotSourceCcy == currency_ ? fxSpotTargetCcy : fxSpotSourceCcy;
2587 Handle<YieldTermStructure> foreignDiscountCurve;
2588 if (!foreignDiscountID.empty()) {
2589 foreignDiscountID = yieldCurveKey(foreignCcy, foreignDiscountID, asofDate_);
2590 auto it = requiredYieldCurves_.find(foreignDiscountID);
2591 if (it != requiredYieldCurves_.end()) {
2592 foreignDiscountCurve = it->second->handle();
2593 } else {
2594 QL_FAIL("The foreign discount curve, " << foreignDiscountID
2595 << ", required in the building "
2596 "of the curve, "
2597 << curveSpec_.name() << ", was not found.");
2598 }
2599 } else {
2600 // fall back on the foreign discount curve if no index given
2601 // look up the inccy discount curve - falls back to defualt if no inccy
2602 DLOG("YieldCurve::addCrossCcyBasisSwaps No discount curve provided for building curve "
2603 << curveSpec_.name() << ", looking up the inccy curve in the market.")
2604 foreignDiscountCurve = market_->discountCurve(foreignCcy.code(), Market::inCcyConfiguration);
2605 }
2606
2607 /* Need to retrieve the foreign projection curve in the other currency. If its ID is empty,
2608 set it equal to the foreign discount curve. */
2609 string foreignProjectionCurveID = basisSwapSegment->foreignProjectionCurveID();
2610 QuantLib::ext::shared_ptr<IborIndex> foreignIndex =
2611 onFlatSide ? basisSwapConvention->spreadIndex() : basisSwapConvention->flatIndex();
2612 if (foreignProjectionCurveID.empty()) {
2613 foreignIndex = foreignIndex->clone(foreignDiscountCurve);
2614 } else {
2615 foreignProjectionCurveID = yieldCurveKey(foreignCcy, foreignProjectionCurveID, asofDate_);
2616 QuantLib::ext::shared_ptr<YieldCurve> foreignProjectionCurve;
2617 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2618 it = requiredYieldCurves_.find(foreignProjectionCurveID);
2619 if (it != requiredYieldCurves_.end()) {
2620 foreignProjectionCurve = it->second;
2621 } else {
2622 QL_FAIL("The foreign projection curve, " << foreignProjectionCurveID
2623 << ", required in the building "
2624 "of the curve, "
2625 << curveSpec_.name() << ", was not found.");
2626 }
2627 foreignIndex = foreignIndex->clone(foreignProjectionCurve->handle());
2628 }
2629
2630 // If domestic index projection curve ID is not this curve.
2631 string domesticProjectionCurveID = basisSwapSegment->domesticProjectionCurveID();
2632 QuantLib::ext::shared_ptr<IborIndex> domesticIndex =
2633 onFlatSide ? basisSwapConvention->flatIndex() : basisSwapConvention->spreadIndex();
2634 if (domesticProjectionCurveID != curveConfig_->curveID() && !domesticProjectionCurveID.empty()) {
2635 domesticProjectionCurveID = yieldCurveKey(currency_, domesticProjectionCurveID, asofDate_);
2636 QuantLib::ext::shared_ptr<YieldCurve> domesticProjectionCurve;
2637 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2638 it = requiredYieldCurves_.find(domesticProjectionCurveID);
2639 if (it != requiredYieldCurves_.end()) {
2640 domesticProjectionCurve = it->second;
2641 } else {
2642 QL_FAIL("The domestic projection curve, " << domesticProjectionCurveID
2643 << ", required in the"
2644 " building of the curve, "
2645 << curveSpec_.name() << ", was not found.");
2646 }
2647 domesticIndex = domesticIndex->clone(domesticProjectionCurve->handle());
2648 }
2649
2650 /* Arrange the discount curves and indices for use in the helper */
2651 RelinkableHandle<YieldTermStructure> flatDiscountCurve;
2652 RelinkableHandle<YieldTermStructure> spreadDiscountCurve;
2653 QuantLib::ext::shared_ptr<IborIndex> flatIndex;
2654 QuantLib::ext::shared_ptr<IborIndex> spreadIndex;
2655 if (onFlatSide) {
2656 if (discountCurve_) {
2657 flatDiscountCurve.linkTo(*discountCurve_->handle());
2658 }
2659 spreadDiscountCurve.linkTo(*foreignDiscountCurve);
2660 flatIndex = domesticIndex;
2661 spreadIndex = foreignIndex;
2662 } else {
2663 flatDiscountCurve.linkTo(*foreignDiscountCurve);
2664 if (discountCurve_) {
2665 spreadDiscountCurve.linkTo(*discountCurve_->handle());
2666 }
2667 flatIndex = foreignIndex;
2668 spreadIndex = domesticIndex;
2669 }
2670
2671 Period flatTenor = basisSwapConvention->flatTenor();
2672 Period spreadTenor = basisSwapConvention->spreadTenor();
2673
2674 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2675 "XCcy basis segment does not support pillar choice " << segment->pillarChoice());
2676 auto basisSwapQuoteIDs = basisSwapSegment->quotes();
2677 for (Size i = 0; i < basisSwapQuoteIDs.size(); i++) {
2678 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(basisSwapQuoteIDs[i], asofDate_);
2679
2680 // Check that we have a valid basis swap quote
2681 if (marketQuote) {
2682 QuantLib::ext::shared_ptr<CrossCcyBasisSwapQuote> basisSwapQuote;
2683 QL_REQUIRE(marketQuote->instrumentType() == MarketDatum::InstrumentType::CC_BASIS_SWAP,
2684 "Market quote not of type cross "
2685 "currency basis swap.");
2686 basisSwapQuote = QuantLib::ext::dynamic_pointer_cast<CrossCcyBasisSwapQuote>(marketQuote);
2687
2688 // Create a cross currency basis swap helper if we do.
2689 Period basisSwapTenor = basisSwapQuote->maturity();
2690 bool isResettableSwap = basisSwapConvention->isResettable();
2691 if (!isResettableSwap) {
2692 instruments.push_back(QuantLib::ext::make_shared<CrossCcyBasisSwapHelper>(
2693 basisSwapQuote->quote(), fxSpotQuote->quote(), basisSwapConvention->settlementDays(),
2694 basisSwapConvention->settlementCalendar(), basisSwapTenor, basisSwapConvention->rollConvention(),
2695 flatIndex, spreadIndex, flatDiscountCurve, spreadDiscountCurve, basisSwapConvention->eom(),
2696 flatIndex->currency().code() != fxSpotQuote->unitCcy(), flatTenor, spreadTenor, 0.0, 1.0, 1.0,
2697 Calendar(), Calendar(), std::vector<Natural>(), std::vector<Calendar>(),
2698 basisSwapConvention->paymentLag(), basisSwapConvention->flatPaymentLag(),
2699 basisSwapConvention->includeSpread(), basisSwapConvention->lookback(),
2700 basisSwapConvention->fixingDays(), basisSwapConvention->rateCutoff(),
2701 basisSwapConvention->isAveraged(), basisSwapConvention->flatIncludeSpread(),
2702 basisSwapConvention->flatLookback(), basisSwapConvention->flatFixingDays(),
2703 basisSwapConvention->flatRateCutoff(), basisSwapConvention->flatIsAveraged(), true));
2704 } else { // the quote is for a cross currency basis swap with a resetting notional
2705 bool resetsOnFlatLeg = basisSwapConvention->flatIndexIsResettable();
2706 // the convention here is to call the resetting leg the "domestic leg",
2707 // and the constant notional leg the "foreign leg"
2708 bool spreadOnForeignCcy = resetsOnFlatLeg ? true : false;
2709 QuantLib::ext::shared_ptr<IborIndex> foreignIndex = resetsOnFlatLeg ? spreadIndex : flatIndex;
2710 Handle<YieldTermStructure> foreignDiscount = resetsOnFlatLeg ? spreadDiscountCurve : flatDiscountCurve;
2711 QuantLib::ext::shared_ptr<IborIndex> domesticIndex = resetsOnFlatLeg ? flatIndex : spreadIndex;
2712 Handle<YieldTermStructure> domesticDiscount = resetsOnFlatLeg ? flatDiscountCurve : spreadDiscountCurve;
2713 Handle<Quote> finalFxSpotQuote = fxSpotQuote->quote();
2714 // we might have to flip the given fx spot quote
2715 if (foreignIndex->currency().code() != fxSpotQuote->unitCcy()) {
2716 auto m = [](Real x) { return 1.0 / x; };
2717 finalFxSpotQuote =
2718 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(fxSpotQuote->quote(), m));
2719 }
2720 Period foreignTenor = resetsOnFlatLeg ? spreadTenor : flatTenor;
2721 Period domesticTenor = resetsOnFlatLeg ? flatTenor : spreadTenor;
2722
2723 // Use foreign and dom discount curves for projecting FX forward rates (for e.g. resetting cashflows)
2724 instruments.push_back(QuantLib::ext::make_shared<CrossCcyBasisMtMResetSwapHelper>(
2725 basisSwapQuote->quote(), finalFxSpotQuote, basisSwapConvention->settlementDays(),
2726 basisSwapConvention->settlementCalendar(), basisSwapTenor, basisSwapConvention->rollConvention(),
2727 foreignIndex, domesticIndex, foreignDiscount, domesticDiscount, Handle<YieldTermStructure>(),
2728 Handle<YieldTermStructure>(), basisSwapConvention->eom(), spreadOnForeignCcy, foreignTenor,
2729 domesticTenor, basisSwapConvention->paymentLag(), basisSwapConvention->flatPaymentLag(),
2730 basisSwapConvention->includeSpread(), basisSwapConvention->lookback(),
2731 basisSwapConvention->fixingDays(), basisSwapConvention->rateCutoff(),
2732 basisSwapConvention->isAveraged(), basisSwapConvention->flatIncludeSpread(),
2733 basisSwapConvention->flatLookback(), basisSwapConvention->flatFixingDays(),
2734 basisSwapConvention->flatRateCutoff(), basisSwapConvention->flatIsAveraged(), true));
2735 }
2736 }
2737 }
2738}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addCrossCcyFixFloatSwaps()

void addCrossCcyFixFloatSwaps ( const QuantLib::ext::shared_ptr< YieldCurveSegment > &  segment,
vector< QuantLib::ext::shared_ptr< RateHelper > > &  instruments 
)
private

Definition at line 2739 of file yieldcurve.cpp.

2740 {
2741
2742 DLOG("Adding Segment " << segment->typeID() << " with conventions \"" << segment->conventionsID() << "\"");
2743
2744 // Get the conventions associated with the segment
2745 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2746 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2747 QL_REQUIRE(convention, "No conventions found with ID: " << segment->conventionsID());
2748 QL_REQUIRE(convention->type() == Convention::Type::CrossCcyFixFloat,
2749 "Conventions ID does not give cross currency fix float swap conventions.");
2750 QuantLib::ext::shared_ptr<CrossCcyFixFloatSwapConvention> swapConvention =
2751 QuantLib::ext::dynamic_pointer_cast<CrossCcyFixFloatSwapConvention>(convention);
2752
2753 QL_REQUIRE(swapConvention->fixedCurrency() == currency_,
2754 "The yield curve currency must "
2755 << "equal the cross currency fix float swap's fixed leg currency");
2756
2757 // Cast the segment
2758 QuantLib::ext::shared_ptr<CrossCcyYieldCurveSegment> swapSegment =
2759 QuantLib::ext::dynamic_pointer_cast<CrossCcyYieldCurveSegment>(segment);
2760
2761 // Retrieve the discount curve on the float leg
2762 QuantLib::ext::shared_ptr<IborIndex> floatIndex = swapConvention->index();
2763 Currency floatLegCcy = floatIndex->currency();
2764 string foreignDiscountID = swapSegment->foreignDiscountCurveID();
2765 Handle<YieldTermStructure> floatLegDisc;
2766
2767 QuantLib::ext::shared_ptr<YieldCurve> foreignDiscountCurve;
2768 if (!foreignDiscountID.empty()) {
2769 string floatLegDiscId = yieldCurveKey(floatLegCcy, foreignDiscountID, asofDate_);
2770 auto it = requiredYieldCurves_.find(floatLegDiscId);
2771 if (it != requiredYieldCurves_.end()) {
2772 floatLegDisc = it->second->handle();
2773 } else {
2774 QL_FAIL("The foreign discount curve, " << floatLegDiscId
2775 << ", required in the building "
2776 "of the curve, "
2777 << curveSpec_.name() << ", was not found.");
2778 }
2779 } else {
2780 // fall back on the foreign discount curve if no index given
2781 // look up the inccy discount curve - falls back to defualt if no inccy
2782 DLOG("YieldCurve::addCrossCcyFixFloatSwaps No discount curve provided for building curve "
2783 << curveSpec_.name() << ", looking up the inccy curve in the market.")
2784 floatLegDisc = market_->discountCurve(floatLegCcy.code(), Market::inCcyConfiguration);
2785 }
2786
2787 // Retrieve the projection curve on the float leg. If empty, use discount curve.
2788 string floatLegProjId = swapSegment->foreignProjectionCurveID();
2789 if (floatLegProjId.empty()) {
2790 floatIndex = floatIndex->clone(floatLegDisc);
2791 } else {
2792 floatLegProjId = yieldCurveKey(floatLegCcy, floatLegProjId, asofDate_);
2793 auto it = requiredYieldCurves_.find(floatLegProjId);
2794 QL_REQUIRE(it != requiredYieldCurves_.end(), "The projection curve " << floatLegProjId
2795 << " required in the building of curve "
2796 << curveSpec_.name() << " was not found.");
2797 floatIndex = floatIndex->clone(it->second->handle());
2798 }
2799
2800 // Create the FX spot quote for the helper. The quote needs to be number of units of fixed leg
2801 // currency for 1 unit of float leg currency. We convert the market quote here if needed.
2802 string fxSpotId = swapSegment->spotRateID();
2803 QuantLib::ext::shared_ptr<FXSpotQuote> fxSpotMd = getFxSpotQuote(fxSpotId);
2804 Currency mdUnitCcy = parseCurrency(fxSpotMd->unitCcy());
2805 Currency mdCcy = parseCurrency(fxSpotMd->ccy());
2806 Handle<Quote> fxSpotQuote;
2807 if (mdUnitCcy == floatLegCcy && mdCcy == currency_) {
2808 fxSpotQuote = fxSpotMd->quote();
2809 } else if (mdUnitCcy == currency_ && mdCcy == floatLegCcy) {
2810 auto m=[](Real x) { return 1.0/x;};
2811 fxSpotQuote = Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(fxSpotMd->quote(), m));
2812 } else {
2813 QL_FAIL("The FX spot market quote " << mdUnitCcy << "/" << mdCcy << " cannot be used "
2814 << "in the building of the curve " << curveSpec_.name() << ".");
2815 }
2816
2817 // Create the helpers
2818 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2819 "XCcy fix-float basis segment does not support pillar choice " << segment->pillarChoice());
2820 auto quoteIds = swapSegment->quotes();
2821 for (Size i = 0; i < quoteIds.size(); i++) {
2822
2823 // Throws if quote not found
2824 QuantLib::ext::shared_ptr<MarketDatum> marketQuote = loader_.get(quoteIds[i], asofDate_);
2825
2826 // Check that we have a valid basis swap quote
2827 if (marketQuote) {
2828 QuantLib::ext::shared_ptr<CrossCcyFixFloatSwapQuote> swapQuote =
2829 QuantLib::ext::dynamic_pointer_cast<CrossCcyFixFloatSwapQuote>(marketQuote);
2830 QL_REQUIRE(swapQuote, "Market quote should be of type 'CrossCcyFixFloatSwapQuote'");
2831 bool isResettableSwap = swapConvention->isResettable();
2832 QuantLib::ext::shared_ptr<RateHelper> helper;
2833 if (!isResettableSwap) {
2834 // Create the helper
2835 helper = QuantLib::ext::make_shared<CrossCcyFixFloatSwapHelper>(
2836 swapQuote->quote(), fxSpotQuote, swapConvention->settlementDays(), swapConvention->settlementCalendar(),
2837 swapConvention->settlementConvention(), swapQuote->maturity(), currency_,
2838 swapConvention->fixedFrequency(), swapConvention->fixedConvention(), swapConvention->fixedDayCounter(),
2839 floatIndex, floatLegDisc, Handle<Quote>(), swapConvention->eom());
2840 } else {
2841 bool resetsOnFloatLeg = swapConvention->floatIndexIsResettable();
2842 helper = QuantLib::ext::make_shared<CrossCcyFixFloatMtMResetSwapHelper>(
2843 swapQuote->quote(), fxSpotQuote, swapConvention->settlementDays(), swapConvention->settlementCalendar(),
2844 swapConvention->settlementConvention(), swapQuote->maturity(), currency_, swapConvention->fixedFrequency(),
2845 swapConvention->fixedConvention(), swapConvention->fixedDayCounter(), floatIndex,
2846 floatLegDisc, Handle<Quote>(), swapConvention->eom(), resetsOnFloatLeg);
2847 }
2848 instruments.push_back(helper);
2849 }
2850 }
2851}
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getFxSpotQuote()

QuantLib::ext::shared_ptr< FXSpotQuote > getFxSpotQuote ( string  spotId)
private

Definition at line 2853 of file yieldcurve.cpp.

2853 {
2854 // check the spot id, if like FX/RATE/CCY/CCY we go straight to the loader first
2855 std::vector<string> tokens;
2856 split(tokens, spotId, boost::is_any_of("/"));
2857
2858 QuantLib::ext::shared_ptr<FXSpotQuote> fxSpotQuote;
2859 if (tokens.size() == 4 && tokens[0] == "FX" && tokens[1] == "RATE") {
2860 if (loader_.has(spotId, asofDate_)) {
2861 QuantLib::ext::shared_ptr<MarketDatum> fxSpotMarketQuote = loader_.get(spotId, asofDate_);
2862
2863 if (fxSpotMarketQuote) {
2864 QL_REQUIRE(fxSpotMarketQuote->instrumentType() == MarketDatum::InstrumentType::FX_SPOT,
2865 "Market quote not of type FX spot.");
2866 fxSpotQuote = QuantLib::ext::dynamic_pointer_cast<FXSpotQuote>(fxSpotMarketQuote);
2867 return fxSpotQuote;
2868 }
2869 }
2870 }
2871
2872 // Try to use triangulation otherwise
2873 string unitCcy;
2874 string ccy;
2875 Handle<Quote> spot;
2876 if (tokens.size() > 1 && tokens[0] == "FX") {
2877 if (tokens.size() == 3) {
2878 unitCcy = tokens[1];
2879 ccy = tokens[2];
2880 } else if (tokens.size() == 4 && tokens[1] == "RATE") {
2881 unitCcy = tokens[2];
2882 ccy = tokens[3];
2883 } else {
2884 QL_FAIL("Invalid FX spot ID " << spotId);
2885 }
2886 } else if (tokens.size() == 1 && spotId.size() == 6) {
2887 unitCcy = spotId.substr(0, 3);
2888 ccy = spotId.substr(3);
2889 } else {
2890 QL_FAIL("Could not find quote for ID " << spotId << " with as of date " << io::iso_date(asofDate_) << ".");
2891 }
2892 spot = fxTriangulation_.getQuote(unitCcy + ccy);
2893 fxSpotQuote =
2894 QuantLib::ext::make_shared<FXSpotQuote>(spot->value(), asofDate_, spotId, MarketDatum::QuoteType::RATE, unitCcy, ccy);
2895 return fxSpotQuote;
2896}
QuantLib::Handle< QuantLib::Quote > getQuote(const std::string &pair) const
virtual bool has(const std::string &name, const QuantLib::Date &d) const
Default implementation, returns false if get throws or returns a null pointer.
Definition: loader.cpp:53
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ asofDate_

Date asofDate_
private

Definition at line 129 of file yieldcurve.hpp.

◆ currency_

Currency currency_
private

Definition at line 130 of file yieldcurve.hpp.

◆ curveSpec_

YieldCurveSpec curveSpec_
private

Definition at line 131 of file yieldcurve.hpp.

◆ zeroDayCounter_

DayCounter zeroDayCounter_
private

Definition at line 132 of file yieldcurve.hpp.

◆ extrapolation_

bool extrapolation_
private

Definition at line 133 of file yieldcurve.hpp.

◆ discountCurve_

QuantLib::ext::shared_ptr<YieldCurve> discountCurve_
private

Definition at line 134 of file yieldcurve.hpp.

◆ loader_

const Loader& loader_
private

Definition at line 137 of file yieldcurve.hpp.

◆ h_

RelinkableHandle<YieldTermStructure> h_
private

Definition at line 138 of file yieldcurve.hpp.

◆ p_

QuantLib::ext::shared_ptr<YieldTermStructure> p_
private

Definition at line 139 of file yieldcurve.hpp.

◆ calibrationInfo_

QuantLib::ext::shared_ptr<YieldCurveCalibrationInfo> calibrationInfo_
private

Definition at line 140 of file yieldcurve.hpp.

◆ curveConfig_

QuantLib::ext::shared_ptr<YieldCurveConfig> curveConfig_
private

Definition at line 162 of file yieldcurve.hpp.

◆ curveSegments_

vector<QuantLib::ext::shared_ptr<YieldCurveSegment> > curveSegments_
private

Definition at line 163 of file yieldcurve.hpp.

◆ interpolationVariable_

InterpolationVariable interpolationVariable_
private

Definition at line 164 of file yieldcurve.hpp.

◆ interpolationMethod_

InterpolationMethod interpolationMethod_
private

Definition at line 165 of file yieldcurve.hpp.

◆ mixedInterpolationSize_

Size mixedInterpolationSize_ = 0
private

Definition at line 166 of file yieldcurve.hpp.

◆ requiredYieldCurves_

map<string, QuantLib::ext::shared_ptr<YieldCurve> > requiredYieldCurves_
private

Definition at line 167 of file yieldcurve.hpp.

◆ requiredDefaultCurves_

map<string, QuantLib::ext::shared_ptr<DefaultCurve> > requiredDefaultCurves_
private

Definition at line 168 of file yieldcurve.hpp.

◆ fxTriangulation_

const FXTriangulation& fxTriangulation_
private

Definition at line 169 of file yieldcurve.hpp.

◆ referenceData_

const QuantLib::ext::shared_ptr<ReferenceDataManager> referenceData_
private

Definition at line 170 of file yieldcurve.hpp.

◆ iborFallbackConfig_

IborFallbackConfig iborFallbackConfig_
private

Definition at line 171 of file yieldcurve.hpp.

◆ preserveQuoteLinkage_

const bool preserveQuoteLinkage_
private

Definition at line 172 of file yieldcurve.hpp.

◆ buildCalibrationInfo_

bool buildCalibrationInfo_
private

Definition at line 173 of file yieldcurve.hpp.

◆ market_

const Market* market_
private

Definition at line 174 of file yieldcurve.hpp.