36 {
37
38 LOG(
"FlexiSwap::build() for id \"" <<
id() <<
"\" called.");
39
40
45
46 QL_REQUIRE(
swap_.size() == 2,
"swap must have 2 legs");
47 QL_REQUIRE(
swap_[0].currency() ==
swap_[1].currency(),
"swap must be single currency");
48
49 string ccy_str =
swap_[0].currency();
51
52 Size fixedLegIndex, floatingLegIndex;
53 if (
swap_[0].legType() ==
"Floating" &&
swap_[1].legType() ==
"Fixed") {
54 floatingLegIndex = 0;
55 fixedLegIndex = 1;
56 }
else if (
swap_[1].legType() ==
"Floating" &&
swap_[0].legType() ==
"Fixed") {
57 floatingLegIndex = 1;
58 fixedLegIndex = 0;
59 } else {
60 QL_FAIL(
"Invalid leg types " <<
swap_[0].legType() <<
" + " <<
swap_[1].legType());
61 }
62
63 QuantLib::ext::shared_ptr<FixedLegData> fixedLegData =
64 QuantLib::ext::dynamic_pointer_cast<FixedLegData>(
swap_[fixedLegIndex].concreteLegData());
65 QuantLib::ext::shared_ptr<FloatingLegData> floatingLegData =
66 QuantLib::ext::dynamic_pointer_cast<FloatingLegData>(
swap_[floatingLegIndex].concreteLegData());
67
68 QL_REQUIRE(fixedLegData != nullptr, "expected fixed leg data");
69 QL_REQUIRE(floatingLegData != nullptr, "expected floating leg data");
70
71 QuantLib::ext::shared_ptr<EngineBuilder> tmp = engineFactory->builder("FlexiSwap");
72 auto builder = QuantLib::ext::dynamic_pointer_cast<FlexiSwapBGSEngineBuilderBase>(tmp);
73 QL_REQUIRE(builder, "No Flexi-Swap Builder found for \"" << id() << "\"");
74
78 swap_[fixedLegIndex].notionals(),
swap_[fixedLegIndex].notionalDates(), fixedSchedule, 0.0);
80 swap_[floatingLegIndex].notionals(),
swap_[floatingLegIndex].notionalDates(), floatingSchedule, 0.0);
81 vector<Real> fixedRate =
84 floatingSchedule, 0.0);
86 floatingSchedule, 1.0);
88 floatingSchedule, (Real)Null<Real>());
90 floatingSchedule, (Real)Null<Real>());
93 Handle<IborIndex> index =
97 VanillaSwap::Type type =
swap_[fixedLegIndex].isPayer() ? VanillaSwap::Payer : VanillaSwap::Receiver;
98
100 std::vector<bool> notionalCanBeDecreased(fixedNominal.size(), true);
101
102
103
105 "can not have lower notional bounds and exercise dates / types / values specified at the same time");
106
107
108
112 DLOG(
"optionality is given by lower notional bounds");
113 }
114
115
116
117
118
119
120
122 DLOG(
"optionality is given by exercise dates, types, values");
123
124
125
126
127
128 notionalCanBeDecreased = std::vector<bool>(fixedNominal.size(), false);
129
130
131 Date previousExerciseDate = Null<Date>();
135 "exercise value #" << i <<
" (" <<
exerciseValues_[i] <<
") must be non-negative");
136 QL_REQUIRE(i == 0 || previousExerciseDate < d, "exercise dates must be strictly increasing, got "
137 << QuantLib::io::iso_date(previousExerciseDate)
138 << " and " << QuantLib::io::iso_date(d) << " as #" << i
139 << " and #" << i + 1);
140 previousExerciseDate = d;
141
142 Size exerciseIdx = std::lower_bound(fixedSchedule.dates().begin(), fixedSchedule.dates().end(), d) -
143 fixedSchedule.dates().begin();
144 if (exerciseIdx >= fixedSchedule.dates().size() - 1) {
145 DLOG(
"exercise date "
146 << QuantLib::io::iso_date(d)
147 << " ignored since there is no whole fixed leg period with accrual start >= exercise date");
148 continue;
149 }
150 notionalCanBeDecreased[exerciseIdx] = true;
154 }
157
158
159
162 }
163 } else {
165 << "' unknown, expected ReductionUpToLowerBound, ReductionByAbsoluteAmount, "
166 "ReductionUpToAbsoluteAmount");
167 }
168 }
169 }
170
171 DLOG(
"fixedPeriod#,notional,lowerNotionalBound,canBeReduced");
174 << notionalCanBeDecreased[i]);
175 }
176
177
178
180
181 auto flexiSwap = QuantLib::ext::make_shared<QuantExt::FlexiSwap>(
182 type, fixedNominal, floatNominal, fixedSchedule, fixedRate, fixedDayCounter, floatingSchedule, *index, gearings,
184 paymentConvention);
185
186 auto fixLeg = flexiSwap->leg(0);
187 auto fltLeg = flexiSwap->leg(1);
188
189
190
191 bool hasCapsFloors = false;
192 for (auto const& k : caps) {
193 if (k != Null<Real>())
194 hasCapsFloors = true;
195 }
196 for (auto const& k : floors) {
197 if (k != Null<Real>())
198 hasCapsFloors = true;
199 }
200 if (hasCapsFloors) {
201 QuantLib::ext::shared_ptr<EngineBuilder> cfBuilder = engineFactory->builder("CapFlooredIborLeg");
202 QL_REQUIRE(cfBuilder, "No builder found for CapFlooredIborLeg");
203 QuantLib::ext::shared_ptr<CapFlooredIborLegEngineBuilder> cappedFlooredIborBuilder =
204 QuantLib::ext::dynamic_pointer_cast<CapFlooredIborLegEngineBuilder>(cfBuilder);
205 QL_REQUIRE(cappedFlooredIborBuilder != nullptr, "expected CapFlooredIborLegEngineBuilder");
206 QuantLib::ext::shared_ptr<FloatingRateCouponPricer> couponPricer =
207 cappedFlooredIborBuilder->engine(IndexNameTranslator::instance().oreName(index->name()));
208 QuantLib::setCouponPricer(fltLeg, couponPricer);
209 }
210
211
212 std::vector<Date> expiryDates;
214 Date today = Settings::instance().evaluationDate();
215 Size legRatio = fltLeg.size() / fixLeg.size();
216 for (Size i = 0; i < fltLeg.size(); ++i) {
217 auto fltcpn = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(fltLeg[i]);
218 if (fltcpn != nullptr && fltcpn->fixingDate() > today && i % legRatio == 0) {
219 expiryDates.push_back(fltcpn->fixingDate());
220 auto fixcpn = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(fixLeg[i / legRatio]);
221 QL_REQUIRE(fixcpn != nullptr, "FlexiSwap Builder: expected fixed rate coupon");
222 strikes.push_back(fixcpn->rate() - fltcpn->spread());
223 }
224 }
225
226
227
228 flexiSwap->setPricingEngine(
229 builder->engine(id(), "", index.empty() ? ccy_str : IndexNameTranslator::instance().oreName(index->name()),
230 expiryDates, flexiSwap->maturityDate(), strikes));
232
233
234 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(flexiSwap);
235
240 legs_ = {fixLeg, fltLeg};
244}
std::string floatingIndex_
Store the name of the floating leg index.
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_
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
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)
#define DLOG(text)
Logging Macro (Level = Debug)
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)