48 vector<std::reference_wrapper<vector<string>>> attrs;
51 exerciseFees_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node,
"ExerciseFees",
"ExerciseFee",
52 {
"type",
"startDate"}, attrs, &
parseReal);
60 QL_REQUIRE(!(exDatesNode && exScheduleNode),
61 "Cannot specify both ExerciseDates and ExerciseSchedule. Only one must be used.");
141 bool removeNoticeDatesAfterLastAccrualStart) {
145 if (optionData.
style() ==
"American")
146 removeNoticeDatesAfterLastAccrualStart =
false;
153 Date lastAccrualStartDate = Date::minDate();
154 for (
auto const& l : legs) {
155 for (
auto const& c : l) {
156 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(c))
157 lastAccrualStartDate = std::max(lastAccrualStartDate, cpn->accrualStartDate());
166 BusinessDayConvention noticeBdc =
171 std::vector<QuantLib::Date> sortedExerciseDates;
174 sortedExerciseDates = schedule.dates();
178 sortedExerciseDates.push_back(
parseDate(d));
180 std::sort(sortedExerciseDates.begin(), sortedExerciseDates.end());
184 QL_REQUIRE(optionData.
style() !=
"American" || sortedExerciseDates.size() == 2,
185 "ExerciseBuilder: expected 2 exercise dates for style 'American', got " << sortedExerciseDates.size());
189 std::vector<bool> isExerciseDateAlive(sortedExerciseDates.size(),
false);
191 Date today = Settings::instance().evaluationDate();
193 for (Size i = 0; i < sortedExerciseDates.size(); i++) {
194 Date noticeDate = noticeCal.advance(sortedExerciseDates[i], -noticePeriod, noticeBdc);
196 if (optionData.
style() ==
"American" && i == 0) {
197 noticeDate = std::max(today + 1, noticeDate);
198 sortedExerciseDates[0] = std::max(today + 1, sortedExerciseDates[0]);
200 if (noticeDate > today && (noticeDate <= lastAccrualStartDate || !removeNoticeDatesAfterLastAccrualStart)) {
201 isExerciseDateAlive[i] =
true;
204 DLOG(
"Got notice date " << QuantLib::io::iso_date(noticeDate) <<
" using notice period " << noticePeriod
205 <<
", convention " << noticeBdc <<
", calendar " << noticeCal.name()
208 if (noticeDate > lastAccrualStartDate && removeNoticeDatesAfterLastAccrualStart)
210 << sortedExerciseDates[i] <<
") after last accrual start date "
211 << ore ::data::to_string(lastAccrualStartDate));
217 if (optionData.
style() ==
"European") {
218 QL_REQUIRE(
exerciseDates_.size() == 1,
"Got 'European' option style, but "
220 <<
" exercise dates. Should the style be 'Bermudan'?");
222 }
else if (optionData.
style() ==
"Bermudan" || optionData.
style().empty()) {
225 }
else if (optionData.
style() ==
"American") {
226 QL_REQUIRE(
noticeDates_.size() == 2,
"ExerciseBuilder: internal error, style is american but got "
227 <<
noticeDates_.size() <<
" notice dates, expected 2.");
231 QL_FAIL(
"ExerciseBuilder: style '"
232 << optionData.
style() <<
"' not recognized. Expected one of 'European', 'Bermudan', 'American'");
241 auto nextDate = std::lower_bound(sortedExerciseDates.begin(), sortedExerciseDates.end(), d);
242 if (nextDate != sortedExerciseDates.end()) {
249 Date cashSettlementDate = d;
252 cashSettlementDate = optionData.
paymentData()->calendar().advance(
255 auto const& dates = optionData.
paymentData()->dates();
256 auto nextDate = std::lower_bound(dates.begin(), dates.end(), d);
257 if (nextDate != dates.end())
258 cashSettlementDate = *nextDate;
261 if (p != Null<Real>())
262 cashSettlement_ = QuantLib::ext::make_shared<QuantLib::SimpleCashFlow>(p, cashSettlementDate);
263 DLOG(
"Option is cash settled, amount " << p <<
" paid on " << cashSettlementDate);
272 QL_REQUIRE(optionData.
style() !=
"American" || optionData.
exerciseFees().size() == 1,
273 "ExerciseBuilder: for style 'American' at most one exercise fee is allowed");
277 std::vector<Date> exDatesPlusInf(sortedExerciseDates);
278 exDatesPlusInf.push_back(Date::maxDate());
284 for (
auto& r : allRebates)
287 vector<string> feeType = buildScheduledVectorNormalised<string>(
292 for (Size i = 0; i < allRebates.size(); ++i) {
296 if (feeType[i].empty())
297 feeType[i] =
"Absolute";
299 if (feeType[i] ==
"Percentage") {
303 std::set<std::pair<Date, Real>> notionals;
304 for (
auto const& l : legs) {
305 for (
auto const& c : l) {
306 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(c)) {
307 if (cpn->accrualStartDate() >= sortedExerciseDates[i])
308 notionals.insert(std::make_pair(cpn->accrualStartDate(), cpn->nominal()));
313 if (notionals.empty())
316 Real feeNotional = notionals.begin()->second;
317 DLOG(
"Convert percentage rebate "
318 << allRebates[i] <<
" to absolute rebate " << allRebates[i] * feeNotional <<
" using nominal "
319 << feeNotional <<
" for exercise date " << QuantLib::io::iso_date(sortedExerciseDates[i]));
320 allRebates[i] *= feeNotional;
324 QL_REQUIRE(feeType[i] ==
"Absolute",
"fee type must be Absolute or Relative");
338 BusinessDayConvention feeSettlBdc =
346 feeSettlement_ = QuantLib::ext::make_shared<QuantLib::SimpleCashFlow>(
348 DLOG(
"Settlement fee for exercised option is " <<
feeSettlement_->amount() <<
" paid on "
355 vector<double> rebates;
356 for (Size i = 0; i < sortedExerciseDates.size(); ++i) {
357 if (isExerciseDateAlive[i])
358 rebates.push_back(allRebates[i]);
360 if (optionData.
style() ==
"American") {
362 exercise_ = QuantLib::ext::make_shared<QuantExt::RebatedExercise>(*
exercise_, rebates.front(), feeSettlPeriod,
363 feeSettlCal, feeSettlBdc);
364 auto dbgEx = QuantLib::ext::static_pointer_cast<QuantExt::RebatedExercise>(
exercise_);
365 DLOG(
"Got rebate " << dbgEx->rebate(0) <<
" for American exercise with fee settle period "
366 << feeSettlPeriod <<
", cal " << feeSettlCal <<
", bdc " << feeSettlBdc);
369 feeSettlPeriod, feeSettlCal, feeSettlBdc);
370 auto dbgEx = QuantLib::ext::static_pointer_cast<QuantExt::RebatedExercise>(
exercise_);
372 DLOG(
"Got rebate " << dbgEx->rebate(i) <<
" with payment date "
373 << QuantLib::io::iso_date(dbgEx->rebatePaymentDate(i))
374 <<
" (exercise date=" << QuantLib::io::iso_date(
exerciseDates_[i])
375 <<
") using rebate settl period " << feeSettlPeriod <<
", calendar "
376 << feeSettlCal <<
", convention " << feeSettlBdc);
QuantLib::Date exerciseDate_
ExerciseBuilder(const OptionData &optionData, const std::vector< QuantLib::Leg > legs, bool removeNoticeDatesAfterLastAccrualStart=true)
QuantLib::ext::shared_ptr< QuantLib::Exercise > exercise_
std::vector< QuantLib::Date > noticeDates_
QuantLib::ext::shared_ptr< QuantLib::CashFlow > feeSettlement_
QuantLib::ext::shared_ptr< QuantLib::CashFlow > cashSettlement_
std::vector< QuantLib::Date > exerciseDates_
Serializable object holding option data.
vector< string > exerciseFeeDates_
string exerciseFeeSettlementPeriod_
const string & exerciseFeeSettlementPeriod() const
boost::optional< OptionPaymentData > paymentData_
boost::optional< OptionExerciseData > exerciseData_
const string & noticeConvention() const
string exerciseFeeSettlementCalendar_
string exerciseFeeSettlementConvention_
const string & exerciseFeeSettlementCalendar() const
const string & style() const
const string & noticeCalendar() const
const string & settlement() const
virtual void fromXML(XMLNode *node) override
vector< string > exerciseFeeTypes_
virtual XMLNode * toXML(XMLDocument &doc) const override
const vector< string > & exerciseFeeTypes() const
boost::optional< bool > automaticExercise_
const ScheduleData & exerciseDatesSchedule() const
const bool & payoffAtExpiry() const
const boost::optional< OptionPaymentData > & paymentData() const
const boost::optional< OptionExerciseData > & exerciseData() const
vector< string > exerciseDates_
const vector< string > & exerciseFeeDates() const
ScheduleData exerciseDatesSchedule_
vector< double > exercisePrices_
const string & exerciseFeeSettlementConvention() const
const vector< double > & exerciseFees() const
const vector< string > & exerciseDates() const
const string & noticePeriod() const
vector< double > exerciseFees_
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
bool hasData() const
Check if has any dates/rules/derived schedules.
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
Small XML Document wrapper class.
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
static vector< Real > getChildrenValuesAsDoubles(XMLNode *node, const string &names, const string &name, bool mandatory=false)
static void addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
static void checkNode(XMLNode *n, const string &expectedName)
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
static bool getChildValueAsBool(XMLNode *node, const string &name, bool mandatory=false, bool defaultValue=true)
static XMLNode * getChildNode(XMLNode *n, const string &name="")
static void addChildrenWithOptionalAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
static string getNodeValue(XMLNode *node)
Get a node's value.
static vector< string > getChildrenValues(XMLNode *node, const string &names, const string &name, bool mandatory=false)
static void setNodeName(XMLDocument &doc, XMLNode *node, const string &name)
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
static void appendNode(XMLNode *parent, XMLNode *child)
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
bool parseBool(const string &s)
Convert text to bool.
Real parseReal(const string &s)
Convert text to Real.
leg data model and serialization
#define DLOG(text)
Logging Macro (Level = Debug)
#define WLOG(text)
Logging Macro (Level = Warning)
vector< T > buildScheduledVectorNormalised(const vector< T > &values, const vector< string > &dates, const Schedule &schedule, const T &defaultValue, const bool checkAllValuesAppearInResult=false)
std::string to_string(const LocationInfo &l)
Schedule makeSchedule(const ScheduleDates &data)
Serializable Credit Default Swap.
trade option data model and serialization
Map text representations to QuantLib/QuantExt types.
string conversion utilities