30#include <ql/instruments/bond.hpp>
31#include <ql/pricingengines/bond/bondfunctions.hpp>
38std::map<std::string, QuantLib::ext::shared_ptr<Security>>
40 const QuantLib::ext::shared_ptr<CurveConfigurations>&
curveConfigs,
const Loader& loader,
41 const bool continueOnError,
const std::string& excludeRegex) {
42 std::regex excludePattern;
43 if (!excludeRegex.empty())
44 excludePattern = std::regex(excludeRegex);
46 std::map<std::string, QuantLib::ext::shared_ptr<Security>> securities;
47 for (
const auto& configuration : params->configurations()) {
48 LOG(
"identify securities that require a spread imply for configuration " << configuration.first);
52 for (
const auto& it : params->curveSpecs(configuration.first)) {
53 auto securityspec = QuantLib::ext::dynamic_pointer_cast<SecuritySpec>(
parseCurveSpec(it));
55 std::string securityId = securityspec->securityID();
56 if (std::regex_match(securityId, excludePattern)) {
57 DLOG(
"skip " << securityId <<
" because it matches the exclude regex (" << excludeRegex <<
")");
61 if (
curveConfigs->securityConfig(securityId)->spreadQuote().empty()) {
62 DLOG(
"no spread quote configuraed, skip security " << securityId);
65 QuantLib::ext::shared_ptr<Security> security;
67 security = QuantLib::ext::make_shared<Security>(asof, *securityspec, loader, *
curveConfigs);
68 }
catch (
const std::exception& e) {
69 if (continueOnError) {
71 "Will continue the calculations with a zero security spread: " +
72 std::string(e.what()))
76 QL_FAIL(
"Cannot process security " << securityId <<
" " << e.what());
79 if (security->spread().empty()) {
80 if (!security->price().empty()) {
81 LOG(
"empty spread, non-empty price: will imply spread for security " << securityId);
82 securities[securityId] = security;
84 DLOG(
"empty spread, empty price: spread will be left empty for security " << securityId);
86 "No security spread or bond price to imply the spread is "
87 "given. Will proceed assuming a zero spread.")
91 if (!security->price().empty()) {
92 WLOG(
"non-empty spread, non-empty price, will not overwrite existing spread for security "
95 DLOG(
"non-empty spread, empty price, do nothing for security " << securityId);
99 WLOG(
"do not have security curve config for '" << securityId
100 <<
"' - skip this security in spread imply");
105 LOG(
"got " << securities.size() <<
" securities");
109QuantLib::ext::shared_ptr<Loader>
111 const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager,
112 const QuantLib::ext::shared_ptr<Market>& market,
113 const QuantLib::ext::shared_ptr<EngineData>& engineData,
116 LOG(
"run bond spread imply");
118 Settings::instance().evaluationDate() = market->asofDate();
121 map<MarketContext, string> configurations;
123 auto spreadImplyMarket = QuantLib::ext::make_shared<BondSpreadImplyMarket>(market);
124 auto edCopy = QuantLib::ext::make_shared<EngineData>(*engineData);
125 edCopy->globalParameters()[
"RunType"] =
"BondSpreadImply";
126 auto engineFactory = QuantLib::ext::make_shared<EngineFactory>(edCopy, spreadImplyMarket, configurations,
127 referenceDataManager, iborFallbackConfig);
131 std::map<std::string, QuantLib::ext::shared_ptr<MarketDatum>> generatedSpreads;
132 for (
auto const& sec : securities) {
133 auto storedSpread = generatedSpreads.find(sec.first);
134 if (storedSpread == generatedSpreads.end()) {
136 auto impliedSpread = QuantLib::ext::make_shared<SecuritySpreadQuote>(
137 implySpread(sec.first, sec.second->price()->value(), referenceDataManager, engineFactory,
138 spreadImplyMarket->spreadQuote(sec.first), configuration),
139 market->asofDate(),
"BOND/YIELD_SPREAD/" + sec.first, sec.first);
140 generatedSpreads[sec.first] = impliedSpread;
141 LOG(
"spread imply succeded for security " << sec.first <<
", got " << std::setprecision(10)
142 << impliedSpread->quote()->value());
143 }
catch (
const std::exception& e) {
146 "bond spread imply failed (target price = " + std::to_string(sec.second->price()->value()) +
147 "). Will continue the calculations with a zero security spread.",
155 auto loader = QuantLib::ext::make_shared<InMemoryLoader>();
157 for (
auto const& s : generatedSpreads) {
158 DLOG(
"adding market datum " << s.second->name() <<
" (" << s.second->quote()->value() <<
") for asof "
159 << market->asofDate() <<
" to loader");
160 loader->add(market->asofDate(), s.second->name(), s.second->quote()->value());
163 LOG(
"bond spread imply finished.");
168 const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager,
169 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory,
170 const QuantLib::ext::shared_ptr<SimpleQuote>& spreadQuote,
const std::string& configuration) {
174 QL_REQUIRE(referenceDataManager,
"no reference data manager given");
176 auto b = BondFactory::instance().build(engineFactory, referenceDataManager, securityId);
177 Real adj = b.priceQuoteMethod == QuantExt::BondIndex::PriceQuoteMethod::CurrencyPerUnit
178 ? 1.0 / b.priceQuoteBaseValue
181 Real inflationFactor = b.inflationFactor();
183 DLOG(
"implySpread for securityId " << securityId <<
":");
184 DLOG(
"settlement date = " << QuantLib::io::iso_date(b.bond->settlementDate()));
185 DLOG(
"market quote = " << cleanPrice);
186 DLOG(
"accrueds = " << b.bond->accruedAmount());
187 DLOG(
"inflation factor = " << inflationFactor);
188 DLOG(
"price quote method adj = " << adj);
189 DLOG(
"effective market price = " << cleanPrice * inflationFactor * adj);
191 auto targetFunction = [&b, spreadQuote, cleanPrice, adj, inflationFactor](
const Real& s) {
192 spreadQuote->setValue(s);
193 if (b.modelBuilder !=
nullptr)
194 b.modelBuilder->recalibrate();
195 Real c = b.bond->cleanPrice() / 100.0;
196 TLOG(
"--> spread imply: trying s = " << s <<
" yields clean price " << c);
197 return c - cleanPrice * inflationFactor * adj;
202 if (QuantLib::close_enough(b.bond->cleanPrice(), 0.0)) {
203 DLOG(
"bond has a theoretical clean price of zero (no outstanding flows as of settlement date) -> skip spread "
204 "imply and continue with zero security spread.");
211 Real s = brent.solve(targetFunction, 1E-8, 0.0, 0.001);
213 DLOG(
"theoretical pricing = " << b.bond->cleanPrice() / 100.0);
Bond trade data model and serialization.
bond spread imply utility
market that can be used to imply bond spreads
static QuantLib::ext::shared_ptr< Loader > implyBondSpreads(const std::map< std::string, QuantLib::ext::shared_ptr< Security > > &securities, const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager, const QuantLib::ext::shared_ptr< Market > &market, const QuantLib::ext::shared_ptr< EngineData > &engineData, const std::string &configuration, const IborFallbackConfig &iborFallbackConfig)
static Real implySpread(const std::string &securityId, const Real cleanPrice, const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const QuantLib::ext::shared_ptr< SimpleQuote > &spreadQuote, const std::string &configuration)
helper function that computes a single implied spread for a bond
static std::map< std::string, QuantLib::ext::shared_ptr< Security > > requiredSecurities(const Date &asof, const QuantLib::ext::shared_ptr< TodaysMarketParameters > ¶ms, const QuantLib::ext::shared_ptr< CurveConfigurations > &curveConfigs, const Loader &loader, const bool continueOnError=false, const std::string &excludeRegex=std::string())
void log() const
generate Boost log record to pass to corresponding sinks
Market data loader base class.
Utility class for Structured Curve errors, contains the curve ID.
QuantLib::ext::shared_ptr< CurveSpec > parseCurveSpec(const string &s)
function to convert a string into a curve spec
#define LOG(text)
Logging Macro (Level = Notice)
#define DLOG(text)
Logging Macro (Level = Debug)
#define WLOG(text)
Logging Macro (Level = Warning)
#define TLOG(text)
Logging Macro (Level = Data)
Serializable Credit Default Swap.
Reference data model and serialization.
A wrapper class for holding Bond Spread quotes.
Error for market data or curve.
vector< string > curveConfigs