28#include <ql/cashflows/fixedratecoupon.hpp>
29#include <ql/cashflows/floatingratecoupon.hpp>
41 notionals_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node,
"Notionals",
"Notional",
"startDate",
56 LOG(
"BalanceGuaranteedSwap::build() for id \"" <<
id() <<
"\" called.");
59 additionalData_[
"isdaAssetClass"] = string(
"Interest Rate");
60 additionalData_[
"isdaBaseProduct"] = string(
"Exotic");
61 additionalData_[
"isdaSubProduct"] = string(
"");
62 additionalData_[
"isdaTransaction"] = string(
"");
64 QuantLib::Schedule schedule =
makeSchedule(this->schedule());
66 std::vector<BGSTrancheData> sortedTranches(tranches());
67 std::sort(sortedTranches.begin(), sortedTranches.end(),
69 std::vector<std::vector<Real>> trancheNotionals;
71 for (
auto const& t : sortedTranches) {
72 if (t.securityId() == referenceSecurity()) {
74 "there is more than one tranche with id \"" << referenceSecurity() <<
"\"");
82 QL_REQUIRE(swap_.size() == 2,
"swap must have 2 legs");
83 QL_REQUIRE(swap_[0].currency() == swap_[1].currency(),
"swap must be single currency");
85 string ccy_str = swap_[0].currency();
88 Size fixedLegIndex, floatingLegIndex;
89 if (swap_[0].legType() ==
"Floating" && swap_[1].legType() ==
"Fixed") {
92 }
else if (swap_[1].legType() ==
"Floating" && swap_[0].legType() ==
"Fixed") {
96 QL_FAIL(
"Invalid leg types " << swap_[0].legType() <<
" + " << swap_[1].legType());
99 QuantLib::ext::shared_ptr<FixedLegData> fixedLegData =
100 QuantLib::ext::dynamic_pointer_cast<FixedLegData>(swap_[fixedLegIndex].concreteLegData());
101 QuantLib::ext::shared_ptr<FloatingLegData> floatingLegData =
102 QuantLib::ext::dynamic_pointer_cast<FloatingLegData>(swap_[floatingLegIndex].concreteLegData());
104 QL_REQUIRE(fixedLegData !=
nullptr,
"expected fixed leg data");
105 QL_REQUIRE(floatingLegData !=
nullptr,
"expected floating leg data");
107 QuantLib::ext::shared_ptr<EngineBuilder> tmp = engineFactory->builder(
"BalanceGuaranteedSwap");
108 auto builder = QuantLib::ext::dynamic_pointer_cast<FlexiSwapBGSEngineBuilderBase>(tmp);
109 QL_REQUIRE(builder,
"No BGS Builder found for \"" <<
id() <<
"\"");
123 std::string floatingIndex = floatingLegData->index();
124 DayCounter fixedDayCounter =
parseDayCounter(swap_[fixedLegIndex].dayCounter());
125 Handle<IborIndex> index =
126 engineFactory->market()->iborIndex(floatingIndex, builder->configuration(MarketContext::pricing));
127 DayCounter floatingDayCounter =
parseDayCounter(swap_[floatingLegIndex].dayCounter());
129 VanillaSwap::Type
type = swap_[fixedLegIndex].isPayer() ? VanillaSwap::Payer : VanillaSwap::Receiver;
131 auto bgSwap = QuantLib::ext::make_shared<QuantExt::BalanceGuaranteedSwap>(
135 auto fixLeg = bgSwap->leg(0);
136 auto fltLeg = bgSwap->leg(1);
139 Size legRatio = fltLeg.size() / fixLeg.size();
141 swap_[fixedLegIndex].notionals(), swap_[fixedLegIndex].notionalDates(),
fixedSchedule, 0.0);
143 swap_[floatingLegIndex].notionals(), swap_[floatingLegIndex].notionalDates(),
floatingSchedule, 0.0);
144 for (Size i = 0; i < legFixedNominal.size(); ++i) {
146 "fixed leg notional at " << i <<
" (" << legFixedNominal[i] <<
") does not match tranche notional ("
150 for (Size i = 0; i < legFloatingNominal.size(); ++i) {
153 QL_REQUIRE(
close_enough(legFloatingNominal[i], legFixedNominal[i / legRatio]),
154 "floating leg notional at " << i <<
" (" << legFloatingNominal[i]
155 <<
") does not match fixed leg notional at " << (i / legRatio) <<
" ("
156 << legFixedNominal[i / legRatio] <<
")");
161 bool hasCapsFloors =
false;
162 for (
auto const& k : caps) {
163 if (k != Null<Real>())
164 hasCapsFloors =
true;
166 for (
auto const& k : floors) {
167 if (k != Null<Real>())
168 hasCapsFloors =
true;
171 QuantLib::ext::shared_ptr<EngineBuilder> cfBuilder = engineFactory->builder(
"CapFlooredIborLeg");
172 QL_REQUIRE(cfBuilder,
"No builder found for CapFlooredIborLeg");
173 QuantLib::ext::shared_ptr<CapFlooredIborLegEngineBuilder> cappedFlooredIborBuilder =
174 QuantLib::ext::dynamic_pointer_cast<CapFlooredIborLegEngineBuilder>(cfBuilder);
175 QL_REQUIRE(cappedFlooredIborBuilder !=
nullptr,
"expected CapFlooredIborLegEngineBuilder");
176 QuantLib::ext::shared_ptr<FloatingRateCouponPricer> couponPricer =
177 cappedFlooredIborBuilder->engine(IndexNameTranslator::instance().oreName(index->name()));
178 QuantLib::setCouponPricer(fltLeg, couponPricer);
183 std::vector<Date> expiryDates;
185 Date today = Settings::instance().evaluationDate();
186 for (Size i = 0; i < fltLeg.size(); ++i) {
187 auto fltcpn = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(fltLeg[i]);
188 if (fltcpn !=
nullptr && fltcpn->fixingDate() > today && i % legRatio == 0) {
189 expiryDates.push_back(fltcpn->fixingDate());
190 auto fixcpn = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(fixLeg[i]);
191 QL_REQUIRE(fixcpn !=
nullptr,
"BalanceGuaranteedSwap Builder: expected fixed rate coupon");
192 strikes.push_back(fixcpn->rate() - fltcpn->spread());
198 bgSwap->setPricingEngine(
199 builder->engine(
id(), referenceSecurity(), ccy_str, expiryDates, bgSwap->maturityDate(),
strikes));
200 setSensitivityTemplate(*builder);
206 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(bgSwap);
208 npvCurrency_ = ccy_str;
210 notionalCurrency_ = ccy_str;
211 legCurrencies_ = vector<string>(2, ccy_str);
212 legs_ = {fixLeg, fltLeg};
213 legPayers_ = {swap_[fixedLegIndex].isPayer(), swap_[floatingLegIndex].isPayer()};
214 maturity_ = bgSwap->maturityDate();
217void BalanceGuaranteedSwap::fromXML(
XMLNode* node) {
218 Trade::fromXML(node);
219 XMLNode* swapNode = XMLUtils::getChildNode(node,
"BalanceGuaranteedSwapData");
220 QL_REQUIRE(swapNode,
"BalanceGuaranteedSwap::fromXML(): BalanceGuaranteedSwapData not found");
222 referenceSecurity_ = XMLUtils::getChildValue(swapNode,
"ReferenceSecurity");
224 XMLNode* tranchesNode = XMLUtils::getChildNode(swapNode,
"Tranches");
225 QL_REQUIRE(tranchesNode,
"BalanceGuaranteedSwap::fromXML(): Tranches node not found");
227 vector<XMLNode*> trancheNodes = XMLUtils::getChildrenNodes(tranchesNode,
"Tranche");
228 for (Size i = 0; i < trancheNodes.size(); ++i) {
231 tranches_.push_back(td);
234 XMLNode* scheduleNode = XMLUtils::getChildNode(tranchesNode,
"ScheduleData");
235 schedule_.fromXML(scheduleNode);
238 vector<XMLNode*> nodes = XMLUtils::getChildrenNodes(swapNode,
"LegData");
239 for (Size i = 0; i < nodes.size(); ++i) {
247 XMLNode* node = Trade::toXML(doc);
248 XMLUtils::addChild(doc, node,
"ReferenceSecurity", referenceSecurity_);
251 XMLUtils::appendNode(node, tranchesNode);
252 for (Size i = 0; i < tranches_.size(); ++i) {
253 XMLUtils::appendNode(tranchesNode, tranches_[i].toXML(doc));
256 XMLUtils::appendNode(tranchesNode, schedule_.toXML(doc));
259 XMLUtils::appendNode(node, swapNode);
260 for (Size i = 0; i < swap_.size(); ++i)
261 XMLUtils::appendNode(swapNode, swap_[i].toXML(doc));
Balance Guaranteed Swap data model and serialization.
builder that returns an engine to price capped floored ibor legs
BusinessDayConvention paymentConvention() const
const Schedule & fixedSchedule() const
const Schedule & floatingSchedule() const
VanillaSwap::Type type() const
const Size referencedTranche() const
const std::vector< Real > & fixedRate() const
Serializable Tranche for use in Balance Guaranteed Swaps.
std::vector< std::string > notionalDates_
std::vector< QuantLib::Real > notionals_
virtual void fromXML(ore::data::XMLNode *node) override
virtual ore::data::XMLNode * toXML(ore::data::XMLDocument &doc) const override
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &) override
Serializable object holding leg data.
virtual void fromXML(XMLNode *node) override
Small XML Document wrapper class.
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
static void checkNode(XMLNode *n, const string &expectedName)
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
static void addChildrenWithOptionalAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
static int getChildValueAsInt(XMLNode *node, const string &name, bool mandatory=false, int defaultValue=0)
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
Logic for calculating required fixing dates on legs.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Real parseReal(const string &s)
Convert text to Real.
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
translates between QuantLib::Index::name() and ORE names
Classes and functions for log message handling.
#define LOG(text)
Logging Macro (Level = Notice)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
vector< T > buildScheduledVectorNormalised(const vector< T > &values, const vector< string > &dates, const Schedule &schedule, const T &defaultValue, const bool checkAllValuesAppearInResult=false)
Real currentNotional(const Leg &leg)
void addToRequiredFixings(const QuantLib::Leg &leg, const QuantLib::ext::shared_ptr< FixingDateGetter > &fixingDateGetter)
Schedule makeSchedule(const ScheduleDates &data)
Serializable Credit Default Swap.