1414 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
1515*/
1616
17+ #include < ored/portfolio/barrieroption.hpp>
1718#include < ored/portfolio/builders/fxbarrieroption.hpp>
1819#include < ored/portfolio/fxkikobarrieroption.hpp>
1920#include < ored/portfolio/genericbarrieroption.hpp>
21+ #include < ored/utilities/parsers.hpp>
2022namespace ore {
2123namespace data {
2224
25+ struct GenericBarrierOptionData {
26+ QuantLib::ext::shared_ptr<Underlying> underlying;
27+ OptionData optionData;
28+ std::vector<BarrierData> barriers;
29+ ScheduleData barrierMonitoringDates;
30+ BarrierData transatlanticBarrier;
31+ std::string payCurrency;
32+ std::string settlementDate;
33+ std::string quantity;
34+ std::string strike;
35+ std::string amount;
36+ std::string kikoType;
37+ };
2338
24- QuantLib::ext::shared_ptr<ore::data::Trade> FxBarrierOptionScriptedEngineBuilder::build (const Trade* trade, const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory){
25- auto fxKiKoBarrierOption = dynamic_cast <const ore::data::FxKIKOBarrierOption*>(trade);
39+ GenericBarrierOptionData parseFxBarrierOption (const ore::data::FxOptionWithBarrier* fxBarrierOption) {
40+ QL_REQUIRE (fxBarrierOption != nullptr , " FxBarrierOptionScriptedEngineBuilder: internal error, could not "
41+ " cast to ore::data::FxOptionWithBarrier. Contact dev." );
42+ GenericBarrierOptionData data;
43+ std::string indexName = fxBarrierOption->fxIndex ().empty ()
44+ ? " GENERIC-" + fxBarrierOption->boughtCurrency () + " -" + fxBarrierOption->soldCurrency ()
45+ : fxBarrierOption->fxIndex ().substr (3 );
46+ data.underlying = QuantLib::ext::make_shared<FXUnderlying>(" FX" , indexName, 1.0 );
47+ data.optionData = fxBarrierOption->option ();
48+ // Barrier
49+ const auto & barrier = fxBarrierOption->barrier ();
50+ if (barrier.levels ().size () == 1 ){
51+ data.barriers .push_back (barrier);
52+ } else if (barrier.levels ().size () == 2 ){
53+ auto doubleBarrierType = parseDoubleBarrierType (barrier.type ());
54+ string lowBarrierType = doubleBarrierType == DoubleBarrier::KIKO || doubleBarrierType == DoubleBarrier::KnockIn
55+ ? " DownAndIn"
56+ : " DownAndOut" ;
57+ string highBarrierType = doubleBarrierType == DoubleBarrier::KIKO || doubleBarrierType == DoubleBarrier::KnockOut
58+ ? " UpAndOut"
59+ : " UpAndIn" ;
2660
27- QL_REQUIRE (fxKiKoBarrierOption != nullptr ,
28- " FxKIKOBarrierOptionScriptedEngineBuilder: internal error, could not "
29- " cast to ore::data::FxKIKOBarrierOption. Contact dev." );
61+ BarrierData lowBarrier (lowBarrierType, {barrier.levels ().front ().value ()}, barrier.rebate (), {barrier.levels ().front ()},
62+ barrier.style (), barrier.strictComparison (), barrier.overrideTriggered ());
63+ BarrierData highBarrier (highBarrierType, {barrier.levels ().back ().value ()}, barrier.rebate (),
64+ {barrier.levels ().back ()}, barrier.style (), barrier.strictComparison (),
65+ barrier.overrideTriggered ());
66+ data.barriers .push_back (lowBarrier);
67+ data.barriers .push_back (highBarrier);
68+ } else {
69+ QL_FAIL (" FxBarrierOptionScriptedEngineBuilder: only single and double barriers are supported. Please check trade xml." );
70+ }
71+
72+ std::string startDate = to_string (fxBarrierOption->startDate ());
73+ std::string exerciseDate = data.optionData .exerciseDates ().front ();
74+
75+ ScheduleRules rule (startDate, exerciseDate, " 1D" , fxBarrierOption->calendarStr (), " Following" , " Unadjusted" ,
76+ " Backward" );
77+ data.barrierMonitoringDates = ScheduleData (rule);
78+ // ! Empty transatlantic
79+ data.transatlanticBarrier = BarrierData ();
80+ data.payCurrency = fxBarrierOption->soldCurrency ();
81+ Date expiryDate = parseDate (exerciseDate);
82+ Date paymentDate = expiryDate;
83+ const QuantLib::ext::optional<OptionPaymentData>& opd = data.optionData .paymentData ();
84+ if (opd) {
85+ if (opd->rulesBased ()) {
86+ const Calendar& cal = opd->calendar ();
87+ QL_REQUIRE (cal != Calendar (), " Need a non-empty calendar for rules based payment date." );
88+ paymentDate = cal.advance (expiryDate, opd->lag (), Days, opd->convention ());
89+ } else {
90+ const vector<Date>& dates = opd->dates ();
91+ QL_REQUIRE (dates.size () == 1 , " Need exactly one payment date for cash settled European option." );
92+ paymentDate = dates[0 ];
93+ }
94+ QL_REQUIRE (paymentDate >= expiryDate, " Payment date must be greater than or equal to expiry date." );
95+ }
96+ data.settlementDate = to_string (paymentDate);
97+ data.quantity = to_string (fxBarrierOption->boughtAmount ());
98+ data.strike = to_string (fxBarrierOption->strike ());
99+ data.amount = " " ;
100+ data.kikoType = " KoAlways" ;
101+ return data;
102+ }
103+
104+ GenericBarrierOptionData parseFxKIKOBarrierOptionData (const ore::data::FxKIKOBarrierOption* fxKiKoBarrierOption) {
105+ QL_REQUIRE (fxKiKoBarrierOption != nullptr , " FxKIKOBarrierOptionScriptedEngineBuilder: internal error, could not "
106+ " cast to ore::data::FxKIKOBarrierOption. Contact dev." );
107+ GenericBarrierOptionData data;
30108 std::string indexName =
31109 fxKiKoBarrierOption->fxIndex ().empty ()
32110 ? " GENERIC-" + fxKiKoBarrierOption->boughtCurrency () + " -" + fxKiKoBarrierOption->soldCurrency ()
33111 : fxKiKoBarrierOption->fxIndex ().substr (3 );
34- QuantLib::ext::shared_ptr<Underlying> underlying = QuantLib::ext::make_shared<FXUnderlying>(" FX" , indexName, 1.0 );
35-
36- const auto & optionData = fxKiKoBarrierOption->option ();
112+ data.underlying = QuantLib::ext::make_shared<FXUnderlying>(" FX" , indexName, 1.0 );
113+ data.optionData = fxKiKoBarrierOption->option ();
37114
38115 std::string startDate = fxKiKoBarrierOption->startDate ();
39- std::string exerciseDate = optionData.exerciseDates ().front ();
40-
41- ScheduleRules rule (startDate, exerciseDate, " 1D" , fxKiKoBarrierOption->calendar (), " Following" , " Unadjusted" , " Backward" );
42- ScheduleData barrierMonitoringDates (rule);
43-
44- // ! Empty transatlantic barrier
45- auto transatlanticBarrier = BarrierData ();
46- // ! Observation date for schedule monitoring dates only at the end
116+ std::string exerciseDate = data.optionData .exerciseDates ().front ();
47117
48- std::string domesticCurrency = fxKiKoBarrierOption->soldCurrency ();
118+ ScheduleRules rule (startDate, exerciseDate, " 1D" , fxKiKoBarrierOption->calendar (), " Following" , " Unadjusted" ,
119+ " Backward" );
120+ data.barrierMonitoringDates = ScheduleData (rule);
49121
122+ // ! Empty transatlantic
123+ data.barriers = fxKiKoBarrierOption->barriers ();
124+ data.transatlanticBarrier = BarrierData ();
125+ data.payCurrency = fxKiKoBarrierOption->soldCurrency ();
50126 Date expiryDate = parseDate (exerciseDate);
51127 Date paymentDate = expiryDate;
52- const QuantLib::ext::optional<OptionPaymentData>& opd = optionData.paymentData ();
128+ const QuantLib::ext::optional<OptionPaymentData>& opd = data. optionData .paymentData ();
53129 if (opd) {
54130 if (opd->rulesBased ()) {
55131 const Calendar& cal = opd->calendar ();
@@ -62,12 +138,30 @@ QuantLib::ext::shared_ptr<ore::data::Trade> FxBarrierOptionScriptedEngineBuilder
62138 }
63139 QL_REQUIRE (paymentDate >= expiryDate, " Payment date must be greater than or equal to expiry date." );
64140 }
65- auto qty = fxKiKoBarrierOption->boughtAmount ();
66- auto strike = fxKiKoBarrierOption->strike ();
67- std::vector<BarrierData> barriers = fxKiKoBarrierOption->barriers ();
141+ data.settlementDate = to_string (paymentDate);
142+ data.quantity = to_string (fxKiKoBarrierOption->boughtAmount ());
143+ data.strike = to_string (fxKiKoBarrierOption->strike ());
144+ data.amount = " " ;
145+ data.kikoType = " KoAlways" ;
146+ return data;
147+ }
148+
149+ QuantLib::ext::shared_ptr<ore::data::Trade>
150+ FxBarrierOptionScriptedEngineBuilder::build (const Trade* trade,
151+ const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
152+ GenericBarrierOptionData data;
153+ if (auto fxKiKoBarrierOption = dynamic_cast <const ore::data::FxKIKOBarrierOption*>(trade);
154+ fxKiKoBarrierOption != nullptr ) {
155+ data = parseFxKIKOBarrierOptionData (fxKiKoBarrierOption);
156+ } else if (auto fxBarrierOption = dynamic_cast <const ore::data::FxOptionWithBarrier*>(trade);
157+ fxBarrierOption != nullptr ) {
158+ data = parseFxBarrierOption (fxBarrierOption);
159+ } else {
160+ QL_FAIL (" FxKIKOBarrierOptionScriptedEngineBuilder::build(): trade is not a FxKIKOBarrierOption" );
161+ }
68162 auto barrierOption = QuantLib::ext::make_shared<GenericBarrierOption>(
69- underlying, optionData, barriers, barrierMonitoringDates, transatlanticBarrier, domesticCurrency ,
70- to_string (paymentDate), to_string (qty), to_string ( strike), " " , " KoAlways " );
163+ data. underlying , data. optionData , data. barriers , data. barrierMonitoringDates , data. transatlanticBarrier ,
164+ data. payCurrency , data. settlementDate , data. quantity , data. strike , data. amount , data. kikoType );
71165
72166 barrierOption->build (engineFactory);
73167 return barrierOption;
0 commit comments