Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
genericbarrieroption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17 */
18
21
23
24#include <boost/lexical_cast.hpp>
25
26namespace ore {
27namespace data {
28
29// clang-format off
30
31 static const std::string mcscript =
32 " REQUIRE PayoffType == 0 OR PayoffType == 1;\n"
33 " REQUIRE SIZE(Underlyings) == SIZE(TransatlanticBarrierType);\n"
34 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierLevels) / SIZE(Underlyings);\n"
35 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebates);\n"
36 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebateCurrencies);\n"
37 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebatePayTimes);\n"
38 " REQUIRE ExpiryDate >= BarrierMonitoringDates[SIZE(BarrierMonitoringDates)];\n"
39 "\n"
40 " NUMBER KnockedIn, KnockedOut, Active, rebate, TransatlanticActive;\n"
41 " NUMBER U, i, k, d, currentNotional, levelIndex;\n"
42 "\n"
43 " FOR d IN (1, SIZE(BarrierMonitoringDates), 1) DO\n"
44 "\n"
45 " FOR i IN (1, SIZE(BarrierTypes), 1) DO\n"
46 "\n"
47 " FOR k IN (1, SIZE(Underlyings), 1) DO\n"
48 " U = Underlyings[k](BarrierMonitoringDates[d]);\n"
49 "\n"
50 " levelIndex = ((k - 1) * SIZE(BarrierTypes)) + i;\n"
51 " IF {BarrierTypes[i] == 1 AND U <= BarrierLevels[levelIndex]} OR\n"
52 " {BarrierTypes[i] == 2 AND U >= BarrierLevels[levelIndex]} THEN\n"
53 " IF KnockedOut == 0 THEN\n"
54 " KnockedIn = 1;\n"
55 " END;\n"
56 " END;\n"
57 "\n"
58 " IF {BarrierTypes[i] == 3 AND U < BarrierLevels[levelIndex]} OR\n"
59 " {BarrierTypes[i] == 4 AND U > BarrierLevels[levelIndex]} THEN\n"
60 " IF KikoType == 1 OR { KikoType == 2 AND KnockedIn == 0 } OR { KikoType == 3 AND KnockedIn == 1 } THEN\n"
61 " IF KnockedOut == 0 THEN\n"
62 " IF BarrierRebatePayTimes[i] == 0 THEN\n"
63 " rebate = PAY( LongShort * BarrierRebates[i], BarrierMonitoringDates[d], BarrierMonitoringDates[d], BarrierRebateCurrencies[i] );\n"
64 " ELSE\n"
65 " rebate = PAY( LongShort * BarrierRebates[i], BarrierMonitoringDates[d], SettlementDate, BarrierRebateCurrencies[i] );\n"
66 " END;\n"
67 " END;\n"
68 " KnockedOut = 1;\n"
69 " END;\n"
70 " END;\n"
71 "\n"
72 " END;\n"
73 "\n"
74 " END;\n"
75 "\n"
76 " END;\n"
77 "\n"
78 " Active = 1;\n"
79 " FOR i IN (1, SIZE(BarrierTypes),1) DO\n"
80 " IF BarrierTypes[i] == 1 OR BarrierTypes[i] == 2 THEN\n"
81 " Active = 0;\n"
82 " END;\n"
83 " END;\n"
84 "\n"
85 " Active = max(Active, KnockedIn) * (1 - KnockedOut);\n"
86 "\n"
87 " IF BarrierRebate != 0 THEN\n"
88 " rebate = (1 - Active) * PAY( LongShort * BarrierRebate, SettlementDate, SettlementDate, BarrierRebateCurrency );\n"
89 " END;\n"
90 "\n"
91 " TransatlanticActive = 1;\n"
92 " FOR k IN (1, SIZE(Underlyings), 1) DO\n"
93 " REQUIRE TransatlanticBarrierType[k] >= 0 AND TransatlanticBarrierType[k] <= 4;\n"
94 " IF { TransatlanticBarrierType[k] == 1 AND Underlyings[k](ExpiryDate) >= TransatlanticBarrierLevel[k] } OR\n"
95 " { TransatlanticBarrierType[k] == 2 AND Underlyings[k](ExpiryDate) <= TransatlanticBarrierLevel[k] } OR\n"
96 " { TransatlanticBarrierType[k] == 3 AND Underlyings[k](ExpiryDate) < TransatlanticBarrierLevel[k] } OR\n"
97 " { TransatlanticBarrierType[k] == 4 AND Underlyings[k](ExpiryDate) > TransatlanticBarrierLevel[k] } THEN\n"
98 " TransatlanticActive = 0;\n"
99 " END;\n"
100 " END;\n"
101 "\n"
102 " rebate = rebate + Active * (1 - TransatlanticActive) * PAY( TransatlanticBarrierRebate, SettlementDate, SettlementDate, TransatlanticBarrierRebateCurrency );\n"
103 "\n"
104 " IF PayoffType == 0 AND SIZE(Underlyings) == 1 THEN\n"
105 " value = Active * TransatlanticActive * PAY( LongShort * Quantity * max(0, PutCall * (Underlyings[1](ExpiryDate) - Strike)), ExpiryDate, SettlementDate, PayCurrency ) +\n"
106 " rebate;\n"
107 " ELSE\n"
108 " value = Active * TransatlanticActive * PAY( LongShort * Amount, ExpiryDate, SettlementDate, PayCurrency ) +\n"
109 " rebate;\n"
110 " END;\n"
111 "\n"
112 " IF PayoffType == 0 THEN\n"
113 " currentNotional = Quantity * Strike;\n"
114 " ELSE\n"
115 " currentNotional = Amount;\n"
116 " END;";
117
118 static const std::string fdscript =
119 " REQUIRE PayoffType == 0 OR PayoffType == 1;\n"
120 " REQUIRE SIZE(Underlyings) == SIZE(TransatlanticBarrierType);\n"
121 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierLevels) / SIZE(Underlyings);\n"
122 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebates);\n"
123 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebateCurrencies);\n"
124 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebatePayTimes);\n"
125 " REQUIRE ExpiryDate >= BarrierMonitoringDates[SIZE(BarrierMonitoringDates)];\n"
126 "\n"
127 " NUMBER V, V_V, V_NA, V_KI, V_KO, V_KIKO, V_KOKI;\n"
128 " NUMBER R, R_V, R_NA, R_KI, R_KO, R_KIKO, R_KOKI, rebate;\n"
129 " NUMBER U, i, k, d, currentNotional, TransatlanticActive, IsKnockedIn, IsKnockedOut, levelIndex;\n"
130 "\n"
131 " IF PayoffType == 0 AND SIZE(Underlyings) == 1 THEN\n"
132 " V = PAY( LongShort * Quantity * max(0, PutCall * (Underlyings[1](ExpiryDate) - Strike)), ExpiryDate, SettlementDate, PayCurrency );\n"
133 " ELSE\n"
134 " V = PAY( LongShort * Amount, ExpiryDate, SettlementDate, PayCurrency );\n"
135 " END;\n"
136 "\n"
137 " TransatlanticActive = 1;\n"
138 " FOR k IN (1, SIZE(Underlyings), 1) DO\n"
139 " REQUIRE TransatlanticBarrierType[k] >= 0 AND TransatlanticBarrierType[k] <= 4;\n"
140 " IF { TransatlanticBarrierType[k] == 1 AND Underlyings[k](ExpiryDate) >= TransatlanticBarrierLevel[k] } OR\n"
141 " { TransatlanticBarrierType[k] == 2 AND Underlyings[k](ExpiryDate) <= TransatlanticBarrierLevel[k] } OR\n"
142 " { TransatlanticBarrierType[k] == 3 AND Underlyings[k](ExpiryDate) < TransatlanticBarrierLevel[k] } OR\n"
143 " { TransatlanticBarrierType[k] == 4 AND Underlyings[k](ExpiryDate) > TransatlanticBarrierLevel[k] } THEN\n"
144 " TransatlanticActive = 0;\n"
145 " END;\n"
146 " END;\n"
147 "\n"
148 " IF TransatlanticActive == 0 THEN\n"
149 " V = PAY( LongShort * TransatlanticBarrierRebate, ExpiryDate, SettlementDate, TransatlanticBarrierRebateCurrency );\n"
150 " END;\n"
151 "\n"
152 " V_V = V;\n"
153 " V_NA = V;\n"
154 " V_KI = V * 0;\n"
155 " V_KO = V * 0;\n"
156 " V_KIKO = V * 0;\n"
157 " V_KOKI = V * 0;\n"
158 "\n"
159 " R = PAY( LongShort * BarrierRebate, ExpiryDate, SettlementDate, BarrierRebateCurrency);\n"
160 " R_V = R;\n"
161 " R_NA = R;\n"
162 " R_KI = R * 0;\n"
163 " R_KO = R * 0;\n"
164 " R_KIKO = R * 0;\n"
165 " R_KOKI = R * 0;\n"
166 "\n"
167 " FOR i IN (1, SIZE(BarrierTypes), 1) DO\n"
168 " IF BarrierTypes[i] == 1 OR BarrierTypes[i] == 2 THEN\n"
169 " V_V = V_V * 0;\n"
170 " R_V = R_V * 0;\n"
171 " END;\n"
172 " END;\n"
173 "\n"
174 " FOR d IN (SIZE(BarrierMonitoringDates), 1, -1) DO\n"
175 "\n"
176 " V_V = NPV(V_V, BarrierMonitoringDates[d]);\n"
177 " V_NA = NPV(V_NA, BarrierMonitoringDates[d]);\n"
178 " V_KI = NPV(V_KI, BarrierMonitoringDates[d]);\n"
179 " V_KO = NPV(V_KO, BarrierMonitoringDates[d]);\n"
180 " V_KIKO = NPV(V_KIKO, BarrierMonitoringDates[d]);\n"
181 " V_KOKI = NPV(V_KOKI, BarrierMonitoringDates[d]);\n"
182 " R_V = NPV(R_V, BarrierMonitoringDates[d]);\n"
183 " R_NA = NPV(R_NA, BarrierMonitoringDates[d]);\n"
184 " R_KI = NPV(R_KI, BarrierMonitoringDates[d]);\n"
185 " R_KO = NPV(R_KO, BarrierMonitoringDates[d]);\n"
186 " R_KIKO = NPV(R_KIKO, BarrierMonitoringDates[d]);\n"
187 " R_KOKI = NPV(R_KOKI, BarrierMonitoringDates[d]);\n"
188 " rebate = NPV(rebate, BarrierMonitoringDates[d]);\n"
189 "\n"
190 " FOR i IN (1, SIZE(BarrierTypes), 1) DO\n"
191 "\n"
192 " IsKnockedIn = 0;\n"
193 " IsKnockedOut = 0;\n"
194 " FOR k IN (1, SIZE(Underlyings), 1) DO\n"
195 " U = Underlyings[k](BarrierMonitoringDates[d]);\n"
196 " levelIndex = ((k - 1) * SIZE(BarrierTypes)) + i;\n"
197 " IF {BarrierTypes[i] == 1 AND U <= BarrierLevels[levelIndex]} OR\n"
198 " {BarrierTypes[i] == 2 AND U >= BarrierLevels[levelIndex]} THEN\n"
199 " IsKnockedIn = 1;"
200 " END;\n"
201 " IF {BarrierTypes[i] == 3 AND U < BarrierLevels[levelIndex]} OR\n"
202 " {BarrierTypes[i] == 4 AND U > BarrierLevels[levelIndex]} THEN\n"
203 " IsKnockedOut = 1;"
204 " END;\n"
205 " END;\n"
206 "\n"
207 " IF {IsKnockedIn == 1} THEN\n"
208 " V_KIKO = V_KO + V_KIKO + V_KOKI;\n"
209 " V_KOKI = V_KOKI * 0;\n"
210 " V_KI = V_NA + V_KI;\n"
211 " V_KO = V_KO * 0;\n"
212 " V_NA = V_NA * 0;\n"
213 " V_V = V_KI;\n"
214 " IF KikoType == 2 THEN\n"
215 " V_V = V_V + V_KIKO;\n"
216 " END;\n"
217 " R_KIKO = R_KO + R_KIKO + R_KOKI;\n"
218 " R_KOKI = R_KOKI * 0;\n"
219 " R_KI = R_NA + R_KI;\n"
220 " R_KO = R_KO * 0;\n"
221 " R_NA = R_NA * 0;\n"
222 " R_V = R_KI;\n"
223 " IF KikoType == 2 THEN\n"
224 " R_V = R_V + R_KIKO;\n"
225 " END;\n"
226 " END;\n"
227 "\n"
228 " IF { IsKnockedOut == 1 } THEN\n"
229 " V_KOKI = V_KI + V_KOKI + V_KIKO;\n"
230 " V_KIKO = V_KIKO * 0;\n"
231 " V_KO = V_NA + V_KO;\n"
232 " V_KI = V_KI * 0;\n"
233 " V_NA = V_NA * 0;\n"
234 " IF KikoType == 1 OR KikoType == 2 THEN\n"
235 " V_V = V_V * 0;\n"
236 " END;\n"
237 " R_KOKI = R_KI + R_KOKI + R_KIKO;\n"
238 " R_KIKO = R_KIKO * 0;\n"
239 " R_KO = R_NA + R_KO;\n"
240 " R_KI = R_KI * 0;\n"
241 " R_NA = R_NA * 0;\n"
242 " IF KikoType == 1 OR KikoType == 2 THEN\n"
243 " R_V = R_V * 0;\n"
244 " END;\n"
245 " IF BarrierRebatePayTimes[i] == 0 THEN\n"
246 " rebate = PAY( LongShort * BarrierRebates[i], BarrierMonitoringDates[d], BarrierMonitoringDates[d], BarrierRebateCurrencies[i] );\n"
247 " ELSE\n"
248 " rebate = PAY( LongShort * BarrierRebates[i], BarrierMonitoringDates[d], SettlementDate, BarrierRebateCurrencies[i] );\n"
249 " END;\n"
250 " END;\n"
251 "\n"
252 " END;\n"
253 "\n"
254 " END;\n"
255 "\n"
256 " rebate = NPV(rebate, TODAY);"
257 " R_V = NPV(R_V, TODAY);"
258 " V_V = NPV(V_V, TODAY);"
259 "\n"
260 "\n"
261 " rebate = rebate + ( PAY( LongShort * BarrierRebate, TODAY, SettlementDate, BarrierRebateCurrency ) - R_V );\n"
262 " value = V_V + rebate;\n"
263 "\n"
264 " IF PayoffType == 0 THEN\n"
265 " currentNotional = Quantity * Strike;\n"
266 " ELSE\n"
267 " currentNotional = Amount;\n"
268 " END;";
269
270// clang-format on
271
272void GenericBarrierOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& factory) {
273
274 // set script parameters
275
276 clear();
277 initIndices();
278
279 if (underlyings_.size() > 1)
280 QL_REQUIRE(optionData_.payoffType() == "CashOrNothing",
281 "Only CashOrNothing payoff allowed for mulitple underlyings");
282
283 std::string payoffType;
284 if (optionData_.payoffType() == "Vanilla" || optionData_.payoffType() == "AssetOrNothing")
285 payoffType = "0";
286 else if (optionData_.payoffType() == "CashOrNothing")
287 payoffType = "1";
288 else {
289 QL_FAIL("PayoffTpye (" << optionData_.payoffType() << ") must be Vanilla or CashOrNothing");
290 }
291 numbers_.emplace_back("Number", "PayoffType", payoffType);
292
293 QL_REQUIRE(optionData_.payoffType() != "Vanilla" || (!quantity_.empty() && !strike_.empty() && amount_.empty()),
294 "Need Quantity, Strike, no Amount for PayoffType = Vanilla");
295 QL_REQUIRE(optionData_.payoffType() != "AssetOrNothing" ||
296 (!quantity_.empty() && strike_.empty() && amount_.empty()),
297 "Need Quantity, no Strike, no Amount for PayoffType = AssetOrNothing");
298 QL_REQUIRE(optionData_.payoffType() != "CashOrNothing" ||
299 (quantity_.empty() && strike_.empty() && !amount_.empty()),
300 "Need no Quantity, no Strike, Amount for PayoffType = CashOrNothing");
301
302 std::vector<std::string> transatlanticBarrierType(underlyings_.size(), "0");
303 std::vector<std::string> transatlanticBarrierLevel(underlyings_.size(), "0");
304 std::string transatlanticBarrierRebate = "0.0";
305 std::string transatlanticBarrierRebateCurrency = payCurrency_;
306 if (!transatlanticBarrier_[0].type().empty()) {
307 transatlanticBarrierType.clear();
308 for (auto const& n : transatlanticBarrier_) {
309 if (n.type() == "DownAndIn")
310 transatlanticBarrierType.push_back("1");
311 else if (n.type() == "UpAndIn")
312 transatlanticBarrierType.push_back("2");
313 else if (n.type() == "DownAndOut")
314 transatlanticBarrierType.push_back("3");
315 else if (n.type() == "UpAndOut")
316 transatlanticBarrierType.push_back("4");
317 else {
318 QL_FAIL("Transatlantic BarrierType (" << n.type()
319 << ") must be DownAndIn, UpAndIn, DownAndOut, UpAndOut");
320 }
321 }
322 QL_REQUIRE(transatlanticBarrierType.size() == 1 || transatlanticBarrierType.size() == underlyings_.size(),
323 "Transatlantic Barrier must have only 1 Barrier block or 1 block for each underlyings, got "
324 << transatlanticBarrierType.size());
325 if (transatlanticBarrierType.size() == 1 && underlyings_.size() > 1) {
326 transatlanticBarrierType.assign(underlyings_.size(), transatlanticBarrierType[0]);
327 }
328 transatlanticBarrierLevel.clear();
329 if (transatlanticBarrier_.size() == 1) {
330 QL_REQUIRE(transatlanticBarrier_[0].levels().size() == underlyings_.size(),
331 "Transatlantic Barrier must have exactly 1 level for each underlying, got "
332 << transatlanticBarrier_[0].levels().size());
333 for (const auto& l : transatlanticBarrier_[0].levels())
334 transatlanticBarrierLevel.push_back(boost::lexical_cast<std::string>(l.value()));
335 } else {
336 QL_REQUIRE(transatlanticBarrierType.size() == underlyings_.size(),
337 "Transatlantic Barrier must have exactly 1 level for each underlying, got "
338 << transatlanticBarrier_.size());
339 for (auto const& n : transatlanticBarrier_) {
340 QL_REQUIRE(n.levels().size() == 1, "Number of level in each barrier block in transatlantic barriers "
341 "must be exactly 1 if more than 1 barrier blocks are provided, got "
342 << transatlanticBarrier_.size());
343 transatlanticBarrierLevel.push_back(boost::lexical_cast<std::string>(n.levels()[0].value()));
344 }
345 }
346 if (transatlanticBarrier_.size() > 1) {
347 for (Size i = 1; i < transatlanticBarrier_.size(); i++) {
348 QL_REQUIRE(transatlanticBarrier_[i].rebateCurrency().empty() ||
349 transatlanticBarrier_[i].rebateCurrency() == transatlanticBarrier_[0].rebateCurrency(),
350 "Rebate currency for transatlantic barriers must be identical or only given in the first "
351 "transatlantic barrier.");
352 }
353 }
354 transatlanticBarrierRebate = boost::lexical_cast<std::string>(transatlanticBarrier_[0].rebate());
355 if (!transatlanticBarrier_[0].rebateCurrency().empty())
356 transatlanticBarrierRebateCurrency = transatlanticBarrier_[0].rebateCurrency();
357 }
358 numbers_.emplace_back("Number", "TransatlanticBarrierType", transatlanticBarrierType);
359 numbers_.emplace_back("Number", "TransatlanticBarrierLevel", transatlanticBarrierLevel);
360 numbers_.emplace_back("Number", "TransatlanticBarrierRebate", transatlanticBarrierRebate);
361 currencies_.emplace_back("Currency", "TransatlanticBarrierRebateCurrency", transatlanticBarrierRebateCurrency);
362
363 auto positionType = parsePositionType(optionData_.longShort());
364 numbers_.emplace_back("Number", "LongShort", positionType == Position::Long ? "1" : "-1");
365
366 if (optionData_.callPut().empty()) {
367 QL_REQUIRE(optionData_.payoffType() == "CashOrNothing" || optionData_.payoffType() == "AssetOrNothing",
368 "Payoff type must be vanilla if option type is not givien.");
369 numbers_.emplace_back("Number", "PutCall", "1.0");
370 } else {
371 numbers_.emplace_back("Number", "PutCall",
372 parseOptionType(optionData_.callPut()) == Option::Call ? "1.0" : "-1.0");
373 }
374 numbers_.emplace_back("Number", "Quantity", quantity_.empty() ? "0.0" : quantity_);
375 if (!strike_.empty())
376 numbers_.emplace_back("Number", "Strike", strike_);
377 numbers_.emplace_back("Number", "Amount", amount_.empty() ? "0.0" : amount_);
378 currencies_.emplace_back("Currency", "PayCurrency", payCurrency_);
379
380 QL_REQUIRE(optionData_.exerciseDates().size() == 1,
381 "OptionData must contain exactly one ExerciseDate, got " << optionData_.exerciseDates().size());
382 events_.emplace_back("ExpiryDate", optionData_.exerciseDates().front());
383
384 if (!settlementDate_.empty()) {
385 QL_REQUIRE(
386 settlementLag_.empty() && settlementCalendar_.empty() && settlementConvention_.empty(),
387 "If SettlementDate is given, no SettlementLag, SettlementCalendar or SettlementConvention must be given.");
388 events_.emplace_back("SettlementDate", settlementDate_);
389 } else {
390 Date ref = parseDate(optionData_.exerciseDates().front());
391 Period p = settlementLag_.empty() ? 0 * Days : parsePeriod(settlementLag_);
392 Calendar cal =
394 BusinessDayConvention conv =
396 events_.emplace_back("SettlementDate", ore::data::to_string(cal.advance(ref, p, conv)));
397 }
398
400 QL_REQUIRE(barrierMonitoringStartDate_.empty() && barrierMonitoringEndDate_.empty(),
401 "If ScheduleData is given, no StartDate or EndDate must be given");
402 events_.emplace_back("BarrierMonitoringDates", barrierMonitoringDates_);
403 } else {
404 /* build a daily schedule from the given start / end dates and deriving the calendar from
405 the underlying */
406 QL_REQUIRE(!barrierMonitoringStartDate_.empty() && !barrierMonitoringEndDate_.empty(),
407 "If no ScheduleData is given, StartDate and EndDate must be given");
408 events_.emplace_back("BarrierMonitoringDates",
410 getUnderlyingCalendar(factory).name(), "F", "F", "Forward")));
411 }
412
413 std::vector<std::string> barrierTypes, barrierLevels, barrierRebates, barrierRebateCurrencies,
414 barrierRebatePayTimes;
415 bool hasKi = false, hasKo = false;
416 for (auto const& b : barriers_) {
417 std::string barrierType;
418 if (b.type() == "DownAndIn") {
419 barrierType = "1";
420 hasKi = true;
421 } else if (b.type() == "UpAndIn") {
422 barrierType = "2";
423 hasKi = true;
424 } else if (b.type() == "DownAndOut") {
425 barrierType = "3";
426 hasKo = true;
427 } else if (b.type() == "UpAndOut") {
428 barrierType = "4";
429 hasKo = true;
430 } else {
431 QL_FAIL("BarrierType (" << b.type() << ") must be DownAndIn, UpAndIn, DownAndOut, UpAndOut");
432 }
433 barrierTypes.push_back(barrierType);
434 QL_REQUIRE(b.levels().size() == underlyings_.size(), "Barrier must have exactly number of levels as underlyings, got " << b.levels().size());
435 for (const auto& l : b.levels())
436 barrierLevels.push_back(boost::lexical_cast<std::string>(l.value()));
437 barrierRebates.push_back(boost::lexical_cast<std::string>(b.rebate()));
438 barrierRebateCurrencies.push_back(b.rebateCurrency().empty() ? payCurrency_ : b.rebateCurrency());
439 std::string rebatePayTime;
440 if (b.rebatePayTime() == "atHit")
441 rebatePayTime = "0";
442 else if (b.rebatePayTime() == "atExpiry" || b.rebatePayTime().empty())
443 rebatePayTime = "1";
444 else {
445 QL_FAIL("RebatePayTime (" << b.rebatePayTime() << ") must be atHit, atExpiry");
446 }
447 barrierRebatePayTimes.push_back(rebatePayTime);
448 }
449
450 // if there is at least one ki barrier, all rebates must be identical + atExpiry
451 // and are set via BarrierRebate, BarrierRebateCurrency
452
453 std::string barrierRebate = "0.0", barrierRebateCurrency = payCurrency_;
454 if (hasKi) {
455 for (Size i = 1; i < barrierTypes.size(); ++i) {
456 QL_REQUIRE(close_enough(parseReal(barrierRebates[i]), parseReal(barrierRebates[0])) &&
457 barrierRebateCurrencies[i] == barrierRebateCurrencies[0],
458 "If Knock-In barrier is present, all rebates must be identical, found "
459 << barrierRebates[0] << " " << barrierRebateCurrencies[0] << " and " << barrierRebates[i]
460 << " " << barrierRebateCurrencies[i]);
461 }
462 for (Size i = 0; i < barrierTypes.size(); ++i) {
463 QL_REQUIRE(barrierRebatePayTimes[i] == "1",
464 "If Knock-In barrier is present, all rebate pay times must be atExpiry");
465 }
466 barrierRebate = barrierRebates[0];
467 barrierRebateCurrency = barrierRebateCurrencies[0];
468 for (Size i = 0; i < barrierTypes.size(); ++i) {
469 barrierRebates[i] = "0.0";
470 barrierRebateCurrencies[i] = payCurrency_;
471 }
472 }
473
474 numbers_.emplace_back("Number", "BarrierTypes", barrierTypes);
475 numbers_.emplace_back("Number", "BarrierLevels", barrierLevels);
476 numbers_.emplace_back("Number", "BarrierRebates", barrierRebates);
477 currencies_.emplace_back("Currency", "BarrierRebateCurrencies", barrierRebateCurrencies);
478 numbers_.emplace_back("Number", "BarrierRebatePayTimes", barrierRebatePayTimes);
479 numbers_.emplace_back("Number", "BarrierRebate", barrierRebate);
480 currencies_.emplace_back("Currency", "BarrierRebateCurrency", barrierRebateCurrency);
481
482 std::string kikoType;
483 if (kikoType_ == "KoAlways" || kikoType_.empty())
484 kikoType = "1";
485 else if (kikoType_ == "KoBeforeKi")
486 kikoType = "2";
487 else if (kikoType_ == "KoAfterKi")
488 kikoType = "3";
489 else {
490 QL_FAIL("KikoType (" << kikoType_ << ") must be KoAlways, KoBeforeKi, KoAfterKi");
491 }
492 numbers_.emplace_back("Number", "KikoType", kikoType);
493
494 QL_REQUIRE((hasKi && hasKo) || kikoType == "1",
495 "KikoType (" << kikoType_ << ") must be KoAlways if there are only Ko or only Ki barriers");
496 QL_REQUIRE(!(hasKi && hasKo) || !kikoType_.empty(),
497 "KikoType must be given (KoAlways, KoBeforeKi, KoAfterKi) if both Ko and Ki barriers are present");
498
499 // set product tag
500
501 productTag_ = (underlyings_.size() < 2) ? "SingleAssetOptionBwd({AssetClass})"
502 : "MultiAssetOption({AssetClass})";
503
504 // set script
505
507 mcscript, "value",
508 {{"currentNotional", "currentNotional"},
509 {"notionalCurrency", "PayCurrency"},
510 {"Active", "Active"},
511 {"TransatlanticActive", "TransatlanticActive"}},
512 {}, {}, {ScriptedTradeScriptData::CalibrationData("Underlyings", {"Strike", "BarrierLevels"})});
514 fdscript, "value", {{"currentNotional", "currentNotional"}, {"notionalCurrency", "PayCurrency"}}, {}, {},
515 {ScriptedTradeScriptData::CalibrationData("Underlyings", {"Strike", "BarrierLevels"})});
516
517 // build trade
518
519 ScriptedTrade::build(factory, optionData_.premiumData(), positionType == QuantLib::Position::Long ? -1.0 : 1.0);
520}
521
523 std::vector<std::string> underlyings;
524 for (auto const& u : underlyings_)
525 underlyings.push_back(scriptedIndexName(u));
526
527 indices_.emplace_back("Index", "Underlyings", underlyings);
528}
529
530QuantLib::Calendar GenericBarrierOption::getUnderlyingCalendar(const QuantLib::ext::shared_ptr<EngineFactory>& factory) const {
531 Calendar calendar = NullCalendar();
532 QL_REQUIRE(underlyings_.size() > 0, "No underlyings provided.");
534 if (ind.isFx()) {
535 /* just take the default calendars for the two currencies, this can be improved once we have
536 full fx indices available in the t0 market (TODO) */
537 calendar = parseCalendar(ind.fx()->sourceCurrency().code() + "," + ind.fx()->targetCurrency().code());
538 } else if (ind.isEq()) {
539 /* get the equity calendar from the market */
540 calendar = factory->market()
541 ->equityCurve(ind.eq()->name(), factory->configuration(MarketContext::pricing))
542 ->fixingCalendar();
543 } else if (ind.isComm()) {
544 /* again, just take the default calendar for the comm currency until we have the actual calendar
545 available via the market interface */
546 calendar =
547 parseCalendar(factory->market()
548 ->commodityPriceCurve(ind.commName(), factory->configuration(MarketContext::pricing))
549 ->currency()
550 .code());
551 }
552 return calendar;
553}
554
556 Trade::fromXML(node);
557 XMLNode* dataNode = XMLUtils::getChildNode(node, tradeType() + "Data");
558 QL_REQUIRE(dataNode, tradeType() + "Data node not found");
559
560 if (XMLNode* underlyingsNode = XMLUtils::getChildNode(dataNode, "Underlyings")) {
561 QL_REQUIRE(underlyingsNode, "No Underlyings node");
562 auto underlyings = XMLUtils::getChildrenNodes(underlyingsNode, "Underlying");
563 for (auto const& n : underlyings) {
564 UnderlyingBuilder underlyingBuilder;
565 underlyingBuilder.fromXML(n);
566 underlyings_.push_back(underlyingBuilder.underlying());
567 }
568 } else {
569 XMLNode* tmp = XMLUtils::getChildNode(dataNode, "Underlying");
570 if (!tmp)
571 tmp = XMLUtils::getChildNode(dataNode, "Name");
572 UnderlyingBuilder underlyingBuilder;
573 underlyingBuilder.fromXML(tmp);
574 underlyings_.push_back(underlyingBuilder.underlying());
575 }
576
577 optionData_.fromXML(XMLUtils::getChildNode(dataNode, "OptionData"));
578
579 auto barriersNode = XMLUtils::getChildNode(dataNode, "Barriers");
580 QL_REQUIRE(barriersNode, "No Barriers node found");
581 if (auto sd = XMLUtils::getChildNode(barriersNode, "ScheduleData")) {
583 }
584 barrierMonitoringStartDate_ = XMLUtils::getChildValue(barriersNode, "StartDate", false);
585 barrierMonitoringEndDate_ = XMLUtils::getChildValue(barriersNode, "EndDate", false);
586 kikoType_ = XMLUtils::getChildValue(barriersNode, "KikoType", false, "KoAlways");
587 auto barriers = XMLUtils::getChildrenNodes(barriersNode, "BarrierData");
588 for (auto const& n : barriers) {
589 barriers_.push_back(BarrierData());
590 barriers_.back().fromXML(n);
591 }
592
593 auto transatlanticBarrierNode = XMLUtils::getChildNode(dataNode, "TransatlanticBarrier");
594 if (transatlanticBarrierNode) {
595 auto b = XMLUtils::getChildrenNodes(transatlanticBarrierNode, "BarrierData");
596 for (auto const& n : b) {
598 transatlanticBarrier_.back().fromXML(n);
599 }
600 }
601
602 payCurrency_ = XMLUtils::getChildValue(dataNode, "PayCurrency", true);
603 settlementDate_ = XMLUtils::getChildValue(dataNode, "SettlementDate", false);
604 settlementLag_ = XMLUtils::getChildValue(dataNode, "SettlementLag", false);
605 settlementCalendar_ = XMLUtils::getChildValue(dataNode, "SettlementCalendar", false);
606 settlementConvention_ = XMLUtils::getChildValue(dataNode, "SettlementConvention", false);
607 quantity_ = XMLUtils::getChildValue(dataNode, "Quantity", false);
608 strike_ = XMLUtils::getChildValue(dataNode, "Strike", false);
609 amount_ = XMLUtils::getChildValue(dataNode, "Amount", false);
610
611 initIndices();
612}
613
615 XMLNode* node = Trade::toXML(doc);
616 XMLNode* dataNode = doc.allocNode(tradeType() + "Data");
617 XMLUtils::appendNode(node, dataNode);
618
619
620 XMLNode* underlyingsNode = doc.allocNode("Underlyings");
621 for (auto& n : underlyings_) {
622 XMLUtils::appendNode(underlyingsNode, n->toXML(doc));
623 }
624 XMLUtils::appendNode(dataNode, underlyingsNode);
625 XMLUtils::appendNode(dataNode, optionData_.toXML(doc));
626
627 XMLNode* barriers = doc.allocNode("Barriers");
630 if (!barrierMonitoringStartDate_.empty())
631 XMLUtils::addChild(doc, barriers, "StartDate", barrierMonitoringStartDate_);
632 if (!barrierMonitoringEndDate_.empty())
633 XMLUtils::addChild(doc, barriers, "EndDate", barrierMonitoringEndDate_);
634 for (auto& n : barriers_) {
635 XMLUtils::appendNode(barriers, n.toXML(doc));
636 }
637 if (!kikoType_.empty())
638 XMLUtils::addChild(doc, barriers, "KikoType", kikoType_);
639 XMLUtils::appendNode(dataNode, barriers);
640
641 if (!transatlanticBarrier_[0].type().empty()) {
642 XMLNode* transatlanticBarrierNode = doc.allocNode("TransatlanticBarrier");
643 for (auto& n : transatlanticBarrier_) {
644 XMLUtils::appendNode(transatlanticBarrierNode, n.toXML(doc));
645 }
646 XMLUtils::appendNode(dataNode, transatlanticBarrierNode);
647 }
648
649 XMLUtils::addChild(doc, dataNode, "PayCurrency", payCurrency_);
650 if (!settlementDate_.empty())
651 XMLUtils::addChild(doc, dataNode, "SettlementDate", settlementDate_);
652 if (!settlementLag_.empty())
653 XMLUtils::addChild(doc, dataNode, "SettlementLag", settlementLag_);
654 if (!settlementCalendar_.empty())
655 XMLUtils::addChild(doc, dataNode, "SettlementCalendar", settlementCalendar_);
656 if (!settlementConvention_.empty())
657 XMLUtils::addChild(doc, dataNode, "SettlementConvention", settlementConvention_);
658
659 if (!quantity_.empty())
660 XMLUtils::addChild(doc, dataNode, "Quantity", quantity_);
661 if (!strike_.empty())
662 XMLUtils::addChild(doc, dataNode, "Strike", strike_);
663 if (!amount_.empty())
664 XMLUtils::addChild(doc, dataNode, "Amount", amount_);
665
666 return node;
667}
668
669} // namespace data
670} // namespace ore
Serializable obejct holding barrier data.
Definition: barrierdata.hpp:34
std::vector< BarrierData > transatlanticBarrier_
std::vector< QuantLib::ext::shared_ptr< ore::data::Underlying > > underlyings_
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
std::vector< BarrierData > barriers_
QuantLib::Calendar getUnderlyingCalendar(const QuantLib::ext::shared_ptr< EngineFactory > &factory) const
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
bool isComm() const
Definition: utilities.hpp:102
QuantLib::ext::shared_ptr< EquityIndex2 > eq() const
Definition: utilities.hpp:110
bool isFx() const
Definition: utilities.hpp:100
QuantLib::ext::shared_ptr< FxIndex > fx() const
Definition: utilities.hpp:109
bool isEq() const
Definition: utilities.hpp:101
std::string commName() const
Definition: utilities.cpp:474
const string & callPut() const
Definition: optiondata.hpp:71
const string & payoffType() const
Definition: optiondata.hpp:72
const string & longShort() const
Definition: optiondata.hpp:70
virtual void fromXML(XMLNode *node) override
Definition: optiondata.cpp:32
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: optiondata.cpp:86
const PremiumData & premiumData() const
Definition: optiondata.hpp:83
const vector< string > & exerciseDates() const
Definition: optiondata.hpp:76
Serializable schedule data.
Definition: schedule.hpp:202
bool hasData() const
Check if has any dates/rules/derived schedules.
Definition: schedule.hpp:223
virtual void fromXML(XMLNode *node) override
Definition: schedule.cpp:179
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: schedule.cpp:198
Serializable object holding schedule Rules data.
Definition: schedule.hpp:37
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
virtual void fromXML(XMLNode *node) override
Definition: trade.cpp:34
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: trade.cpp:46
const string & tradeType() const
Definition: trade.hpp:133
const QuantLib::ext::shared_ptr< Underlying > & underlying()
Definition: underlying.hpp:266
void fromXML(XMLNode *node) override
Definition: underlying.cpp:305
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
Definition: xmlutils.cpp:277
static XMLNode * getChildNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:387
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
Definition: xmlutils.cpp:181
static void appendNode(XMLNode *parent, XMLNode *child)
Definition: xmlutils.cpp:406
generic barrier option wrapper for scripted trade
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Definition: parsers.cpp:404
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Definition: parsers.cpp:173
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
Option::Type parseOptionType(const std::string &s)
Convert text to QuantLib::Option::Type.
Definition: parsers.cpp:481
@ data
Definition: log.hpp:77
Calendar calendar
Definition: utilities.cpp:441
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
QL_DEPRECATED_ENABLE_WARNING std::string scriptedIndexName(const QuantLib::ext::shared_ptr< Underlying > &underlying)
Definition: utilities.cpp:614
Size size(const ValueType &v)
Definition: value.cpp:145
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
some utility functions
string conversion utilities
string name