/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2006 Ferdinando Ametrano Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #include namespace QuantLib { Schedule::Schedule(const Date& effectiveDate, const Date& terminationDate, const Period& tenor, const Calendar& calendar, BusinessDayConvention convention, BusinessDayConvention terminationDateConvention, bool backward, bool endOfMonth, const Date& firstDate, const Date& nextToLastDate) : fullInterface_(true), calendar_(calendar), tenor_(tenor), convention_(convention), firstDate_(firstDate), nextToLastDate_(nextToLastDate), startFromEnd_(backward), longFinal_(false), endOfMonth_(endOfMonth), finalIsRegular_(true) { // sanity checks QL_REQUIRE(effectiveDate != Date(), "null effective date"); QL_REQUIRE(terminationDate != Date(), "null termination date"); QL_REQUIRE(effectiveDate < terminationDate, "effective date (" << effectiveDate << ") later than or equal to termination date (" << terminationDate << ")"); if (firstDate != Date()) { QL_REQUIRE((firstDate > effectiveDate && firstDate < terminationDate), "first date (" << firstDate << ") out of range (effective date (" << effectiveDate << "), termination date (" << terminationDate << "))"); } if (nextToLastDate != Date()) { QL_REQUIRE((nextToLastDate > effectiveDate && nextToLastDate < terminationDate), "next to last date (" << nextToLastDate << ") out of range (effective date (" << effectiveDate << "), termination date (" << terminationDate << "))"); } if (tenor_ < Period(1, Days)) { QL_REQUIRE(firstDate == Date(), "first date incompatible with zero coupon schedule"); QL_REQUIRE(nextToLastDate == Date(), "next to last date incompatible with zero coupon schedule"); dates_.push_back(effectiveDate); dates_.push_back(terminationDate); isRegular_.push_back(true); } else if (backward) { // backward roll date convention // calendar needed for endOfMonth adjustment Calendar nullCalendar = NullCalendar(); Integer periods = 1; dates_.push_back(terminationDate); Date seed = terminationDate; if (nextToLastDate != Date()) { dates_.insert(dates_.begin(), nextToLastDate); Date temp = nullCalendar.advance(seed, -periods*tenor_, convention, endOfMonth); if (temp!=nextToLastDate) isRegular_.insert(isRegular_.begin(), false); else isRegular_.insert(isRegular_.begin(), true); seed = nextToLastDate; } Date exitDate = effectiveDate; if (firstDate != Date()) exitDate = firstDate; while (true) { Date temp = nullCalendar.advance(seed, -periods*tenor_, convention, endOfMonth); if (temp < exitDate) break; else { dates_.insert(dates_.begin(), temp); isRegular_.insert(isRegular_.begin(), true); periods++; } } if (endOfMonth && calendar.isEndOfMonth(seed)) convention=Preceding; if (calendar.adjust(dates_.front(),convention)!= calendar.adjust(effectiveDate, convention)) { dates_.insert(dates_.begin(), effectiveDate); isRegular_.insert(isRegular_.begin(), false); } } else { // forward roll date convention // calendar needed for endOfMonth adjustment Calendar nullCalendar = NullCalendar(); Integer periods = 1; dates_.push_back(effectiveDate); Date seed = effectiveDate; if (firstDate!=Date()) { dates_.push_back(firstDate); Date temp = nullCalendar.advance(seed, periods*tenor_, convention, endOfMonth); if (temp!=firstDate) isRegular_.push_back(false); else isRegular_.push_back(true); seed = firstDate; } Date exitDate = terminationDate; if (nextToLastDate != Date()) exitDate = nextToLastDate; while (true) { Date temp = nullCalendar.advance(seed, periods*tenor_, convention, endOfMonth); if (temp > exitDate) break; else { dates_.push_back(temp); isRegular_.push_back(true); periods++; } } if (endOfMonth && calendar.isEndOfMonth(seed)) convention=Preceding; if (calendar.adjust(dates_.back(),terminationDateConvention)!= calendar.adjust(terminationDate, terminationDateConvention)) { dates_.push_back(terminationDate); isRegular_.push_back(false); } } for (Size i=0; i