22#include <boost/lexical_cast.hpp>
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"
39 "FOR d IN (1, SIZE(FixingDates), 1) DO\n"
40 " Fixing[d] = Underlying(FixingDates[d]);\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"
48 " IF wasTriggered != 1 THEN\n"
51 " AccProfit = AccProfit + PnL;\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"
61 " IF TargetType == 1 THEN\n"
62 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
65 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
69 "value = LongShort * Payoff;\n"
70 "currentNotional = FixingAmount * RangeStrikes[1];";
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"
81 "FOR d IN (1, SIZE(FixingDates), 1) DO\n"
82 " Fixing[d] = Underlying(FixingDates[d]);\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"
90 " IF wasTriggered != 1 THEN\n"
93 " AccProfit[d] = AccProfit[d] + PnL;\n"
94 " Hits[d] = Hits[d] + 1;\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"
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"
110 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
111 " nthPayoff[d] = PAY(PnL, FixingDates[d], SettlementDates[d], PayCcy);\n"
114 " IF d < SIZE(FixingDates) THEN\n"
115 " AccProfit[d + 1] = AccProfit[d];\n"
116 " Hits[d + 1] = Hits[d];\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"
125 " _AMC_NPV[s] = LongShort * NPVMEM( bwdPayoff, _AMC_SimDates[s], a);\n"
127 " _AMC_NPV[s] = LongShort * NPVMEM( bwdPayoff, _AMC_SimDates[s], a);\n"
130 " d = DATEINDEX(FixingAndSimDates[a], FixingDates, EQ);\n"
132 " bwdPayoff = bwdPayoff + nthPayoff[d];\n"
135 "value = LongShort * Payoff;\n"
136 "currentNotional = FixingAmount * RangeStrikes[1];";
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"
146 "FOR d IN (1, SIZE(FixingDates), 1) DO\n"
147 " Fixing[d] = Underlying(FixingDates[d]);\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"
157 " IF wasTriggered != 1 THEN\n"
159 " PnLPoints = tmpPnLPoints;\n"
160 " IF PnLPoints >= 0 THEN\n"
161 " AccProfitPoints = AccProfitPoints + PnLPoints;\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"
169 " IF TargetType == 1 THEN\n"
170 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
173 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
177 "value = LongShort * Payoff;\n"
178 "currentNotional = FixingAmount * RangeStrikes[1];";
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"
189 "FOR d IN (1, SIZE(FixingDates), 1) DO\n"
190 " Fixing[d] = Underlying(FixingDates[d]);\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"
200 " IF wasTriggered != 1 THEN\n"
202 " PnLPoints = tmpPnLPoints;\n"
203 " IF PnLPoints >= 0 THEN\n"
204 " AccProfitPoints[d] = AccProfitPoints[d] + PnLPoints;\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"
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"
219 " Payoff = Payoff + LOGPAY(PnL, FixingDates[d], SettlementDates[d], PayCcy, 0, Cashflow);\n"
220 " nthPayoff[d] = PAY(PnL, FixingDates[d], SettlementDates[d], PayCcy);\n"
223 " IF d < SIZE(FixingDates) THEN\n"
224 " AccProfitPoints[d + 1] = AccProfitPoints[d];\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"
232 " _AMC_NPV[s] = LongShort * NPVMEM( bwdPayoff, _AMC_SimDates[s], a);\n"
234 " _AMC_NPV[s] = LongShort * NPVMEM( bwdPayoff, _AMC_SimDates[s], a);\n"
237 " d = DATEINDEX(FixingAndSimDates[a], FixingDates, EQ);\n"
239 " bwdPayoff = bwdPayoff + nthPayoff[d];\n"
242 "value = LongShort * Payoff;\n"
243 "currentNotional = FixingAmount * RangeStrikes[1];";
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) {
258 <<
") does not match strikeDates size ("
261 "TaRF: rangeBoundSet size (" <<
rangeBoundSet_.size() <<
") does not match rangeBoundSetDates size ("
264 "TaRF: both ttargetAmount, targetPoints is populated, only one is allowed");
268void TaRF::build(
const QuantLib::ext::shared_ptr<EngineFactory>& factory) {
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>();
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.");
294 std::vector<std::string> rangeStrikes, rangeUpperBounds, rangeLowerBounds, rangeLeverages;
295 for (Size i = 0; i < rangeBoundSet.size(); ++i) {
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])));
303 rangeStrikes.push_back(boost::lexical_cast<std::string>(
parseReal(
strikes[i])));
305 QL_FAIL(
"insufficient strike information");
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()));
315 numberOfRangeBounds = rangeLowerBounds.size();
318 numberOfRangeBounds * (i + 1) == rangeLowerBounds.size(),
319 "Each RangeBounds subnode (under RangeBoundSets) must contain the same number of RangeBound nodes");
323 QL_REQUIRE(numberOfRangeBounds != Null<Size>(),
"internal error: numberOfRangeBounds not set.");
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);
334 numbers_.emplace_back(
"Number",
"LongShort",
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());
354 QL_FAIL(
"invalid barrier definition, expected CumulatedProfitCap or FixingCap with exactly one level");
360 Real targetAmount = 0.0, targetPoints = 0.0;
371 std::string scriptToUse, amcScriptToUse;
372 if (knockOutProfitAmountPoints !=
"0") {
373 scriptToUse = tarf_script_points;
374 amcScriptToUse = tarf_script_points_amc;
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);
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);
390 std::string targetType;
398 QL_FAIL(
"invalid payoffType, expected TargetTruncated, TargetExact, TargetFull");
400 numbers_.emplace_back(
"Number",
"TargetType", targetType);
411 {{
"currentNotional",
"currentNotional"},
412 {
"notionalCurrency",
"PayCcy"},
413 {
"FixingAmount",
"FixingAmount"},
414 {
"Fixing",
"Fixing"},
415 {
"Triggered",
"Triggered"}},
419 amcScriptToUse,
"value",
420 {{
"currentNotional",
"currentNotional"},
421 {
"notionalCurrency",
"PayCcy"},
422 {
"FixingAmount",
"FixingAmount"},
423 {
"Fixing",
"Fixing"},
424 {
"Triggered",
"Triggered"}},
438 QL_REQUIRE(dataNode,
tradeType() +
"Data node not found");
444 "both TargetAmount and TargetPoints are given, only one of these is allowed at the same time");
447 QL_REQUIRE(
strikes_.front().empty(),
448 "both Strike and Strikes nodes are given, only one of these is allowed at the same time.");
450 QL_REQUIRE(!
strikes_.empty(),
"noch Strike nodes under Strikes given.");
457 underlyingBuilder.
fromXML(tmp);
467 QL_REQUIRE(rangeBounds.front() ==
nullptr,
468 "both RangeBounds and RangeBoundSet nodes are given, only one allowed at the same time");
471 QL_REQUIRE(!rangeBounds.empty(),
"no RangeBounds subnode under RangeBoundSets given");
473 QL_REQUIRE(rangeBounds.front() !=
nullptr,
"either RangeBounds or RangeBoundSet nodes required");
475 for (
auto const& r : rangeBounds) {
478 for (
auto const& n : rb) {
484 QL_REQUIRE(barriersNode,
"No Barriers node");
486 for (
auto const& n : barriers) {
Serializable obejct holding barrier data.
Serializable object holding option data.
const string & payoffType() const
const string & longShort() const
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
Serializable obejct holding range bound data.
Serializable schedule data.
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
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_
std::vector< std::string > strikeDates_
std::vector< std::string > strikes_
ScheduleData fixingDates_
void fromXML(XMLNode *node) override
QuantLib::ext::shared_ptr< Underlying > underlying_
XMLNode * toXML(XMLDocument &doc) const override
TaRF(const std::string &tradeType="TaRF")
std::string settlementLag_
std::string targetAmount_
std::string targetPoints_
std::vector< BarrierData > barriers_
std::vector< std::string > rangeBoundSetDates_
std::vector< std::vector< RangeBound > > rangeBoundSet_
std::string fixingAmount_
std::string settlementCalendar_
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
const string & tradeType() const
const QuantLib::ext::shared_ptr< Underlying > & underlying()
void fromXML(XMLNode *node) override
Small XML Document wrapper class.
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
static void addChildrenWithAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
static void addAttribute(XMLDocument &doc, XMLNode *node, const string &attrName, const string &attrValue)
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
static XMLNode * getChildNode(XMLNode *n, const string &name="")
static vector< string > getChildrenValuesWithAttributes(XMLNode *node, const string &names, const string &name, const string &attrName, vector< string > &attrs, bool mandatory=false)
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
static void appendNode(XMLNode *parent, XMLNode *child)
static vector< XMLNode * > getChildrenNodesWithAttributes(XMLNode *node, const string &names, const string &name, const string &attrName, vector< string > &attrs, bool mandatory=false)
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Real parseReal(const string &s)
Convert text to Real.
QL_DEPRECATED_ENABLE_WARNING std::string scriptedIndexName(const QuantLib::ext::shared_ptr< Underlying > &underlying)
Schedule makeSchedule(const ScheduleDates &data)
Serializable Credit Default Swap.
tarf wrapper for scripted trade