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;
70 Size referencedTranche = Null<Size>(), counter = 0;
71 for (auto const& t : sortedTranches) {
73 QL_REQUIRE(referencedTranche == Null<Size>(),
75 referencedTranche = counter;
76 }
78 ++counter;
79 }
80 QL_REQUIRE(referencedTranche != Null<Size>(), "referenced tranche not found");
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
113 vector<Real> fixedRate =
116 floatingSchedule, 0.0);
118 floatingSchedule, 1.0);
120 floatingSchedule, (Real)Null<Real>());
122 floatingSchedule, (Real)Null<Real>());
123 std::string floatingIndex = floatingLegData->index();
125 Handle<IborIndex> index =
129 VanillaSwap::Type type =
swap_[fixedLegIndex].isPayer() ? VanillaSwap::Payer : VanillaSwap::Receiver;
130
131 auto bgSwap = QuantLib::ext::make_shared<QuantExt::BalanceGuaranteedSwap>(
132 type, trancheNotionals,
schedule, referencedTranche, fixedSchedule, fixedRate, fixedDayCounter,
133 floatingSchedule, *index, gearings, spreads, caps, floors, floatingDayCounter, paymentConvention);
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) {
145 QL_REQUIRE(
close_enough(bgSwap->trancheNominal(referencedTranche, fixedSchedule[i]), legFixedNominal[i]),
146 "fixed leg notional at " << i << " (" << legFixedNominal[i] << ") does not match tranche notional ("
147 << bgSwap->trancheNominal(referencedTranche, fixedSchedule[i])
148 << "), referenced tranche is " << referencedTranche);
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}
const ore::data::ScheduleData schedule() const
std::vector< bool > legPayers_
std::vector< string > legCurrencies_
std::vector< QuantLib::Leg > legs_
void setSensitivityTemplate(const EngineBuilder &builder)
RequiredFixings requiredFixings_
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)