54 {
55
56 LOG(
"BalanceGuaranteedSwap::build() for id \"" <<
id() <<
"\" called.");
57
58
63
65
66 std::vector<BGSTrancheData> sortedTranches(
tranches());
67 std::sort(sortedTranches.begin(), sortedTranches.end(),
68 [](const BGSTrancheData& x, const BGSTrancheData& y) { return x.seniority() < y.seniority(); });
69 std::vector<std::vector<Real>> trancheNotionals;
71 for (auto const& t : sortedTranches) {
76 }
78 ++counter;
79 }
81
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");
84
85 string ccy_str =
swap_[0].currency();
87
88 Size fixedLegIndex, floatingLegIndex;
89 if (swap_[0].legType() == "Floating" && swap_[1].legType() == "Fixed") {
90 floatingLegIndex = 0;
91 fixedLegIndex = 1;
92 } else if (swap_[1].legType() == "Floating" && swap_[0].legType() == "Fixed") {
93 floatingLegIndex = 1;
94 fixedLegIndex = 0;
95 } else {
96 QL_FAIL("Invalid leg types " << swap_[0].legType() << " + " << swap_[1].legType());
97 }
98
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());
103
104 QL_REQUIRE(fixedLegData != nullptr, "expected fixed leg data");
105 QL_REQUIRE(floatingLegData != nullptr, "expected floating leg data");
106
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() << "\"");
110
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;
130
131 auto bgSwap = QuantLib::ext::make_shared<QuantExt::BalanceGuaranteedSwap>(
134
135 auto fixLeg = bgSwap->leg(0);
136 auto fltLeg = bgSwap->leg(1);
137
138
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 ("
149 }
150 for (Size i = 0; i < legFloatingNominal.size(); ++i) {
151
152
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] << ")");
157 }
158
159
160
161 bool hasCapsFloors = false;
162 for (auto const& k : caps) {
163 if (k != Null<Real>())
164 hasCapsFloors = true;
165 }
166 for (auto const& k : floors) {
167 if (k != Null<Real>())
168 hasCapsFloors = true;
169 }
170 if (hasCapsFloors) {
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);
179 }
180
181
182
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());
193 }
194 }
195
196
197
198 bgSwap->setPricingEngine(
199 builder->engine(
id(),
referenceSecurity(), ccy_str, expiryDates, bgSwap->maturityDate(), strikes));
201
202
204
205
206 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(bgSwap);
207
212 legs_ = {fixLeg, fltLeg};
215}
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
const std::string & referenceSecurity() const
const ore::data::ScheduleData schedule() const
const std::vector< BGSTrancheData > & tranches() const
std::vector< bool > legPayers_
std::vector< string > legCurrencies_
std::vector< QuantLib::Leg > legs_
void setSensitivityTemplate(const EngineBuilder &builder)
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
std::map< std::string, boost::any > additionalData_
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
#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)