Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow negative paymentlag #224

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Docs/UserGuide/tradecomponents/legdatanotionals.tex
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ \subsubsection{Leg Data and Notionals}
\item PaymentLag [optional]: The payment lag applies to Fixed legs, Equity legs, and Floating legs with Ibor and OIS indices (but not to BMA/SIFMA indices), as well as CPI legs and Zero Coupon Fixed legs. \\
PaymentLag is also not supported for CapFloor Floating legs that have Ibor coupons with sub periods (HasSubPeriods = \emph{true}), nor for CapFloor Floating legs with averaged ON coupons (IsAveraged = \emph{true}).

Allowable values: Any valid period, i.e. a non-negative whole number, optionally followed by \emph{D} (days), \emph{W} (weeks), \emph{M} (months),
Allowable values: Any valid period, i.e. a positive or negative whole number, optionally followed by \emph{D} (days), \emph{W} (weeks), \emph{M} (months),
\emph{Y} (years). Defaults to \emph{0D} if left blank or omitted. If a whole number is given and no letter, it is assumed that it is a number of \emph{D} (days).

\item DayCounter: The day count convention of the leg coupons. Note that \lstinline!DayCounter! is mandatory for all leg types except \emph{Equity}.
Expand Down
2 changes: 1 addition & 1 deletion Docs/UserGuide/tradedata/fxforward.tex
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ \subsubsection{FX Forward}
The \lstinline!Rules! sub-node is shown in Listing \ref{lst:settlement_data_node}, and the meanings and allowable values of its elements follow below.
\begin{itemize}
\item PaymentLag [Optional]: The lag between the value date and the payment date. \\
Allowable values: Any valid period, i.e.\ a non-negative whole number, optionally followed by \emph{D} (days), \emph{W} (weeks), \emph{M} (months),
Allowable values: Any valid period, i.e.\ a negative or positive whole number, optionally followed by \emph{D} (days), \emph{W} (weeks), \emph{M} (months),
\emph{Y} (years). For cash settlement and if a FXIndex is specified defaults to the fx convention (field ``SpotDays'') if blank or omitted, otherwise to 0. If a whole number is given and no letter, it is assumed that it is a number of \emph{D} (days).
\item PaymentCalendar [Optional]: The calendar to be used when applying the payment lag. \\
Allowable values: See Table \ref{tab:calendar} \lstinline!Calendar!. For cash settlement and if a FXIndex is specified defaults to the fx convention (field ``AdvanceCalendar'') if left blank or omitted, otherwise to NullCalendar (no holidays).
Expand Down
10 changes: 5 additions & 5 deletions OREData/ored/portfolio/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@
namespace ore {
namespace data {

typedef boost::variant<QuantLib::Period, QuantLib::Natural> PaymentLag;
typedef boost::variant<QuantLib::Period, QuantLib::Integer> PaymentLag;

struct PaymentLagPeriod : public boost::static_visitor<QuantLib::Period> {
public:
QuantLib::Period operator()(const QuantLib::Natural& n) const { return Period(n, Days); }
QuantLib::Period operator()(const QuantLib::Integer& n) const { return Period(n, Days); }
QuantLib::Period operator()(const QuantLib::Period& p) const { return p; }
};

struct PaymentLagInteger : public boost::static_visitor<QuantLib::Natural> {
struct PaymentLagInteger : public boost::static_visitor<QuantLib::Integer> {
public:
QuantLib::Natural operator()(const QuantLib::Natural& n) const { return n; }
QuantLib::Natural operator()(const QuantLib::Period& p) const { return static_cast<QuantLib::Natural>(days(p)); }
QuantLib::Integer operator()(const QuantLib::Integer& n) const { return n; }
QuantLib::Integer operator()(const QuantLib::Period& p) const { return static_cast<QuantLib::Integer>(days(p)); }
};

} // namespace data
Expand Down
4 changes: 2 additions & 2 deletions OREData/ored/utilities/parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,10 +622,10 @@ Month parseMonth(const string& s) {

PaymentLag parsePaymentLag(const string& s) {
Period p;
Natural n;
Integer n = 0;
if (tryParse<Period>(s, p, parsePeriod))
return p;
else if (tryParse<Natural>(s, n, parseInteger))
else if (tryParse<Integer>(s, n, parseInteger))
return n;
else
return 0;
Expand Down
2 changes: 1 addition & 1 deletion QuantExt/qle/cashflows/averageonindexedcoupon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ AverageONLeg& AverageONLeg::withPaymentCalendar(const Calendar& calendar) {
return *this;
}

AverageONLeg& AverageONLeg::withPaymentLag(Natural lag) {
AverageONLeg& AverageONLeg::withPaymentLag(Integer lag) {
paymentLag_ = lag;
return *this;
}
Expand Down
4 changes: 2 additions & 2 deletions QuantExt/qle/cashflows/averageonindexedcoupon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ class AverageONLeg {
AverageONLeg& withTelescopicValueDates(bool telescopicValueDates);
AverageONLeg& withRateCutoff(Natural rateCutoff);
AverageONLeg& withPaymentCalendar(const Calendar& calendar);
AverageONLeg& withPaymentLag(Natural lag);
AverageONLeg& withPaymentLag(Integer lag);
AverageONLeg& withLookback(const Period& lookback);
AverageONLeg& withFixingDays(const Size fixingDays);
AverageONLeg& withCaps(Rate cap);
Expand All @@ -215,7 +215,7 @@ class AverageONLeg {
std::vector<Real> notionals_;
DayCounter paymentDayCounter_;
BusinessDayConvention paymentAdjustment_;
Natural paymentLag_;
Integer paymentLag_;
std::vector<Real> gearings_;
std::vector<Spread> spreads_;
bool telescopicValueDates_;
Expand Down
2 changes: 1 addition & 1 deletion QuantExt/qle/cashflows/cpicoupon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ CPILeg& CPILeg::withPaymentCalendar(const Calendar& cal) {
return *this;
}

CPILeg& CPILeg::withPaymentLag(Natural lag) {
CPILeg& CPILeg::withPaymentLag(Integer lag) {
paymentLag_ = lag;
return *this;
}
Expand Down
4 changes: 2 additions & 2 deletions QuantExt/qle/cashflows/cpicoupon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class CPILeg {
CPILeg& withPaymentDayCounter(const DayCounter&);
CPILeg& withPaymentAdjustment(BusinessDayConvention);
CPILeg& withPaymentCalendar(const Calendar&);
CPILeg& withPaymentLag(Natural lag);
CPILeg& withPaymentLag(Integer lag);
CPILeg& withFixingDays(Natural fixingDays);
CPILeg& withFixingDays(const std::vector<Natural>& fixingDays);
CPILeg& withObservationInterpolation(CPI::InterpolationType);
Expand Down Expand Up @@ -175,7 +175,7 @@ class CPILeg {
DayCounter paymentDayCounter_;
BusinessDayConvention paymentAdjustment_;
Calendar paymentCalendar_;
Natural paymentLag_;
Integer paymentLag_;
std::vector<Natural> fixingDays_;
CPI::InterpolationType observationInterpolation_;
bool subtractInflationNominal_;
Expand Down
2 changes: 1 addition & 1 deletion QuantExt/qle/cashflows/equitycoupon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ EquityLeg& EquityLeg::withPaymentAdjustment(BusinessDayConvention convention) {
return *this;
}

EquityLeg& EquityLeg::withPaymentLag(Natural paymentLag) {
EquityLeg& EquityLeg::withPaymentLag(Integer paymentLag) {
paymentLag_ = paymentLag;
return *this;
}
Expand Down
4 changes: 2 additions & 2 deletions QuantExt/qle/cashflows/equitycoupon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class EquityLeg {
EquityLeg& withNotionals(const std::vector<Real>& notionals);
EquityLeg& withPaymentDayCounter(const DayCounter& dayCounter);
EquityLeg& withPaymentAdjustment(BusinessDayConvention convention);
EquityLeg& withPaymentLag(Natural paymentLag);
EquityLeg& withPaymentLag(Integer paymentLag);
EquityLeg& withPaymentCalendar(const Calendar& calendar);
EquityLeg& withReturnType(EquityReturnType);
EquityLeg& withDividendFactor(Real);
Expand All @@ -184,7 +184,7 @@ class EquityLeg {
boost::shared_ptr<FxIndex> fxIndex_;
std::vector<Real> notionals_;
DayCounter paymentDayCounter_;
Natural paymentLag_;
Integer paymentLag_;
BusinessDayConvention paymentAdjustment_;
Calendar paymentCalendar_;
EquityReturnType returnType_;
Expand Down
2 changes: 1 addition & 1 deletion QuantExt/qle/cashflows/overnightindexedcoupon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ OvernightLeg& OvernightLeg::withPaymentCalendar(const Calendar& cal) {
return *this;
}

OvernightLeg& OvernightLeg::withPaymentLag(Natural lag) {
OvernightLeg& OvernightLeg::withPaymentLag(Integer lag) {
paymentLag_ = lag;
return *this;
}
Expand Down
4 changes: 2 additions & 2 deletions QuantExt/qle/cashflows/overnightindexedcoupon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class OvernightLeg {
OvernightLeg& withPaymentDayCounter(const DayCounter&);
OvernightLeg& withPaymentAdjustment(BusinessDayConvention);
OvernightLeg& withPaymentCalendar(const Calendar&);
OvernightLeg& withPaymentLag(Natural lag);
OvernightLeg& withPaymentLag(Integer lag);
OvernightLeg& withGearings(Real gearing);
OvernightLeg& withGearings(const std::vector<Real>& gearings);
OvernightLeg& withSpreads(Spread spread);
Expand Down Expand Up @@ -266,7 +266,7 @@ class OvernightLeg {
DayCounter paymentDayCounter_;
Calendar paymentCalendar_;
BusinessDayConvention paymentAdjustment_;
Natural paymentLag_;
Integer paymentLag_;
std::vector<Real> gearings_;
std::vector<Spread> spreads_;
bool telescopicValueDates_;
Expand Down
51 changes: 51 additions & 0 deletions QuantExt/test/cpileg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/all.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <ql/time/daycounters/simpledaycounter.hpp>
#include <ql/time/businessdayconvention.hpp>
#include <qle/cashflows/cpicoupon.hpp>

using namespace QuantLib;
Expand Down Expand Up @@ -70,6 +72,55 @@ BOOST_AUTO_TEST_CASE(testCpiLegPaymentLag) {
}
}

BOOST_AUTO_TEST_CASE(testCpiLegNegativePaymentLag) {

BOOST_TEST_MESSAGE("Testing QuantExt::CPILeg for negative payment lag...");

Date evaluationDate(6, October, 2023);
Settings::instance().evaluationDate() = evaluationDate;
Calendar calendar = WeekendsOnly();
DayCounter dayCounter = SimpleDayCounter();
BusinessDayConvention dayConvention = ModifiedFollowing;

Date startDate(6, October, 2023);
Date endDate(6, October, 2024);
Schedule fixedSchedule = MakeSchedule()
.from(startDate)
.to(endDate)
.withTenor(Period(6, Months))
.withCalendar(calendar)
.withConvention(dayConvention)
.backwards();

auto flatYts = ext::shared_ptr<YieldTermStructure>(new FlatForward(evaluationDate, 0.025, dayCounter));
RelinkableHandle<YieldTermStructure> yTS(flatYts);

auto ukrpi = ext::make_shared<UKRPI>();

Integer paymentLag = -2;
Leg cpiLeg = QuantExt::CPILeg(fixedSchedule, ukrpi, yTS, 100, Period(3, Months))
.withNotionals(1e6)
.withFixedRates(0.01)
.withPaymentCalendar(calendar)
.withPaymentDayCounter(dayCounter)
.withPaymentAdjustment(dayConvention)
.withPaymentLag(paymentLag);


for (auto& coupon : cpiLeg) {
if (auto cpiCoupon = ext::dynamic_pointer_cast<CPICoupon>(coupon)) {
// The setup leg will have six regular coupons
Date testPaymentLag = calendar.advance(cpiCoupon->accrualEndDate(), paymentLag, Days, dayConvention);

BOOST_CHECK_EQUAL(cpiCoupon->date(), testPaymentLag);
} else if (auto cpiNotionalCashflow = ext::dynamic_pointer_cast<CPICashFlow>(coupon)) {
// and one of these flows
Date testPaymentLag = calendar.advance(fixedSchedule.endDate(), paymentLag, Days, dayConvention);
BOOST_CHECK_EQUAL(cpiNotionalCashflow->date(), testPaymentLag);
}
}
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()