268 {
269
270
271
274
275
276
278 fixingSchedulePlusInf.push_back(Date::maxDate());
279 std::vector<std::vector<RangeBound>> rangeBoundSet = buildScheduledVectorNormalised<std::vector<RangeBound>>(
281 std::vector<std::string>
strikes =
283 Size numberOfRangeBounds = Null<Size>();
284
285 QL_REQUIRE(rangeBoundSet.size() == fixingSchedulePlusInf.size() - 1,
286 "RangeBoundSet has " << rangeBoundSet.size() << " elements for " << (fixingSchedulePlusInf.size() - 1)
287 << " fixing dates.");
288 QL_REQUIRE(
strikes.size() == fixingSchedulePlusInf.size() - 1,
"Strikes has " <<
strikes.size() <<
" elements for "
289 << (fixingSchedulePlusInf.size() - 1)
290 << " fixing dates.");
291
292
293
294 std::vector<std::string> rangeStrikes, rangeUpperBounds, rangeLowerBounds, rangeLeverages;
295 for (Size i = 0; i < rangeBoundSet.size(); ++i) {
296
297 for (auto const& r : rangeBoundSet[i]) {
298 if (r.strike() != Null<Real>())
299 rangeStrikes.push_back(boost::lexical_cast<std::string>(r.strike()));
300 else if (r.strikeAdjustment() != Null<Real>() && !strikes[i].empty())
301 rangeStrikes.push_back(boost::lexical_cast<std::string>(r.strikeAdjustment() +
parseReal(strikes[i])));
302 else if (!strikes[i].empty())
303 rangeStrikes.push_back(boost::lexical_cast<std::string>(
parseReal(strikes[i])));
304 else {
305 QL_FAIL("insufficient strike information");
306 }
307 rangeLowerBounds.push_back(
308 boost::lexical_cast<std::string>(r.from() == Null<Real>() ? -QL_MAX_REAL : r.from()));
309 rangeUpperBounds.push_back(boost::lexical_cast<std::string>(r.to() == Null<Real>() ? QL_MAX_REAL : r.to()));
310 rangeLeverages.push_back(
311 boost::lexical_cast<std::string>(r.leverage() == Null<Real>() ? 1.0 : r.leverage()));
312 }
313
314 if (i == 0)
315 numberOfRangeBounds = rangeLowerBounds.size();
316 else {
317 QL_REQUIRE(
318 numberOfRangeBounds * (i + 1) == rangeLowerBounds.size(),
319 "Each RangeBounds subnode (under RangeBoundSets) must contain the same number of RangeBound nodes");
320 }
321 }
322
323 QL_REQUIRE(numberOfRangeBounds != Null<Size>(), "internal error: numberOfRangeBounds not set.");
324
325
326
327 numbers_.emplace_back(
"Number",
"NumberOfRangeBounds", std::to_string(numberOfRangeBounds));
328 numbers_.emplace_back(
"Number",
"RangeStrikes", rangeStrikes);
329 numbers_.emplace_back(
"Number",
"RangeLowerBounds", rangeLowerBounds);
330 numbers_.emplace_back(
"Number",
"RangeUpperBounds", rangeUpperBounds);
331 numbers_.emplace_back(
"Number",
"RangeLeverages", rangeLeverages);
332
334 numbers_.emplace_back(
"Number",
"LongShort",
336
338
343
344 std::string knockOutProfitAmount = "0", knockOutProfitAmountPoints = "0", knockOutProfitEvents = "0";
346 QL_REQUIRE(b.style().empty() || b.style() == "European", "only european barrier style supported");
347 if (b.type() == "CumulatedProfitCap" && !b.levels().empty())
348 knockOutProfitAmount = boost::lexical_cast<std::string>(b.levels().front().value());
349 else if (b.type() == "CumulatedProfitCapPoints" && !b.levels().empty())
350 knockOutProfitAmountPoints = boost::lexical_cast<std::string>(b.levels().front().value());
351 else if (b.type() == "FixingCap" && !b.levels().empty())
352 knockOutProfitEvents = boost::lexical_cast<std::string>(b.levels().front().value());
353 else {
354 QL_FAIL("invalid barrier definition, expected CumulatedProfitCap or FixingCap with exactly one level");
355 }
356 }
357
358
359
360 Real targetAmount = 0.0, targetPoints = 0.0;
367 }
368
369
370
371 std::string scriptToUse, amcScriptToUse;
372 if (knockOutProfitAmountPoints != "0") {
373 scriptToUse = tarf_script_points;
374 amcScriptToUse = tarf_script_points_amc;
375 QL_REQUIRE(
376 knockOutProfitAmount == "0",
377 "CumulatedProfitCapPoints can not be combined with other barrier types CumulatedPorfitCap, FixingCap");
378 numbers_.emplace_back(
"Number",
"TargetPoints", boost::lexical_cast<std::string>(targetPoints));
379 numbers_.emplace_back(
"Number",
"KnockOutProfitAmountPoints", knockOutProfitAmountPoints);
380 } else {
381 scriptToUse = tarf_script_regular;
382 amcScriptToUse = tarf_script_regular_amc;
383 numbers_.emplace_back(
"Number",
"TargetAmount", boost::lexical_cast<std::string>(targetAmount));
384 numbers_.emplace_back(
"Number",
"KnockOutProfitAmount", knockOutProfitAmount);
385 numbers_.emplace_back(
"Number",
"KnockOutProfitEvents", knockOutProfitEvents);
386 }
387
388
389
390 std::string targetType;
392 targetType = "-1";
394 targetType = "0";
396 targetType = "1";
397 else {
398 QL_FAIL("invalid payoffType, expected TargetTruncated, TargetExact, TargetFull");
399 }
400 numbers_.emplace_back(
"Number",
"TargetType", targetType);
401
402
403
405
406
407
409
410 script_[
""] = ScriptedTradeScriptData(scriptToUse,
"value",
411 {{"currentNotional", "currentNotional"},
412 {"notionalCurrency", "PayCcy"},
413 {"FixingAmount", "FixingAmount"},
414 {"Fixing", "Fixing"},
415 {"Triggered", "Triggered"}},
416 {});
417
418 script_[
"AMC"] = ScriptedTradeScriptData(
419 amcScriptToUse, "value",
420 {{"currentNotional", "currentNotional"},
421 {"notionalCurrency", "PayCcy"},
422 {"FixingAmount", "FixingAmount"},
423 {"Fixing", "Fixing"},
424 {"Triggered", "Triggered"}},
425 {}, {ScriptedTradeScriptData::NewScheduleData("FixingAndSimDates", "Join", {"_AMC_SimDates", "FixingDates"})},
426 {}, {}, {"Asset"});
427
428
429
431}
const string & payoffType() const
const string & longShort() const
std::vector< ScriptedTradeEventData > events_
std::vector< ScriptedTradeValueTypeData > currencies_
std::vector< ScriptedTradeValueTypeData > numbers_
std::map< std::string, ScriptedTradeScriptData > script_
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Real parseReal(const string &s)
Convert text to Real.
Schedule makeSchedule(const ScheduleDates &data)