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);
92 DayCounter fixedDayCounter =
parseDayCounter(swap_[fixedLegIndex].dayCounter());
93 Handle<IborIndex> index =
94 engineFactory->market()->iborIndex(floatingIndex_, builder->configuration(MarketContext::pricing));
95 DayCounter floatingDayCounter =
parseDayCounter(swap_[floatingLegIndex].dayCounter());
97 VanillaSwap::Type
type =
swap_[fixedLegIndex].isPayer() ? VanillaSwap::Payer : VanillaSwap::Receiver;
98
101
102
103
105 "can not have lower notional bounds and exercise dates / types / values specified at the same time");
106
107
108
110 lowerNotionalBounds =
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
129
130
131 Date previousExerciseDate = Null<Date>();
134 QL_REQUIRE(exerciseValues_[i] > 0.0 ||
close_enough(exerciseValues_[i], 0.0),
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
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 }
151 if (exerciseTypes_[i] == "ReductionUpToLowerBound") {
152 for (Size j = exerciseIdx; j < lowerNotionalBounds.size(); ++j) {
153 lowerNotionalBounds[j] = std::min(lowerNotionalBounds[j], exerciseValues_[i]);
154 }
155 } else if (exerciseTypes_[i] == "ReductionByAbsoluteAmount" ||
156 exerciseTypes_[i] == "ReductionUpToAbsoluteAmount") {
157
158
159
160 for (Size j = exerciseIdx; j < lowerNotionalBounds.size(); ++j) {
161 lowerNotionalBounds[j] = std::max(lowerNotionalBounds[j] - exerciseValues_[i], 0.0);
162 }
163 } else {
164 QL_FAIL("exercise type '" << exerciseTypes_[i]
165 << "' unknown, expected ReductionUpToLowerBound, ReductionByAbsoluteAmount, "
166 "ReductionUpToAbsoluteAmount");
167 }
168 }
169 }
170
171 DLOG(
"fixedPeriod#,notional,lowerNotionalBound,canBeReduced");
172 for (Size i = 0; i < lowerNotionalBounds.size(); ++i) {
173 DLOG(i <<
"," <<
fixedNominal.at(i) <<
"," << lowerNotionalBounds[i] <<
"," << std::boolalpha
175 }
176
177
178
180
181 auto flexiSwap = QuantLib::ext::make_shared<QuantExt::FlexiSwap>(
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}
const std::vector< bool > & notionalCanBeDecreased() const
const std::vector< Real > & fixedNominal() const
BusinessDayConvention paymentConvention() const
const Schedule & fixedSchedule() const
const Schedule & floatingSchedule() const
VanillaSwap::Type type() const
const std::vector< Real > & fixedRate() const
std::string floatingIndex_
Store the name of the floating leg index.
const std::vector< double > & lowerNotionalBounds() const
const std::string & optionLongShort() 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_
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)