Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into oas_price
Browse files Browse the repository at this point in the history
  • Loading branch information
HristoRaykov committed Jun 27, 2024
2 parents dff2ef4 + b6acb72 commit 4656250
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 9 deletions.
23 changes: 18 additions & 5 deletions ql/termstructures/yield/oisratehelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,18 @@ namespace QuantLib {
RateAveraging::Type averagingMethod,
ext::optional<bool> endOfMonth,
ext::optional<Frequency> fixedPaymentFrequency,
Calendar fixedCalendar)
Calendar fixedCalendar,
Natural lookbackDays,
Natural lockoutDays,
bool applyObservationShift)
: RelativeDateRateHelper(fixedRate), pillarChoice_(pillar), settlementDays_(settlementDays), tenor_(tenor),
discountHandle_(std::move(discount)), telescopicValueDates_(telescopicValueDates),
paymentLag_(paymentLag), paymentConvention_(paymentConvention),
paymentFrequency_(paymentFrequency), paymentCalendar_(std::move(paymentCalendar)),
forwardStart_(forwardStart), overnightSpread_(overnightSpread),
averagingMethod_(averagingMethod), endOfMonth_(endOfMonth),
fixedPaymentFrequency_(fixedPaymentFrequency), fixedCalendar_(std::move(fixedCalendar)) {
fixedPaymentFrequency_(fixedPaymentFrequency), fixedCalendar_(std::move(fixedCalendar)),
lookbackDays_(lookbackDays), lockoutDays_(lockoutDays), applyObservationShift_(applyObservationShift) {

overnightIndex_ =
ext::dynamic_pointer_cast<OvernightIndex>(overnightIndex->clone(termStructureHandle_));
Expand Down Expand Up @@ -80,7 +84,10 @@ namespace QuantLib {
.withPaymentFrequency(paymentFrequency_)
.withPaymentCalendar(paymentCalendar_)
.withOvernightLegSpread(overnightSpread_)
.withAveragingMethod(averagingMethod_);
.withAveragingMethod(averagingMethod_)
.withLookbackDays(lookbackDays_)
.withLockoutDays(lockoutDays_)
.withObservationShift(applyObservationShift_);
if (endOfMonth_) {
tmp.withEndOfMonth(*endOfMonth_);
}
Expand Down Expand Up @@ -171,7 +178,10 @@ namespace QuantLib {
Spread overnightSpread,
ext::optional<bool> endOfMonth,
ext::optional<Frequency> fixedPaymentFrequency,
const Calendar& fixedCalendar)
const Calendar& fixedCalendar,
Natural lookbackDays,
Natural lockoutDays,
bool applyObservationShift)
: RateHelper(fixedRate), discountHandle_(std::move(discount)),
telescopicValueDates_(telescopicValueDates), averagingMethod_(averagingMethod) {

Expand All @@ -197,7 +207,10 @@ namespace QuantLib {
.withPaymentFrequency(paymentFrequency)
.withPaymentCalendar(paymentCalendar)
.withOvernightLegSpread(overnightSpread)
.withAveragingMethod(averagingMethod_);
.withAveragingMethod(averagingMethod_)
.withLookbackDays(lookbackDays)
.withLockoutDays(lockoutDays)
.withObservationShift(applyObservationShift);
if (endOfMonth) {
tmp.withEndOfMonth(*endOfMonth);
}
Expand Down
13 changes: 11 additions & 2 deletions ql/termstructures/yield/oisratehelper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ namespace QuantLib {
RateAveraging::Type averagingMethod = RateAveraging::Compound,
ext::optional<bool> endOfMonth = ext::nullopt,
ext::optional<Frequency> fixedPaymentFrequency = ext::nullopt,
Calendar fixedCalendar = Calendar());
Calendar fixedCalendar = Calendar(),
Natural lookbackDays = Null<Natural>(),
Natural lockoutDays = 0,
bool applyObservationShift = false);
//! \name RateHelper interface
//@{
Real impliedQuote() const override;
Expand Down Expand Up @@ -92,6 +95,9 @@ namespace QuantLib {
ext::optional<bool> endOfMonth_;
ext::optional<Frequency> fixedPaymentFrequency_;
Calendar fixedCalendar_;
Natural lookbackDays_;
Natural lockoutDays_;
bool applyObservationShift_;
};

//! Rate helper for bootstrapping over Overnight Indexed Swap rates
Expand All @@ -112,7 +118,10 @@ namespace QuantLib {
Spread overnightSpread = 0.0,
ext::optional<bool> endOfMonth = ext::nullopt,
ext::optional<Frequency> fixedPaymentFrequency = ext::nullopt,
const Calendar& fixedCalendar = Calendar());
const Calendar& fixedCalendar = Calendar(),
Natural lookbackDays = Null<Natural>(),
Natural lockoutDays = 0,
bool applyObservationShift = false);

/*! \deprecated Use the overload without forward start.
Deprecated in version 1.35.
Expand Down
4 changes: 2 additions & 2 deletions test-suite/overnightindexedcoupon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,8 +489,8 @@ BOOST_AUTO_TEST_CASE(testTelescopicFormulaWhenLookbackWithObservationShiftAndNoI
CHECK_OIS_COUPON_RESULT("coupon rate using telescopic formula", actualRate,
expectedRateTelescopicSeries, 1e-12);

auto& fixingDates = coupon15July->fixingDates();
auto& dts = coupon15July->dt();
const auto& fixingDates = coupon15July->fixingDates();
const auto& dts = coupon15July->dt();
Size n = fixingDates.size();

Rate expectedRateIterativeFormula = 1.0;
Expand Down
144 changes: 144 additions & 0 deletions test-suite/overnightindexedswap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,25 @@ struct CommonVars {
.withAveragingMethod(averagingMethod);
}

ext::shared_ptr<OvernightIndexedSwap>
makeSwapWithLookback(Period length,
Rate fixedRate,
Integer paymentLag,
Natural lookbackDays,
Natural lockoutDays,
bool applyObservationShift,
bool telescopicValueDates) {
return MakeOIS(length, eoniaIndex, fixedRate, 0 * Days)
.withEffectiveDate(settlement)
.withNominal(nominal)
.withPaymentLag(paymentLag)
.withDiscountingTermStructure(eoniaTermStructure)
.withLookbackDays(lookbackDays)
.withLockoutDays(lockoutDays)
.withObservationShift(applyObservationShift)
.withTelescopicValueDates(telescopicValueDates);
}

CommonVars() {
type = Swap::Payer;
settlementDays = 2;
Expand Down Expand Up @@ -389,6 +408,131 @@ BOOST_AUTO_TEST_CASE(testBootstrapWithTelescopicDatesAndArithmeticAverage) {
testBootstrap(true, RateAveraging::Simple, 1.0e-5);
}


void testBootstrapWithLookback(Natural lookbackDays,
Natural lockoutDays,
bool applyObservationShift,
bool telescopicValueDates,
Natural paymentLag) {

CommonVars vars;

std::vector<ext::shared_ptr<RateHelper> > eoniaHelpers;

ext::shared_ptr<Eonia> eonia(new Eonia);

for (auto& i : eoniaSwapData) {
Real rate = 0.01 * i.rate;
auto quote = ext::make_shared<SimpleQuote>(rate);
Period term = i.n * i.unit;
auto helper = ext::make_shared<OISRateHelper>(i.settlementDays,
term,
Handle<Quote>(quote),
eonia,
Handle<YieldTermStructure>(),
telescopicValueDates,
paymentLag,
Following,
Annual,
Calendar(),
0 * Days,
0.0,
Pillar::LastRelevantDate,
Date(),
RateAveraging::Compound,
ext::nullopt,
ext::nullopt,
Calendar(),
lookbackDays,
lockoutDays,
applyObservationShift);
eoniaHelpers.push_back(helper);
}

auto eoniaTS = ext::make_shared<PiecewiseYieldCurve<ForwardRate, BackwardFlat>>(vars.today, eoniaHelpers, Actual365Fixed());

vars.eoniaTermStructure.linkTo(eoniaTS);

// test curve consistency
for (auto& i : eoniaSwapData) {
Rate expected = i.rate / 100;
Period term = i.n * i.unit;
ext::shared_ptr<OvernightIndexedSwap> swap =
vars.makeSwapWithLookback(term, 0.0, paymentLag, lookbackDays, lockoutDays,
applyObservationShift, telescopicValueDates);
Rate calculated = swap->fairRate();
Rate error = std::fabs(expected-calculated);
Real tolerance = 1e-8;

if (error>tolerance)
BOOST_FAIL("curve inconsistency:" << std::setprecision(10) <<
"\n swap length: " << term <<
"\n quoted rate: " << expected <<
"\n calculated rate: " << calculated <<
"\n error: " << error <<
"\n tolerance: " << tolerance);
}
}



BOOST_AUTO_TEST_CASE(testBootstrapWithLookbackDays) {
BOOST_TEST_MESSAGE("Testing Eonia-swap curve building with lookback days...");

auto lookbackDays = 2;
auto lockoutDays = 0;
auto applyObservationShift = false;
auto paymentLag = 2;

testBootstrapWithLookback(lookbackDays, lockoutDays, applyObservationShift, false, paymentLag);

BOOST_CHECK_EXCEPTION(
testBootstrapWithLookback(lookbackDays, lockoutDays, applyObservationShift, true, paymentLag),
Error, ExpectedErrorMessage("Telescopic formula cannot be applied"));
}

BOOST_AUTO_TEST_CASE(testBootstrapWithLookbackDaysAndShift) {
BOOST_TEST_MESSAGE("Testing Eonia-swap curve building with lookback days and observation shift...");

auto lookbackDays = 2;
auto lockoutDays = 0;
auto applyObservationShift = true;
auto paymentLag = 2;

testBootstrapWithLookback(lookbackDays, lockoutDays, applyObservationShift, false, paymentLag);

testBootstrapWithLookback(lookbackDays, lockoutDays, applyObservationShift, true, paymentLag);
}

BOOST_AUTO_TEST_CASE(testBootstrapWithLockoutDays) {
BOOST_TEST_MESSAGE("Testing Eonia-swap curve building with lookback and lockout days...");

auto lookbackDays = 2;
auto lockoutDays = 2;
auto applyObservationShift = false;
auto paymentLag = 0;

testBootstrapWithLookback(lookbackDays, lockoutDays, applyObservationShift, false, paymentLag);

BOOST_CHECK_EXCEPTION(
testBootstrapWithLookback(lookbackDays, lockoutDays, applyObservationShift, true, paymentLag),
Error, ExpectedErrorMessage("Telescopic formula cannot be applied"));
}

BOOST_AUTO_TEST_CASE(testBootstrapWithLockoutDaysAndShift) {
BOOST_TEST_MESSAGE("Testing Eonia-swap curve building with lookback and lockout days and observation shift...");

auto lookbackDays = 2;
auto lockoutDays = 2;
auto applyObservationShift = true;
auto paymentLag = 0;

testBootstrapWithLookback(lookbackDays, lockoutDays, applyObservationShift, false, paymentLag);

testBootstrapWithLookback(lookbackDays, lockoutDays, applyObservationShift, true, paymentLag);
}


BOOST_AUTO_TEST_CASE(testSeasonedSwaps) {

BOOST_TEST_MESSAGE("Testing seasoned Eonia-swap calculation...");
Expand Down

0 comments on commit 4656250

Please sign in to comment.