22#include <ql/utilities/vectors.hpp>
23#include <ql/time/calendars/jointcalendar.hpp>
24#include <boost/algorithm/string/case_conv.hpp>
33 return out <<
"Price";
35 return out <<
"Total";
37 return out <<
"Absolute";
39 return out <<
"Dividend";
41 QL_FAIL(
"unknown EquityReturnType(" <<
int(t) <<
")");
46 if (boost::algorithm::to_upper_copy(str) ==
"PRICE")
48 else if (boost::algorithm::to_upper_copy(str) ==
"TOTAL")
50 else if (boost::algorithm::to_upper_copy(str) ==
"ABSOLUTE")
52 else if (boost::algorithm::to_upper_copy(str) ==
"DIVIDEND")
54 QL_FAIL(
"Invalid EquityReturnType " << str);
58 Natural fixingDays,
const QuantLib::ext::shared_ptr<QuantExt::EquityIndex2>& equityCurve,
59 const DayCounter& dayCounter,
EquityReturnType returnType, Real dividendFactor,
60 bool notionalReset, Real initialPrice, Real quantity,
const Date& fixingStartDate,
61 const Date& fixingEndDate,
const Date& refPeriodStart,
const Date& refPeriodEnd,
62 const Date& exCouponDate,
const QuantLib::ext::shared_ptr<FxIndex>& fxIndex,
63 const bool initialPriceIsInTargetCcy, Real legInitialNotional,
const Date& legFixingDate)
64 :
Coupon(paymentDate, nominal, startDate, endDate, refPeriodStart, refPeriodEnd, exCouponDate),
65 fixingDays_(fixingDays), equityCurve_(equityCurve), dayCounter_(dayCounter), returnType_(returnType),
66 dividendFactor_(dividendFactor), notionalReset_(notionalReset), initialPrice_(initialPrice),
67 initialPriceIsInTargetCcy_(initialPriceIsInTargetCcy), quantity_(quantity), fixingStartDate_(fixingStartDate),
68 fixingEndDate_(fixingEndDate), fxIndex_(fxIndex), legInitialNotional_(legInitialNotional),
69 legFixingDate_(legFixingDate) {
70 QL_REQUIRE(
dividendFactor_ > 0.0,
"Dividend factor should not be negative. It is expected to be between 0 and 1.");
71 QL_REQUIRE(
equityCurve_,
"Equity underlying an equity swap coupon cannot be empty.");
74 Calendar eqCalendar = NullCalendar();
75 Calendar fxCalendar = NullCalendar();
80 fxCalendar =
fxIndex_->fixingCalendar();
82 Calendar fixingCalendar = JointCalendar(eqCalendar, fxCalendar);
88 fixingCalendar.advance(startDate, -
static_cast<Integer
>(
fixingDays_), Days, Preceding);
92 fixingCalendar.advance(endDate, -
static_cast<Integer
>(
fixingDays_), Days, Preceding);
96 registerWith(Settings::instance().evaluationDate());
100 "EquityCoupon: notional required if notional does not reset");
115 "leg initial notional and fixing date required to compute the missing quantity in case of a resetting equity leg");
149 if (d <= accrualStartDate_ || d > paymentDate_) {
152 Time fullPeriod =
dayCounter().yearFraction(accrualStartDate_, accrualEndDate_, refPeriodStart_, refPeriodEnd_);
154 dayCounter().yearFraction(accrualStartDate_, std::min(d, accrualEndDate_), refPeriodStart_, refPeriodEnd_);
155 return nominal() *
rate() * thisPeriod / fullPeriod;
160 QL_REQUIRE(
pricer_,
"pricer not set");
179EquityLeg::EquityLeg(
const Schedule& schedule,
const QuantLib::ext::shared_ptr<QuantExt::EquityIndex2>& equityCurve,
180 const QuantLib::ext::shared_ptr<FxIndex>& fxIndex)
181 : schedule_(schedule), equityCurve_(equityCurve), fxIndex_(fxIndex), paymentLag_(0), paymentAdjustment_(Following),
183 initialPriceIsInTargetCcy_(false), dividendFactor_(1.0), fixingDays_(0), notionalReset_(false),
184 quantity_(Null<Real>()) {}
256EquityLeg::operator Leg()
const {
264 if (!paymentCalendar_.empty()) {
265 calendar = paymentCalendar_;
267 calendar = schedule_.calendar();
270 Size numPeriods = schedule_.size() - 1;
272 if (valuationSchedule_.size() > 0) {
273 QL_REQUIRE(valuationSchedule_.size() == schedule_.size(),
274 "mismatch in valuationSchedule (" << valuationSchedule_.size() <<
") and scheduleData ("
275 << schedule_.size() <<
") sizes");
278 Date legFixingDate = Date();
279 if (valuationSchedule_.size() > 0)
280 legFixingDate = valuationSchedule_.dates().front();
281 else if (schedule_.size() > 0)
282 legFixingDate = equityCurve_->fixingCalendar().advance(schedule_.dates().front(),
283 -
static_cast<Integer
>(fixingDays_), Days, Preceding);
285 QL_FAIL(
"Cannot build equity leg, neither schedule nor valuation schedule are defined");
287 Real quantity = Null<Real>(), notional = Null<Real>(), legInitialNotional = Null<Real>();
288 if (notionalReset_) {
290 if (quantity_ != Null<Real>()) {
291 quantity = quantity_;
292 QL_REQUIRE(notionals_.empty(),
"EquityLeg: notional and quantity are given at the same time");
298 QL_REQUIRE(!notionals_.empty(),
"EquityLeg: can not compute qunantity, since no notional is given");
299 QL_REQUIRE(fxIndex_ ==
nullptr || initialPriceIsInTargetCcy_,
300 "EquityLeg: can not compute quantity from nominal when fx conversion is required");
301 notional = notionals_.front();
302 legInitialNotional = notional;
303 if (initialPrice_ != Null<Real>())
304 quantity = (initialPrice_ == 0) ? notional : notional / initialPrice_;
307 if (!notionals_.empty()) {
308 QL_REQUIRE(quantity_ == Null<Real>(),
"EquityLeg: notional and quantity are given at the same time");
310 legInitialNotional = notionals_.front();
312 QL_REQUIRE(initialPrice_ != Null<Real>(),
"EquityLeg: can not compute notional, since no intialPrice is given");
313 QL_REQUIRE(quantity_ != Null<Real>(),
"EquityLeg: can not compute notional, since no quantity is given");
314 QL_REQUIRE(fxIndex_ ==
nullptr || initialPriceIsInTargetCcy_,
315 "EquityLeg: can not compute notional from quantity when fx conversion is required");
316 notional = (initialPrice_ == 0) ? quantity_ : quantity_ * initialPrice_;
320 for (Size i = 0; i < numPeriods; ++i) {
321 startDate = schedule_.date(i);
322 endDate = schedule_.date(i + 1);
323 paymentDate = calendar.advance(endDate, paymentLag_, Days, paymentAdjustment_);
325 Date fixingStartDate = Date();
326 Date fixingEndDate = Date();
327 if (valuationSchedule_.size() > 0) {
328 fixingStartDate = valuationSchedule_.date(i);
329 fixingEndDate = valuationSchedule_.date(i + 1);
332 Real initialPrice = (i == 0) ? initialPrice_ : Null<Real>();
333 bool initialPriceIsInTargetCcy = initialPrice != Null<Real>() ? initialPriceIsInTargetCcy_ :
false;
334 if (!notionalReset_ && !notionals_.empty()) {
335 notional = detail::get(notionals_, i, 0.0);
338 QuantLib::ext::shared_ptr<EquityCoupon> cashflow(
new EquityCoupon(
339 paymentDate, notional, startDate, endDate, fixingDays_, equityCurve_, paymentDayCounter_, returnType_,
340 dividendFactor_, notionalReset_, initialPrice, quantity, fixingStartDate, fixingEndDate, Date(), Date(),
341 Date(), fxIndex_, initialPriceIsInTargetCcy, legInitialNotional, legFixingDate));
344 cashflow->setPricer(pricer);
346 cashflows.push_back(cashflow);
QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > equityCurve_
void setPricer(const QuantLib::ext::shared_ptr< EquityCouponPricer > &)
QuantLib::ext::shared_ptr< EquityCouponPricer > pricer() const
QuantLib::ext::shared_ptr< FxIndex > fxIndex_
std::vector< Date > fixingDates() const
return both fixing dates
bool initialPriceIsInTargetCcy_
bool initialPriceIsInTargetCcy() const
initial price is in target ccy (if applicable, i.e. if fxIndex != null, otherwise ignored)
Rate rate() const override
Real fxRate() const
FX conversion rate (or 1.0 if not applicable)
Real nominal() const override
EquityReturnType returnType_
EquityCoupon(const Date &paymentDate, Real nominal, const Date &startDate, const Date &endDate, Natural fixingDays, const QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > &equityCurve, const DayCounter &dayCounter, EquityReturnType returnType, Real dividendFactor=1.0, bool notionalReset=false, Real initialPrice=Null< Real >(), Real quantity=Null< Real >(), const Date &fixingStartDate=Date(), const Date &fixingEndDate=Date(), const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date(), const Date &exCouponDate=Date(), const QuantLib::ext::shared_ptr< FxIndex > &fxIndex=nullptr, const bool initialPriceIsInTargetCcy=false, Real legInitialNotional=Null< Real >(), const Date &legFixingDate=Date())
DayCounter dayCounter() const override
Real accruedAmount(const Date &) const override
QuantLib::ext::shared_ptr< EquityCouponPricer > pricer_
Real quantity() const
Number of equity shares held.
Date fixingStartDate() const
The date at which the starting equity price is fixed.
Real initialPrice() const
initial price
Pricer for equity coupons.
helper class building a sequence of equity coupons
EquityLeg & withInitialPriceIsInTargetCcy(bool)
BusinessDayConvention paymentAdjustment_
EquityLeg & withDividendFactor(Real)
EquityLeg & withPaymentCalendar(const Calendar &calendar)
EquityLeg & withNotional(Real notional)
Calendar paymentCalendar_
EquityLeg & withFixingDays(Natural)
Schedule valuationSchedule_
bool initialPriceIsInTargetCcy_
EquityLeg(const Schedule &schedule, const QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > &equityCurve, const QuantLib::ext::shared_ptr< FxIndex > &fxIndex=nullptr)
std::vector< Real > notionals_
EquityReturnType returnType_
EquityLeg & withNotionalReset(bool)
EquityLeg & withQuantity(Real)
EquityLeg & withNotionals(const std::vector< Real > ¬ionals)
EquityLeg & withInitialPrice(Real)
EquityLeg & withPaymentDayCounter(const DayCounter &dayCounter)
EquityLeg & withValuationSchedule(const Schedule &valuationSchedule)
EquityLeg & withPaymentAdjustment(BusinessDayConvention convention)
EquityLeg & withPaymentLag(Natural paymentLag)
EquityLeg & withReturnType(EquityReturnType)
DayCounter paymentDayCounter_
coupon paying the return on an equity
Pricer for equity coupons.
std::ostream & operator<<(std::ostream &out, EquityReturnType t)
EquityReturnType parseEquityReturnType(const std::string &str)