Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
tarf.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
22#include <boost/lexical_cast.hpp>
23
24namespace ore {
25namespace data {
26
27using namespace QuantExt;
28
29// clang-format off
30
31 static const std::string tarf_script_regular =
32 "REQUIRE FixingAmount > 0;\n"
33 "NUMBER Payoff, d, r, ri, PnL, tmpPnL, wasTriggered, AccProfit, Hits, currentNotional;\n"
34 "NUMBER Fixing[SIZE(FixingDates)], Triggered[SIZE(FixingDates)];\n"
35 "FOR r IN (1, SIZE(RangeUpperBounds), 1) DO\n"
36 " REQUIRE RangeLowerBounds[r] <= RangeUpperBounds[r];\n"
37 " REQUIRE RangeStrikes[r] >= 0;\n"
38 "END;\n"
39 "FOR d IN (1, SIZE(FixingDates), 1) DO\n"
40 " Fixing[d] = Underlying(FixingDates[d]);\n"
41 " tmpPnL = 0;\n"
42 " FOR r IN (1, NumberOfRangeBounds, 1) DO\n"
43 " ri = (d - 1) * NumberOfRangeBounds + r;\n"
44 " IF Fixing[d] > RangeLowerBounds[ri] AND Fixing[d] <= RangeUpperBounds[ri] THEN\n"
45 " tmpPnL = tmpPnL + RangeLeverages[ri] * FixingAmount * (Fixing[d] - RangeStrikes[ri]);\n"
46 " END;\n"
47 " END;\n"
48 " IF wasTriggered != 1 THEN\n"
49 " PnL = tmpPnL;\n"
50 " IF PnL >= 0 THEN\n"
51 " AccProfit = AccProfit + PnL;\n"
52 " Hits = Hits + 1;\n"
53 " END;\n"
54 " IF {KnockOutProfitEvents > 0 AND Hits >= KnockOutProfitEvents} OR\n"
55 " {KnockOutProfitAmount > 0 AND AccProfit >= KnockOutProfitAmount} THEN\n"
56 " wasTriggered = 1;\n"
57 " Triggered[d] = 1;\n"
58 " IF TargetType == 0 THEN\n"
59 " Payoff = Payoff + LOGPAY(TargetAmount - (AccProfit - PnL), FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
60 " END;\n"
61 " IF TargetType == 1 THEN\n"
62 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
63 " END;\n"
64 " ELSE\n"
65 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
66 " END;\n"
67 " END;\n"
68 "END;\n"
69 "value = LongShort * Payoff;\n"
70 "currentNotional = FixingAmount * RangeStrikes[1];";
71
72 static const std::string tarf_script_regular_amc =
73 "REQUIRE FixingAmount > 0;\n"
74 "NUMBER Payoff, d, r, ri, PnL, tmpPnL, wasTriggered, AccProfit[SIZE(FixingDates)], Hits[SIZE(FixingDates)], currentNotional;\n"
75 "NUMBER Fixing[SIZE(FixingDates)], Triggered[SIZE(FixingDates)];\n"
76 "NUMBER a, s, nthPayoff[SIZE(FixingDates)], bwdPayoff, _AMC_NPV[SIZE(_AMC_SimDates)];\n"
77 "FOR r IN (1, SIZE(RangeUpperBounds), 1) DO\n"
78 " REQUIRE RangeLowerBounds[r] <= RangeUpperBounds[r];\n"
79 " REQUIRE RangeStrikes[r] >= 0;\n"
80 "END;\n"
81 "FOR d IN (1, SIZE(FixingDates), 1) DO\n"
82 " Fixing[d] = Underlying(FixingDates[d]);\n"
83 " tmpPnL = 0;\n"
84 " FOR r IN (1, NumberOfRangeBounds, 1) DO\n"
85 " ri = (d - 1) * NumberOfRangeBounds + r;\n"
86 " IF Fixing[d] > RangeLowerBounds[ri] AND Fixing[d] <= RangeUpperBounds[ri] THEN\n"
87 " tmpPnL = tmpPnL + RangeLeverages[ri] * FixingAmount * (Fixing[d] - RangeStrikes[ri]);\n"
88 " END;\n"
89 " END;\n"
90 " IF wasTriggered != 1 THEN\n"
91 " PnL = tmpPnL;\n"
92 " IF PnL >= 0 THEN\n"
93 " AccProfit[d] = AccProfit[d] + PnL;\n"
94 " Hits[d] = Hits[d] + 1;\n"
95 " END;\n"
96 " IF {KnockOutProfitEvents > 0 AND Hits[d] >= KnockOutProfitEvents} OR\n"
97 " {KnockOutProfitAmount > 0 AND AccProfit[d] >= KnockOutProfitAmount} THEN\n"
98 " wasTriggered = 1;\n"
99 " Triggered[d] = 1;\n"
100 " IF TargetType == 0 THEN\n"
101 " Payoff = Payoff + LOGPAY(TargetAmount - (AccProfit[d] - PnL), FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
102 " nthPayoff[d] = PAY(TargetAmount - (AccProfit[d] - PnL), FixingDates[d], SettlementDates[d], PayCcy);\n"
103 " AccProfit[d] = TargetAmount;\n"
104 " END;\n"
105 " IF TargetType == 1 THEN\n"
106 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
107 " nthPayoff[d] = PAY(PnL, FixingDates[d], SettlementDates[d], PayCcy);\n"
108 " END;\n"
109 " ELSE\n"
110 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
111 " nthPayoff[d] = PAY(PnL, FixingDates[d], SettlementDates[d], PayCcy);\n"
112 " END;\n"
113 " END;\n"
114 " IF d < SIZE(FixingDates) THEN\n"
115 " AccProfit[d + 1] = AccProfit[d];\n"
116 " Hits[d + 1] = Hits[d];\n"
117 " END;\n"
118 "END;\n"
119 "FOR a IN (SIZE(FixingAndSimDates), 1, -1) DO\n"
120 " s = DATEINDEX(FixingAndSimDates[a], _AMC_SimDates, EQ);\n"
121 " d = DATEINDEX(FixingAndSimDates[a], FixingDates, GT);\n"
122 " IF s > 0 THEN\n"
123 " IF d > 1 THEN\n"
124 // including Hits[d-1] or AccProfit[d-1] in the regression is not stable
125 " _AMC_NPV[s] = LongShort * NPVMEM( bwdPayoff, _AMC_SimDates[s], a);\n"
126 " ELSE\n"
127 " _AMC_NPV[s] = LongShort * NPVMEM( bwdPayoff, _AMC_SimDates[s], a);\n"
128 " END;\n"
129 " END;\n"
130 " d = DATEINDEX(FixingAndSimDates[a], FixingDates, EQ);\n"
131 " IF d > 0 THEN\n"
132 " bwdPayoff = bwdPayoff + nthPayoff[d];\n"
133 " END;\n"
134 "END;\n"
135 "value = LongShort * Payoff;\n"
136 "currentNotional = FixingAmount * RangeStrikes[1];";
137
138 static const std::string tarf_script_points =
139 "REQUIRE FixingAmount > 0;\n"
140 "NUMBER Payoff, d, r, ri, PnL, tmpPnL, PnLPoints, tmpPnLPoints, wasTriggered, AccProfitPoints, currentNotional;\n"
141 "NUMBER Fixing[SIZE(FixingDates)], Triggered[SIZE(FixingDates)];\n"
142 "FOR r IN (1, SIZE(RangeUpperBounds), 1) DO\n"
143 " REQUIRE RangeLowerBounds[r] <= RangeUpperBounds[r];\n"
144 " REQUIRE RangeStrikes[r] >= 0;\n"
145 "END;\n"
146 "FOR d IN (1, SIZE(FixingDates), 1) DO\n"
147 " Fixing[d] = Underlying(FixingDates[d]);\n"
148 " tmpPnL = 0;\n"
149 " tmpPnLPoints = 0;\n"
150 " FOR r IN (1, NumberOfRangeBounds, 1) DO\n"
151 " ri = (d - 1) * NumberOfRangeBounds + r;\n"
152 " IF Fixing[d] > RangeLowerBounds[ri] AND Fixing[d] <= RangeUpperBounds[ri] THEN\n"
153 " tmpPnL = tmpPnL + RangeLeverages[ri] * FixingAmount * (Fixing[d] - RangeStrikes[ri]);\n"
154 " tmpPnLPoints = tmpPnLPoints + RangeLeverages[ri] / abs(RangeLeverages[ri]) * (Fixing[d] - RangeStrikes[ri]);\n"
155 " END;\n"
156 " END;\n"
157 " IF wasTriggered != 1 THEN\n"
158 " PnL = tmpPnL;\n"
159 " PnLPoints = tmpPnLPoints;\n"
160 " IF PnLPoints >= 0 THEN\n"
161 " AccProfitPoints = AccProfitPoints + PnLPoints;\n"
162 " END;\n"
163 " IF KnockOutProfitAmountPoints > 0 AND AccProfitPoints >= KnockOutProfitAmountPoints THEN\n"
164 " wasTriggered = 1;\n"
165 " Triggered[d] = 1;\n"
166 " IF TargetType == 0 THEN\n"
167 " Payoff = Payoff + LOGPAY((TargetPoints - (AccProfitPoints - PnLPoints)) * PnL / PnLPoints, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
168 " END;\n"
169 " IF TargetType == 1 THEN\n"
170 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
171 " END;\n"
172 " ELSE\n"
173 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
174 " END;\n"
175 " END;\n"
176 "END;\n"
177 "value = LongShort * Payoff;\n"
178 "currentNotional = FixingAmount * RangeStrikes[1];";
179
180 static const std::string tarf_script_points_amc =
181 "REQUIRE FixingAmount > 0;\n"
182 "NUMBER Payoff, d, r, ri, PnL, tmpPnL, PnLPoints, tmpPnLPoints, wasTriggered, AccProfitPoints[SIZE(FixingDates)], currentNotional;\n"
183 "NUMBER Fixing[SIZE(FixingDates)], Triggered[SIZE(FixingDates)];\n"
184 "NUMBER a, s, nthPayoff[SIZE(FixingDates)], bwdPayoff, _AMC_NPV[SIZE(_AMC_SimDates)];\n"
185 "FOR r IN (1, SIZE(RangeUpperBounds), 1) DO\n"
186 " REQUIRE RangeLowerBounds[r] <= RangeUpperBounds[r];\n"
187 " REQUIRE RangeStrikes[r] >= 0;\n"
188 "END;\n"
189 "FOR d IN (1, SIZE(FixingDates), 1) DO\n"
190 " Fixing[d] = Underlying(FixingDates[d]);\n"
191 " tmpPnL = 0;\n"
192 " tmpPnLPoints = 0;\n"
193 " FOR r IN (1, NumberOfRangeBounds, 1) DO\n"
194 " ri = (d - 1) * NumberOfRangeBounds + r;\n"
195 " IF Fixing[d] > RangeLowerBounds[ri] AND Fixing[d] <= RangeUpperBounds[ri] THEN\n"
196 " tmpPnL = tmpPnL + RangeLeverages[ri] * FixingAmount * (Fixing[d] - RangeStrikes[ri]);\n"
197 " tmpPnLPoints = tmpPnLPoints + RangeLeverages[ri] / abs(RangeLeverages[ri]) * (Fixing[d] - RangeStrikes[ri]);\n"
198 " END;\n"
199 " END;\n"
200 " IF wasTriggered != 1 THEN\n"
201 " PnL = tmpPnL;\n"
202 " PnLPoints = tmpPnLPoints;\n"
203 " IF PnLPoints >= 0 THEN\n"
204 " AccProfitPoints[d] = AccProfitPoints[d] + PnLPoints;\n"
205 " END;\n"
206 " IF KnockOutProfitAmountPoints > 0 AND AccProfitPoints[d] >= KnockOutProfitAmountPoints THEN\n"
207 " wasTriggered = 1;\n"
208 " Triggered[d] = 1;\n"
209 " IF TargetType == 0 THEN\n"
210 " Payoff = Payoff + LOGPAY((TargetPoints - (AccProfitPoints[d] - PnLPoints)) * PnL / PnLPoints, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
211 " nthPayoff[d] = PAY((TargetPoints - (AccProfitPoints[d] - PnLPoints)) * PnL / PnLPoints, FixingDates[d], SettlementDates[d], PayCcy);\n"
212 " AccProfitPoints[d] = TargetPoints;\n"
213 " END;\n"
214 " IF TargetType == 1 THEN\n"
215 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
216 " nthPayoff[d] = PAY(PnL, FixingDates[d], SettlementDates[d], PayCcy);\n"
217 " END;\n"
218 " ELSE\n"
219 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
220 " nthPayoff[d] = PAY(PnL, FixingDates[d], SettlementDates[d], PayCcy);\n"
221 " END;\n"
222 " END;\n"
223 " IF d < SIZE(FixingDates) THEN\n"
224 " AccProfitPoints[d + 1] = AccProfitPoints[d];\n"
225 " END;\n"
226 "END;\n"
227 "FOR a IN (SIZE(FixingAndSimDates), 1, -1) DO\n"
228 " s = DATEINDEX(FixingAndSimDates[a], _AMC_SimDates, EQ);\n"
229 " d = DATEINDEX(FixingAndSimDates[a], FixingDates, GT);\n"
230 " IF s > 0 THEN\n"
231 " IF d > 1 THEN\n"
232 " _AMC_NPV[s] = LongShort * NPVMEM( bwdPayoff, _AMC_SimDates[s], a);\n"
233 " ELSE\n"
234 " _AMC_NPV[s] = LongShort * NPVMEM( bwdPayoff, _AMC_SimDates[s], a);\n"
235 " END;\n"
236 " END;\n"
237 " d = DATEINDEX(FixingAndSimDates[a], FixingDates, EQ);\n"
238 " IF d > 0 THEN\n"
239 " bwdPayoff = bwdPayoff + nthPayoff[d];\n"
240 " END;\n"
241 "END;\n"
242 "value = LongShort * Payoff;\n"
243 "currentNotional = FixingAmount * RangeStrikes[1];";
244// clang-format on
245
246TaRF::TaRF(const std::string& currency, const std::string& fixingAmount, const std::string& targetAmount,
247 const std::string& targetPoints, const std::vector<std::string>& strikes,
248 const std::vector<std::string>& strikeDates, const QuantLib::ext::shared_ptr<Underlying>& underlying,
249 const ScheduleData& fixingDates, const std::string& settlementLag, const std::string& settlementCalendar,
250 const std::string& settlementConvention, OptionData& optionData,
251 const std::vector<std::vector<RangeBound>>& rangeBoundSet,
252 const std::vector<std::string>& rangeBoundSetDates, const std::vector<BarrierData>& barriers)
253 : currency_(currency), fixingAmount_(fixingAmount), targetAmount_(targetAmount), targetPoints_(targetPoints),
254 strikes_(strikes), underlying_(underlying), fixingDates_(fixingDates), settlementLag_(settlementLag),
255 settlementCalendar_(settlementCalendar), settlementConvention_(settlementConvention), optionData_(optionData),
256 rangeBoundSet_(rangeBoundSet), barriers_(barriers) {
257 QL_REQUIRE(strikes_.size() == strikeDates_.size(), "TaRF: strike size (" << strikes_.size()
258 << ") does not match strikeDates size ("
259 << strikeDates_.size() << ")");
260 QL_REQUIRE(rangeBoundSet_.size() == rangeBoundSetDates_.size(),
261 "TaRF: rangeBoundSet size (" << rangeBoundSet_.size() << ") does not match rangeBoundSetDates size ("
262 << rangeBoundSetDates_.size());
263 QL_REQUIRE(targetAmount_.empty() || targetPoints_.empty(),
264 "TaRF: both ttargetAmount, targetPoints is populated, only one is allowed");
265 initIndices();
266}
267
268void TaRF::build(const QuantLib::ext::shared_ptr<EngineFactory>& factory) {
269
270 // 1 inits
271
272 clear();
273 initIndices();
274
275 // 2 build rangeBounds and strikes vectors according to fixing date schedule
276
277 std::vector<QuantLib::Date> fixingSchedulePlusInf = makeSchedule(fixingDates_).dates();
278 fixingSchedulePlusInf.push_back(Date::maxDate());
279 std::vector<std::vector<RangeBound>> rangeBoundSet = buildScheduledVectorNormalised<std::vector<RangeBound>>(
280 rangeBoundSet_, rangeBoundSetDates_, fixingSchedulePlusInf, std::vector<RangeBound>());
281 std::vector<std::string> strikes =
282 buildScheduledVectorNormalised<std::string>(strikes_, strikeDates_, fixingSchedulePlusInf, "");
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 // 3 populate range-bound data (per fixing date)
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 // 4 set parameters
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
333 numbers_.emplace_back("Number", "FixingAmount", fixingAmount_);
334 numbers_.emplace_back("Number", "LongShort",
335 parsePositionType(optionData_.longShort()) == Position::Long ? "1" : "-1");
336
337 currencies_.emplace_back("Currency", "PayCcy", currency_);
338
339 events_.emplace_back("FixingDates", fixingDates_);
340 events_.emplace_back("SettlementDates", "FixingDates", settlementLag_.empty() ? "0D" : settlementLag_,
341 settlementCalendar_.empty() ? "NullCalendar" : settlementCalendar_,
343
344 std::string knockOutProfitAmount = "0", knockOutProfitAmountPoints = "0", knockOutProfitEvents = "0";
345 for (auto const& b : barriers_) {
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 // 4a compute both target amount and points from given trade data, it depends on the variant which we use below
359
360 Real targetAmount = 0.0, targetPoints = 0.0;
361 if (!targetAmount_.empty()) {
362 targetAmount = parseReal(targetAmount_);
363 targetPoints = targetAmount / parseReal(fixingAmount_);
364 } else if (!targetPoints_.empty()) {
365 targetPoints = parseReal(targetPoints_);
366 targetAmount = targetPoints * parseReal(fixingAmount_);
367 }
368
369 // 4b choose the variant and check barrier types, set target amount or points dependent on variant
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 // 4c set target type
389
390 std::string targetType;
391 if (optionData_.payoffType() == "TargetTruncated")
392 targetType = "-1";
393 else if (optionData_.payoffType() == "TargetExact")
394 targetType = "0";
395 else if (optionData_.payoffType() == "TargetFull")
396 targetType = "1";
397 else {
398 QL_FAIL("invalid payoffType, expected TargetTruncated, TargetExact, TargetFull");
399 }
400 numbers_.emplace_back("Number", "TargetType", targetType);
401
402 // 5 set product tag
403
404 productTag_ = "SingleAssetOptionCG({AssetClass})";
405
406 // 6 set script
407
408 script_.clear();
409
410 script_[""] = ScriptedTradeScriptData(scriptToUse, "value",
411 {{"currentNotional", "currentNotional"},
412 {"notionalCurrency", "PayCcy"},
413 {"FixingAmount", "FixingAmount"},
414 {"Fixing", "Fixing"},
415 {"Triggered", "Triggered"}},
416 {});
417
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 // 7 build trade
429
430 ScriptedTrade::build(factory);
431}
432
433void TaRF::initIndices() { indices_.emplace_back("Index", "Underlying", scriptedIndexName(underlying_)); }
434
436 Trade::fromXML(node);
437 XMLNode* dataNode = XMLUtils::getChildNode(node, tradeType() + "Data");
438 QL_REQUIRE(dataNode, tradeType() + "Data node not found");
439 currency_ = XMLUtils::getChildValue(dataNode, "Currency", true);
440 fixingAmount_ = XMLUtils::getChildValue(dataNode, "FixingAmount", true);
441 targetAmount_ = XMLUtils::getChildValue(dataNode, "TargetAmount", false);
442 targetPoints_ = XMLUtils::getChildValue(dataNode, "TargetPoints", false);
443 QL_REQUIRE(targetAmount_.empty() || targetPoints_.empty(),
444 "both TargetAmount and TargetPoints are given, only one of these is allowed at the same time");
445 strikes_ = {XMLUtils::getChildValue(dataNode, "Strike", false)};
446 if (XMLUtils::getChildNode(dataNode, "Strikes")) {
447 QL_REQUIRE(strikes_.front().empty(),
448 "both Strike and Strikes nodes are given, only one of these is allowed at the same time.");
449 strikes_ = XMLUtils::getChildrenValuesWithAttributes(dataNode, "Strikes", "Strike", "startDate", strikeDates_);
450 QL_REQUIRE(!strikes_.empty(), "noch Strike nodes under Strikes given.");
451 }
452 strikeDates_.resize(strikes_.size());
453 XMLNode* tmp = XMLUtils::getChildNode(dataNode, "Underlying");
454 if (!tmp)
455 tmp = XMLUtils::getChildNode(dataNode, "Name");
456 UnderlyingBuilder underlyingBuilder;
457 underlyingBuilder.fromXML(tmp);
458 underlying_ = underlyingBuilder.underlying();
459
460 fixingDates_.fromXML(XMLUtils::getChildNode(dataNode, "ScheduleData"));
461 settlementLag_ = XMLUtils::getChildValue(dataNode, "SettlementLag", false);
462 settlementCalendar_ = XMLUtils::getChildValue(dataNode, "SettlementCalendar", false);
463 settlementConvention_ = XMLUtils::getChildValue(dataNode, "SettlementConvention", false);
464 optionData_.fromXML(XMLUtils::getChildNode(dataNode, "OptionData"));
465 std::vector<XMLNode*> rangeBounds = {XMLUtils::getChildNode(dataNode, "RangeBounds")};
466 if (XMLUtils::getChildNode(dataNode, "RangeBoundSet")) {
467 QL_REQUIRE(rangeBounds.front() == nullptr,
468 "both RangeBounds and RangeBoundSet nodes are given, only one allowed at the same time");
469 rangeBounds = XMLUtils::getChildrenNodesWithAttributes(dataNode, "RangeBoundSet", "RangeBounds", "startDate",
471 QL_REQUIRE(!rangeBounds.empty(), "no RangeBounds subnode under RangeBoundSets given");
472 }
473 QL_REQUIRE(rangeBounds.front() != nullptr, "either RangeBounds or RangeBoundSet nodes required");
474 rangeBoundSetDates_.resize(rangeBounds.size());
475 for (auto const& r : rangeBounds) {
476 rangeBoundSet_.push_back(std::vector<RangeBound>());
477 auto rb = XMLUtils::getChildrenNodes(r, "RangeBound");
478 for (auto const& n : rb) {
479 rangeBoundSet_.back().push_back(RangeBound());
480 rangeBoundSet_.back().back().fromXML(n);
481 }
482 }
483 auto barriersNode = XMLUtils::getChildNode(dataNode, "Barriers");
484 QL_REQUIRE(barriersNode, "No Barriers node");
485 auto barriers = XMLUtils::getChildrenNodes(barriersNode, "BarrierData");
486 for (auto const& n : barriers) {
487 barriers_.push_back(BarrierData());
488 barriers_.back().fromXML(n);
489 }
490 initIndices();
491}
492
494 XMLNode* node = Trade::toXML(doc);
495 XMLNode* dataNode = doc.allocNode(tradeType() + "Data");
496 XMLUtils::appendNode(node, dataNode);
497 XMLUtils::addChild(doc, dataNode, "Currency", currency_);
498 XMLUtils::addChild(doc, dataNode, "FixingAmount", fixingAmount_);
499 if (!targetAmount_.empty())
500 XMLUtils::addChild(doc, dataNode, "TargetAmount", targetAmount_);
501 if (!targetPoints_.empty())
502 XMLUtils::addChild(doc, dataNode, "TargetPoints", targetPoints_);
503 if (!strikes_.front().empty())
504 XMLUtils::addChildrenWithAttributes(doc, dataNode, "Strikes", "Strike", strikes_, "startDate", strikeDates_);
505 XMLUtils::appendNode(dataNode, underlying_->toXML(doc));
507 if (!settlementLag_.empty())
508 XMLUtils::addChild(doc, dataNode, "SettlementLag", settlementLag_);
509 if (!settlementCalendar_.empty())
510 XMLUtils::addChild(doc, dataNode, "SettlementCalendar", settlementCalendar_);
511 if (!settlementConvention_.empty())
512 XMLUtils::addChild(doc, dataNode, "SettlementConvention", settlementConvention_);
513 XMLUtils::appendNode(dataNode, optionData_.toXML(doc));
514 XMLNode* rangeBoundSet = doc.allocNode("RangeBoundSet");
515 for (Size i = 0; i < rangeBoundSet_.size(); ++i) {
516 XMLNode* rangeBoundsNode = doc.allocNode("RangeBounds");
517 for (auto& n : rangeBoundSet_[i]) {
518 XMLUtils::appendNode(rangeBoundsNode, n.toXML(doc));
519 }
520 if (!rangeBoundSetDates_[i].empty())
521 XMLUtils::addAttribute(doc, rangeBoundsNode, "startDate", rangeBoundSetDates_[i]);
522 XMLUtils::appendNode(rangeBoundSet, rangeBoundsNode);
523 }
524 XMLUtils::appendNode(dataNode, rangeBoundSet);
525 XMLNode* barriers = doc.allocNode("Barriers");
526 for (auto& n : barriers_) {
527 XMLUtils::appendNode(barriers, n.toXML(doc));
528 }
529 XMLUtils::appendNode(dataNode, barriers);
530 return node;
531}
532
533} // namespace data
534} // namespace ore
Serializable obejct holding barrier data.
Definition: barrierdata.hpp:34
Serializable object holding option data.
Definition: optiondata.hpp:42
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
Serializable obejct holding range bound data.
Definition: rangebound.hpp:39
Serializable schedule data.
Definition: schedule.hpp:202
virtual void fromXML(XMLNode *node) override
Definition: schedule.cpp:179
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: schedule.cpp:198
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
std::string settlementConvention_
Definition: tarf.hpp:62
void initIndices()
Definition: tarf.cpp:433
OptionData optionData_
Definition: tarf.hpp:63
std::vector< std::string > strikeDates_
Definition: tarf.hpp:59
std::string currency_
Definition: tarf.hpp:58
std::vector< std::string > strikes_
Definition: tarf.hpp:59
ScheduleData fixingDates_
Definition: tarf.hpp:61
void fromXML(XMLNode *node) override
Definition: tarf.cpp:435
QuantLib::ext::shared_ptr< Underlying > underlying_
Definition: tarf.hpp:60
XMLNode * toXML(XMLDocument &doc) const override
Definition: tarf.cpp:493
TaRF(const std::string &tradeType="TaRF")
Definition: tarf.hpp:39
std::string settlementLag_
Definition: tarf.hpp:62
std::string targetAmount_
Definition: tarf.hpp:58
std::string targetPoints_
Definition: tarf.hpp:58
std::vector< BarrierData > barriers_
Definition: tarf.hpp:66
std::vector< std::string > rangeBoundSetDates_
Definition: tarf.hpp:65
std::vector< std::vector< RangeBound > > rangeBoundSet_
Definition: tarf.hpp:64
std::string fixingAmount_
Definition: tarf.hpp:58
std::string settlementCalendar_
Definition: tarf.hpp:62
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Definition: tarf.cpp:268
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 void addChildrenWithAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
Definition: xmlutils.cpp:510
static void addAttribute(XMLDocument &doc, XMLNode *node, const string &attrName, const string &attrValue)
Definition: xmlutils.cpp:412
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 vector< string > getChildrenValuesWithAttributes(XMLNode *node, const string &names, const string &name, const string &attrName, vector< string > &attrs, bool mandatory=false)
Definition: xmlutils.cpp:563
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
static vector< XMLNode * > getChildrenNodesWithAttributes(XMLNode *node, const string &names, const string &name, const string &attrName, vector< string > &attrs, bool mandatory=false)
Definition: xmlutils.cpp:437
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Definition: parsers.cpp:404
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
@ data
Definition: log.hpp:77
QL_DEPRECATED_ENABLE_WARNING std::string scriptedIndexName(const QuantLib::ext::shared_ptr< Underlying > &underlying)
Definition: utilities.cpp:614
Schedule makeSchedule(const ScheduleDates &data)
Definition: schedule.cpp:263
Serializable Credit Default Swap.
Definition: namespaces.docs:23
some utility functions
tarf wrapper for scripted trade
vector< Real > strikes