32 {
33
35
36 QL_REQUIRE(
legData_.size() == 2,
"Expected exactly two legs, got " <<
legData_.size());
37
38 std::set<std::string> legTypes;
40 legTypes.insert(ld.legType());
41 }
42
43 QL_REQUIRE(legTypes.size() == 2 && *legTypes.begin() == "Fixed" && *std::next(legTypes.begin(), 1) == "Floating",
44 "Expected one 'Floating' and one 'Fixed' type");
45
48
49 auto floatAddData = QuantLib::ext::dynamic_pointer_cast<FloatingLegData>(floatLegData.concreteLegData());
50 auto fixedAddData = QuantLib::ext::dynamic_pointer_cast<FixedLegData>(fixedLegData.concreteLegData());
51
52 QL_REQUIRE(floatAddData, "Internal error: could not cast to float additional data");
53 QL_REQUIRE(fixedAddData, "Internal error: could not cast to fixed additional data");
54
55 QL_REQUIRE(fixedLegData.isPayer() != floatLegData.isPayer(), "Expected one payer and one receiver leg");
56
57 if (fixedLegData.isPayer())
58 numbers_.emplace_back(
"Number",
"Payer",
"-1");
59 else
60 numbers_.emplace_back(
"Number",
"Payer",
"1");
61
62 QL_REQUIRE(fixedLegData.notionals().size() == 1,
63 "Expected one notional on fixed leg, got " << fixedLegData.notionals().size());
64 QL_REQUIRE(floatLegData.notionals().size() == 1,
65 "Expected one notional on floating leg, got " << floatLegData.notionals().size());
66 QL_REQUIRE(QuantLib::close_enough(fixedLegData.notionals().front(), floatLegData.notionals().front()),
67 "Expected same notional on fixed and floating leg, got " << fixedLegData.notionals().front() << " and "
68 << floatLegData.notionals().front());
69
70 QL_REQUIRE(fixedAddData->rates().size() == 1,
71 "Expected one rate on fixed leg, got " << fixedAddData->rates().size());
72 QL_REQUIRE(floatAddData->spreads().size() <= 1,
73 "Expected at most one spread on floating leg, got " << floatAddData->spreads().size());
74 QL_REQUIRE(floatAddData->gearings().size() <= 1,
75 "Expected at most one gearing on floating leg, got " << floatAddData->gearings().size());
76
77 numbers_.emplace_back(
"Number",
"Notional", std::to_string(fixedLegData.notionals().front()));
78 numbers_.emplace_back(
"Number",
"FixedRate", std::to_string(fixedAddData->rates().front()));
79 numbers_.emplace_back(
"Number",
"FloatMargin",
80 floatAddData->spreads().empty() ? "0.0" : std::to_string(floatAddData->spreads().front()));
81 numbers_.emplace_back(
"Number",
"FloatGearing",
82 floatAddData->gearings().empty() ? "1.0" : std::to_string(floatAddData->gearings().front()));
83
85 Size fixingShift = floatAddData->fixingDays() == Null<Size>() ? index->fixingDays() : floatAddData->fixingDays();
86 std::string fixingCalendar = index->fixingCalendar().name();
87 events_.emplace_back(
"FloatFixingSchedule",
"FloatSchedule",
"-" + std::to_string(fixingShift) +
"D", fixingCalendar,
"P");
88
89 indices_.emplace_back(
"Index",
"FloatIndex", floatAddData->index());
90
91 std::string floatDayCounter =
92 floatLegData.dayCounter().empty() ? index->dayCounter().name() : floatLegData.dayCounter();
93 std::string fixedDayCounter = fixedLegData.dayCounter().empty() ? floatDayCounter : fixedLegData.dayCounter();
94
95 daycounters_.emplace_back(
"Daycounter",
"FixedDayCounter", fixedDayCounter);
96 daycounters_.emplace_back(
"Daycounter",
"FloatDayCounter", floatDayCounter);
97
98 events_.emplace_back(
"FixedSchedule", fixedLegData.schedule());
99 events_.emplace_back(
"FloatSchedule", floatLegData.schedule());
100
101 QL_REQUIRE(!fixedLegData.currency().empty() && fixedLegData.currency() == floatLegData.currency(),
102 "Both legs must have the same currency, got '" << fixedLegData.currency() << "' on the fixed leg and '"
103 << floatLegData.currency() << "' on the floating leg.");
104 QL_REQUIRE(fixedLegData.currency() == index->currency().code(),
105 "Leg currency '" << fixedLegData.currency() << "' must match float index currency '"
106 << index->currency().code() << "' of index '" << index->name() << "'");
107
108 currencies_.emplace_back(
"Currency",
"PayCurrency", fixedLegData.currency());
109
112
114 if (barrierType == QuantLib::Barrier::DownOut)
115 numbers_.emplace_back(
"Number",
"KnockOutType",
"3");
116 else if (barrierType == QuantLib::Barrier::UpOut)
117 numbers_.emplace_back(
"Number",
"KnockOutType",
"4");
118 else {
119 QL_FAIL(
"Expected BarrierType 'DownAndOut' or 'UpAndOut', got '" <<
barrierData_.
type());
120 }
121
123 QL_REQUIRE(
barrierData_.
levels().front().value() != Null<Real>(),
"No barrier level specified.");
124
126
128
129
130
132
133
134
135 bool isIborBased = QuantLib::ext::dynamic_pointer_cast<QuantLib::OvernightIndex>(index) == nullptr;
136
137
138
139
140
141
142 std::string mc_script = std::string(
143 "REQUIRE KnockOutType == 3 OR KnockOutType == 4;\n"
144 "NUMBER Alive[SIZE(FloatFixingSchedule)], aliveInd, lastFixedIndex, lastFloatIndex, d, j, fix;\n"
145
146 "aliveInd = 1;\n"
147
148 "FOR d IN (1, SIZE(FloatFixingSchedule), 1) DO\n"
149
150 " FOR j IN (lastFixedIndex + 1, SIZE(FixedSchedule) - 1, 1) DO\n"
151 " IF FixedSchedule[j] < FloatFixingSchedule[d] OR d == SIZE(FloatFixingSchedule) THEN\n"
152 " value = value + LOGPAY( Payer * aliveInd * Notional * FixedRate * dcf( FixedDayCounter, FixedSchedule[j], FixedSchedule[j+1]),\n"
153 " FixedSchedule[j], FixedSchedule[j+1], PayCurrency, 1, FixedLegCoupon );\n"
154 " lastFixedIndex = j;\n"
155 " END;\n"
156 " END;\n"
157
158 " FOR j IN (lastFloatIndex + 1, SIZE(FloatSchedule) - 1, 1) DO\n"
159 " IF FloatSchedule[j] < FloatFixingSchedule[d] OR d == SIZE(FloatFixingSchedule) THEN\n"
160 " value = value + LOGPAY( (-Payer) * aliveInd * Notional *\n") + std::string(
161 isIborBased ?
162 " ( FloatGearing * FloatIndex(FloatFixingSchedule[j]) + FloatMargin)\n"
163 :
164 " FWDCOMP(FloatIndex, FloatFixingSchedule[j], FloatSchedule[j], FloatSchedule[j+1], FloatMargin, FloatGearing)\n") + std::string(
165
166 " * dcf( FloatDayCounter, FloatSchedule[j], FloatSchedule[j+1]),\n"
167 " FloatFixingSchedule[j], FloatSchedule[j+1], PayCurrency, 2, FloatingLegCoupon );\n"
168 " lastFloatIndex = j;\n"
169 " END;\n"
170 " END;\n"
171
172 " IF d < SIZE(FloatFixingSchedule) THEN\n"
173 " fix = FloatIndex(FloatFixingSchedule[d]);\n"
174 " IF FloatFixingSchedule[d] >= BarrierStartDate AND\n"
175 " {{KnockOutType == 3 AND fix <= KnockOutLevel} OR\n"
176 " {KnockOutType == 4 AND fix >= KnockOutLevel}} THEN\n"
177 " aliveInd = 0;\n"
178 " END;\n"
179 " Alive[d] = aliveInd;\n"
180 " END;\n"
181
182 "END;\n");
183
184
185
186 script_[
""] = ScriptedTradeScriptData(
187 mc_script, "value", {{"currentNotional", "Notional"}, {"notionalCurrency", "PayCurrency"}, {"Alive", "Alive"}},
188 {}, {}, {}, {});
189
190
191
193}
const std::string & type() const
std::vector< ore::data::TradeBarrier > levels() const
const std::string & style() const
std::vector< ScriptedTradeValueTypeData > daycounters_
std::vector< ScriptedTradeEventData > events_
std::vector< ScriptedTradeValueTypeData > currencies_
std::vector< ScriptedTradeValueTypeData > indices_
std::vector< ScriptedTradeValueTypeData > numbers_
std::map< std::string, ScriptedTradeScriptData > script_
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h)
Convert std::string to QuantLib::IborIndex.
Barrier::Type parseBarrierType(const std::string &s)
Convert std::string to QuantLib::BarrierType.