@@ -30,7 +30,7 @@ namespace data {
3030
3131 static const std::string mcscript =
3232 " REQUIRE PayoffType == 0 OR PayoffType == 1;\n "
33- " REQUIRE TransatlanticBarrierType >= 0 AND TransatlanticBarrierType <= 4 ;\n "
33+ " REQUIRE SIZE(Underlyings) == SIZE(TransatlanticBarrierType) ;\n "
3434 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierLevels) / SIZE(Underlyings);\n "
3535 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebates);\n "
3636 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebateCurrencies);\n "
@@ -90,10 +90,11 @@ namespace data {
9090 " \n "
9191 " TransatlanticActive = 1;\n "
9292 " FOR k IN (1, SIZE(Underlyings), 1) DO\n "
93- " IF { TransatlanticBarrierType == 1 AND Underlyings[k](ExpiryDate) >= TransatlanticBarrierLevel[k] } OR\n "
94- " { TransatlanticBarrierType == 2 AND Underlyings[k](ExpiryDate) <= TransatlanticBarrierLevel[k] } OR\n "
95- " { TransatlanticBarrierType == 3 AND Underlyings[k](ExpiryDate) < TransatlanticBarrierLevel[k] } OR\n "
96- " { TransatlanticBarrierType == 4 AND Underlyings[k](ExpiryDate) > TransatlanticBarrierLevel[k] } THEN\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 "
9798 " TransatlanticActive = 0;\n "
9899 " END;\n "
99100 " END;\n "
@@ -116,7 +117,7 @@ namespace data {
116117
117118 static const std::string fdscript =
118119 " REQUIRE PayoffType == 0 OR PayoffType == 1;\n "
119- " REQUIRE TransatlanticBarrierType >= 0 AND TransatlanticBarrierType <= 4 ;\n "
120+ " REQUIRE SIZE(Underlyings) == SIZE(TransatlanticBarrierType) ;\n "
120121 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierLevels) / SIZE(Underlyings);\n "
121122 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebates);\n "
122123 " REQUIRE SIZE(BarrierTypes) == SIZE(BarrierRebateCurrencies);\n "
@@ -135,10 +136,11 @@ namespace data {
135136 " \n "
136137 " TransatlanticActive = 1;\n "
137138 " FOR k IN (1, SIZE(Underlyings), 1) DO\n "
138- " IF { TransatlanticBarrierType == 1 AND Underlyings[k](ExpiryDate) >= TransatlanticBarrierLevel[k] } OR\n "
139- " { TransatlanticBarrierType == 2 AND Underlyings[k](ExpiryDate) <= TransatlanticBarrierLevel[k] } OR\n "
140- " { TransatlanticBarrierType == 3 AND Underlyings[k](ExpiryDate) < TransatlanticBarrierLevel[k] } OR\n "
141- " { TransatlanticBarrierType == 4 AND Underlyings[k](ExpiryDate) > TransatlanticBarrierLevel[k] } THEN\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 "
142144 " TransatlanticActive = 0;\n "
143145 " END;\n "
144146 " END;\n "
@@ -297,31 +299,61 @@ void GenericBarrierOption::build(const boost::shared_ptr<EngineFactory>& factory
297299 (quantity_.empty () && strike_.empty () && !amount_.empty ()),
298300 " Need no Quantity, no Strike, Amount for PayoffType = CashOrNothing" );
299301
300- std::string transatlanticBarrierType = " 0" ;
302+ std::vector<std:: string> transatlanticBarrierType (underlyings_. size (), " 0" ) ;
301303 std::vector<std::string> transatlanticBarrierLevel (underlyings_.size (), " 0" );
302304 std::string transatlanticBarrierRebate = " 0.0" ;
303305 std::string transatlanticBarrierRebateCurrency = payCurrency_;
304- if (!transatlanticBarrier_.type ().empty ()) {
305- if (transatlanticBarrier_.type () == " DownAndIn" )
306- transatlanticBarrierType = " 1" ;
307- else if (transatlanticBarrier_.type () == " UpAndIn" )
308- transatlanticBarrierType = " 2" ;
309- else if (transatlanticBarrier_.type () == " DownAndOut" )
310- transatlanticBarrierType = " 3" ;
311- else if (transatlanticBarrier_.type () == " UpAndOut" )
312- transatlanticBarrierType = " 4" ;
313- else {
314- QL_FAIL (" Transatlantic BarrierType (" << transatlanticBarrier_.type ()
315- << " ) must be DownAndIn, UpAndIn, DownAndOut, UpAndOut" );
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 ]);
316327 }
317- QL_REQUIRE (transatlanticBarrier_.levels ().size () == underlyings_.size (),
318- " Transatlantic Barrier must have exactly 1 level for each underlying, got " << transatlanticBarrier_.levels ().size ());
319328 transatlanticBarrierLevel.clear ();
320- for (const auto & l : transatlanticBarrier_.levels ())
321- transatlanticBarrierLevel.push_back (boost::lexical_cast<std::string>(l.value ()));
322- transatlanticBarrierRebate = boost::lexical_cast<std::string>(transatlanticBarrier_.rebate ());
323- if (!transatlanticBarrier_.rebateCurrency ().empty ())
324- transatlanticBarrierRebateCurrency = transatlanticBarrier_.rebateCurrency ();
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 ();
325357 }
326358 numbers_.emplace_back (" Number" , " TransatlanticBarrierType" , transatlanticBarrierType);
327359 numbers_.emplace_back (" Number" , " TransatlanticBarrierLevel" , transatlanticBarrierLevel);
@@ -331,7 +363,14 @@ void GenericBarrierOption::build(const boost::shared_ptr<EngineFactory>& factory
331363 auto positionType = parsePositionType (optionData_.longShort ());
332364 numbers_.emplace_back (" Number" , " LongShort" , positionType == Position::Long ? " 1" : " -1" );
333365
334- numbers_.emplace_back (" Number" , " PutCall" , parseOptionType (optionData_.callPut ()) == Option::Call ? " 1.0" : " -1.0" );
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+ }
335374 numbers_.emplace_back (" Number" , " Quantity" , quantity_.empty () ? " 0.0" : quantity_);
336375 if (!strike_.empty ())
337376 numbers_.emplace_back (" Number" , " Strike" , strike_);
@@ -553,9 +592,11 @@ void GenericBarrierOption::fromXML(XMLNode* node) {
553592
554593 auto transatlanticBarrierNode = XMLUtils::getChildNode (dataNode, " TransatlanticBarrier" );
555594 if (transatlanticBarrierNode) {
556- auto b = XMLUtils::getChildNode (transatlanticBarrierNode, " BarrierData" );
557- if (b)
558- transatlanticBarrier_.fromXML (b);
595+ auto b = XMLUtils::getChildrenNodes (transatlanticBarrierNode, " BarrierData" );
596+ for (auto const & n : b) {
597+ transatlanticBarrier_.push_back (BarrierData ());
598+ transatlanticBarrier_.back ().fromXML (n);
599+ }
559600 }
560601
561602 payCurrency_ = XMLUtils::getChildValue (dataNode, " PayCurrency" , true );
@@ -597,9 +638,11 @@ XMLNode* GenericBarrierOption::toXML(XMLDocument& doc) {
597638 XMLUtils::addChild (doc, barriers, " KikoType" , kikoType_);
598639 XMLUtils::appendNode (dataNode, barriers);
599640
600- if (!transatlanticBarrier_.type ().empty ()) {
641+ if (!transatlanticBarrier_[ 0 ] .type ().empty ()) {
601642 XMLNode* transatlanticBarrierNode = doc.allocNode (" TransatlanticBarrier" );
602- XMLUtils::appendNode (transatlanticBarrierNode, transatlanticBarrier_.toXML (doc));
643+ for (auto & n : transatlanticBarrier_) {
644+ XMLUtils::appendNode (transatlanticBarrierNode, n.toXML (doc));
645+ }
603646 XMLUtils::appendNode (dataNode, transatlanticBarrierNode);
604647 }
605648
0 commit comments