2525#include < ql/instruments/compositeinstrument.hpp>
2626#include < ql/instruments/payoffs.hpp>
2727#include < ql/instruments/vanillaoption.hpp>
28+ #include < qle/instruments/cashsettledeuropeanoption.hpp>
2829
2930using namespace QuantLib ;
31+ using namespace QuantExt ;
3032
3133namespace ore {
3234namespace data {
@@ -57,6 +59,7 @@ void FxDigitalOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engi
5759
5860 // Handle PayoffCurrency, we might have to flip the trade here
5961 Real strike = strike_;
62+
6063 bool flipResults = false ;
6164 if (payoffCurrency_ == " " ) {
6265 DLOG (" PayoffCurrency defaulting to " << domesticCurrency_ << " for FxDigitalOption " << id ());
@@ -81,33 +84,84 @@ void FxDigitalOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engi
8184 // Exercise
8285 Date expiryDate = parseDate (option_.exerciseDates ().front ());
8386 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiryDate);
84- maturity_ = std::max (option_.premiumData ().latestPremiumDate (), expiryDate);
87+
88+ Date paymentDate = expiryDate;
89+ const boost::optional<OptionPaymentData>& opd = option_.paymentData ();
90+
91+ if (opd) {
92+ if (opd->rulesBased ()) {
93+ const Calendar& cal = opd->calendar ();
94+ QL_REQUIRE (cal != Calendar (), " Need a non-empty calendar for rules based payment date." );
95+ paymentDate = cal.advance (expiryDate, opd->lag (), Days, opd->convention ());
96+ } else {
97+ const vector<Date>& dates = opd->dates ();
98+ QL_REQUIRE (dates.size () == 1 , " Need exactly one payment date for cash settled European option." );
99+ paymentDate = dates[0 ];
100+ }
101+ QL_REQUIRE (paymentDate >= expiryDate, " Payment date must be greater than or equal to expiry date." );
102+ }
103+ maturity_ = std::max (option_.premiumData ().latestPremiumDate (), paymentDate);
85104 maturityType_ = maturity_ == expiryDate ? " Expiry Date" : " Option's Latest Premium Date" ;
86-
87- // QL does not have an FXDigitalOption, so we add a vanilla one here and wrap
88- // it in a composite.
89- QuantLib::ext::shared_ptr<Instrument> vanilla = QuantLib::ext::make_shared<VanillaOption>(payoff, exercise);
90-
91- // set pricing engines
92- QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder (tradeType_);
93- QL_REQUIRE (builder, " No builder found for " << tradeType_);
94- QuantLib::ext::shared_ptr<FxDigitalOptionEngineBuilder> fxOptBuilder =
95- QuantLib::ext::dynamic_pointer_cast<FxDigitalOptionEngineBuilder>(builder);
96- vanilla->setPricingEngine (fxOptBuilder->engine (forCcy, domCcy, flipResults));
97- setSensitivityTemplate (*fxOptBuilder);
98- addProductModelEngine (*fxOptBuilder);
99-
100- Position::Type positionType = parsePositionType (option_.longShort ());
101- Real bsInd = (positionType == QuantLib::Position::Long ? 1.0 : -1.0 );
102- Real mult = bsInd;
103-
104- std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
105- std::vector<Real> additionalMultipliers;
106- addPremiums (additionalInstruments, additionalMultipliers, mult, option_.premiumData (), -bsInd, domCcy,
107- engineFactory, fxOptBuilder->configuration (MarketContext::pricing));
108-
109- instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(
110- new VanillaInstrument (vanilla, mult, additionalInstruments, additionalMultipliers));
105+ QuantLib::ext::shared_ptr<Instrument> vanilla;
106+ Real exercisePrice = Null<Real>();
107+ bool exercised = false ;
108+ QuantLib::ext::shared_ptr<FxIndex> fxIndex;
109+ if (paymentDate == expiryDate) {
110+ const boost::optional<OptionExerciseData>& oed = option_.exerciseData ();
111+ if (oed) {
112+ QL_REQUIRE (oed->date () == expiryDate, " The supplied exercise date ("
113+ << io::iso_date (oed->date ())
114+ << " ) should equal the option's expiry date ("
115+ << io::iso_date (expiryDate) << " )." );
116+ exercised = true ;
117+ exercisePrice = oed->price ();
118+ }
119+ if (option_.isAutomaticExercise ()) {
120+
121+ fxIndex = buildFxIndex (fxIndex_, domCcy.code (), forCcy.code (), engineFactory->market (),
122+ engineFactory->configuration (MarketContext::pricing));
123+ requiredFixings_.addFixingDate (expiryDate, fxIndex_, paymentDate);
124+ }
125+
126+ vanilla = QuantLib::ext::make_shared<CashSettledEuropeanOption>(type, strike, payoffAmount_, expiryDate,
127+ paymentDate, option_.isAutomaticExercise (),
128+ fxIndex, exercised, exercisePrice);
129+ // set pricing engines
130+ QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder (" FxDigitalOptionEuropeanCS" );
131+ QL_REQUIRE (builder, " No builder found for " << tradeType_);
132+ QuantLib::ext::shared_ptr<FxDigitalCSOptionEngineBuilder> fxOptBuilder =
133+ QuantLib::ext::dynamic_pointer_cast<FxDigitalCSOptionEngineBuilder>(builder);
134+ vanilla->setPricingEngine (fxOptBuilder->engine (forCcy, domCcy, flipResults));
135+ setSensitivityTemplate (*fxOptBuilder);
136+ addProductModelEngine (*fxOptBuilder);
137+ Position::Type positionType = parsePositionType (option_.longShort ());
138+ Real bsInd = (positionType == QuantLib::Position::Long ? 1.0 : -1.0 );
139+ Real mult = bsInd;
140+ std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
141+ std::vector<Real> additionalMultipliers;
142+ addPremiums (additionalInstruments, additionalMultipliers, mult, option_.premiumData (), -bsInd, domCcy,
143+ engineFactory, fxOptBuilder->configuration (MarketContext::pricing));
144+ instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(
145+ new VanillaInstrument (vanilla, mult, additionalInstruments, additionalMultipliers));
146+ } else {
147+ QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder (" FxOptionForward" );
148+ vanilla = QuantLib::ext::make_shared<QuantExt::VanillaForwardOption>(payoff, exercise, paymentDate, paymentDate);
149+ QuantLib::ext::shared_ptr<VanillaOptionEngineBuilder> fxOptBuilder =
150+ QuantLib::ext::dynamic_pointer_cast<VanillaOptionEngineBuilder>(builder);
151+ vanilla->setPricingEngine (fxOptBuilder->engine (
152+ forCcy, domCcy, envelope ().additionalField (" discount_curve" , false , std::string ()), paymentDate));
153+ setSensitivityTemplate (*fxOptBuilder);
154+ addProductModelEngine (*fxOptBuilder);
155+ Position::Type positionType = parsePositionType (option_.longShort ());
156+ Real bsInd = (positionType == QuantLib::Position::Long ? 1.0 : -1.0 );
157+ Real mult = bsInd;
158+ std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
159+ std::vector<Real> additionalMultipliers;
160+ addPremiums (additionalInstruments, additionalMultipliers, mult, option_.premiumData (), -bsInd, domCcy,
161+ engineFactory, fxOptBuilder->configuration (MarketContext::pricing));
162+ instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(
163+ new VanillaInstrument (vanilla, mult, additionalInstruments, additionalMultipliers));
164+ }
111165}
112166
113167void FxDigitalOption::fromXML (XMLNode* node) {
@@ -126,7 +180,6 @@ XMLNode* FxDigitalOption::toXML(XMLDocument& doc) const {
126180 XMLNode* node = Trade::toXML (doc);
127181 XMLNode* fxNode = doc.allocNode (" FxDigitalOptionData" );
128182 XMLUtils::appendNode (node, fxNode);
129-
130183 XMLUtils::appendNode (fxNode, option_.toXML (doc));
131184 XMLUtils::addChild (doc, fxNode, " Strike" , strike_);
132185 XMLUtils::addChild (doc, fxNode, " PayoffCurrency" , payoffCurrency_);
0 commit comments