Beispiel #1
0
Period *Period::normalizedStandard(const PeriodType *type) {
    type = DateTimeUtils::getPeriodType(type);
    int64_t millis = getMillis();  // no overflow can happen, even with Integer.MAX_VALUEs
    millis += (((int64_t) getSeconds()) * ((int64_t) DateTimeConstants::MILLIS_PER_SECOND));
    millis += (((int64_t) getMinutes()) * ((int64_t) DateTimeConstants::MILLIS_PER_MINUTE));
    millis += (((int64_t) getHours()) * ((int64_t) DateTimeConstants::MILLIS_PER_HOUR));
    millis += (((int64_t) getDays()) * ((int64_t) DateTimeConstants::MILLIS_PER_DAY));
    millis += (((int64_t) getWeeks()) * ((int64_t) DateTimeConstants::MILLIS_PER_WEEK));
    Period *result = new Period(millis, type, ISOChronology::getInstanceUTC());
    int years = getYears();
    int months = getMonths();
    if (years != 0 || months != 0) {
        int64_t totalMonths = years * 12L + months;
        if (type->isSupported(DurationFieldType::YEARS_TYPE)) {
            int normalizedYears = FieldUtils::safeToInt(totalMonths / 12);
            result = result->withYears(normalizedYears);
            totalMonths = totalMonths - (normalizedYears * 12);
        }
        if (type->isSupported(DurationFieldType::MONTHS_TYPE)) {
            int normalizedMonths = FieldUtils::safeToInt(totalMonths);
            result = result->withMonths(normalizedMonths);
            totalMonths = totalMonths - normalizedMonths;
        }
        if (totalMonths != 0) {
            string err("Unable to normalize as PeriodType is missing either years or months but period has a month/year amount: ");
            err.append(toString());
            throw UnsupportedOperationException(err);
        }
    }
    return result;
}
Beispiel #2
0
void IsoffMainParser::parsePeriods(Node *root)
{
    std::vector<Node *> periods = DOMHelper::getElementByTagName(root, "Period", false);
    std::vector<Node *>::const_iterator it;

    for(it = periods.begin(); it != periods.end(); ++it)
    {
        Period *period = new (std::nothrow) Period(mpd);
        if (!period)
            continue;
        parseSegmentInformation(*it, period);
        if((*it)->hasAttribute("start"))
            period->startTime.Set(IsoTime((*it)->getAttributeValue("start")));
        if((*it)->hasAttribute("duration"))
            period->duration.Set(IsoTime((*it)->getAttributeValue("duration")));
        if((*it)->hasAttribute("id"))
            period->setId((*it)->getAttributeValue("id"));
        std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(*it, "BaseURL");
        if(!baseUrls.empty())
            period->baseUrl.Set( new Url( baseUrls.front()->getText() ) );

        setAdaptationSets(*it, period);
        mpd->addPeriod(period);
    }
}
 Time SwaptionVolatilityStructure::swapLength(const Period& p) const {
     QL_REQUIRE(p.length()>0,
                "non-positive swap tenor (" << p << ") given");
     switch (p.units()) {
       case Months:
         return p.length()/12.0;
       case Years:
         return static_cast<Time>(p.length());
       default:
         QL_FAIL("invalid Time Unit (" << p.units() << ") for swap length");
     }
 }
    AmortizingFixedRateBond::AmortizingFixedRateBond(
                                      Natural settlementDays,
                                      const Calendar& calendar,
                                      Real initialFaceAmount,
                                      const Date& startDate,
                                      const Period& bondTenor,
                                      const Frequency& sinkingFrequency,
                                      const Rate coupon,
                                      const DayCounter& accrualDayCounter,
                                      BusinessDayConvention paymentConvention,
                                      const Date& issueDate)
    : Bond(settlementDays, calendar, issueDate),
      frequency_(sinkingFrequency),
      dayCounter_(accrualDayCounter) {

        QL_REQUIRE(bondTenor.length() > 0,
                   "bond tenor must be positive. "
                   << bondTenor << " is not allowed.");
        maturityDate_ = startDate + bondTenor;

        cashflows_ =
            FixedRateLeg(sinkingSchedule(startDate, bondTenor,
                                         sinkingFrequency, calendar))
            .withNotionals(sinkingNotionals(bondTenor,
                                            sinkingFrequency, coupon,
                                            initialFaceAmount))
            .withCouponRates(coupon, accrualDayCounter)
            .withPaymentAdjustment(paymentConvention);

        addRedemptionsToCashflows();
    }
Beispiel #5
0
    Real days(const Period& p) {
        if (p.length()==0) return 0.0;

        switch (p.units()) {
          case Days:
              return p.length();
          case Weeks:
              return p.length()*7.0;
          case Months:
            QL_FAIL("cannot convert Months into Days");
          case Years:
            QL_FAIL("cannot convert Years into Days");
          default:
            QL_FAIL("unknown time unit (" << Integer(p.units()) << ")");
        }
    }
Beispiel #6
0
    FixedRateBond::FixedRateBond(Natural settlementDays,
                                 const Calendar& calendar,
                                 Real faceAmount,
                                 const Date& startDate,
                                 const Date& maturityDate,
                                 const Period& tenor,
                                 const std::vector<Rate>& coupons,
                                 const DayCounter& accrualDayCounter,
                                 BusinessDayConvention accrualConvention,
                                 BusinessDayConvention paymentConvention,
                                 Real redemption,
                                 const Date& issueDate,
                                 const Date& stubDate,
                                 DateGeneration::Rule rule,
                                 bool endOfMonth,
                                 const Calendar& paymentCalendar)
     : Bond(settlementDays,
            paymentCalendar==Calendar() ? calendar : paymentCalendar,
            issueDate),
      frequency_(tenor.frequency()), dayCounter_(accrualDayCounter) {

        maturityDate_ = maturityDate;

        Date firstDate, nextToLastDate;
        switch (rule) {
          case DateGeneration::Backward:
            firstDate = Date();
            nextToLastDate = stubDate;
            break;
          case DateGeneration::Forward:
            firstDate = stubDate;
            nextToLastDate = Date();
            break;
          case DateGeneration::Zero:
          case DateGeneration::ThirdWednesday:
          case DateGeneration::Twentieth:
          case DateGeneration::TwentiethIMM:
            QL_FAIL("stub date (" << stubDate << ") not allowed with " <<
                    rule << " DateGeneration::Rule");
          default:
            QL_FAIL("unknown DateGeneration::Rule (" << Integer(rule) << ")");
        }

        Schedule schedule(startDate, maturityDate_, tenor,
                          calendar, accrualConvention, accrualConvention,
                          rule, endOfMonth,
                          firstDate, nextToLastDate);

        cashflows_ = FixedRateLeg(schedule)
            .withNotionals(faceAmount)
            .withCouponRates(coupons, accrualDayCounter)
            .withPaymentCalendar(calendar_)
            .withPaymentAdjustment(paymentConvention);

        addRedemptionsToCashflows(std::vector<Real>(1, redemption));

        QL_ENSURE(!cashflows().empty(), "bond with no cashflows!");
        QL_ENSURE(redemptions_.size() == 1, "multiple redemptions created");
    }
 void SwaptionVolatilityStructure::checkSwapTenor(const Period& swapTenor,
                                                  bool extrapolate) const {
     QL_REQUIRE(swapTenor.length() > 0,
                "non-positive swap tenor (" << swapTenor << ") given");
     QL_REQUIRE(extrapolate || allowsExtrapolation() ||
                swapTenor <= maxSwapTenor(),
                "swap tenor (" << swapTenor << ") is past max tenor ("
                << maxSwapTenor() << ")");
 }
Beispiel #8
0
int main()
{
	//creating object of period by calling default constructor
	Period period;
	//creating object of period by calling constructor w/ param
    PeriodName name;
    char ch = 'y';
    int range1, range2;
    
    //loop
    while (ch == 'y' || ch == 'Y')
    {
        //user prompt to enter year ranges
        cout << "Enter the range of the prehistoric dates"
        << endl << "(in Million years, seperated" << "by space):";
        //read years
        cin >> range1 >> range2;
        //check validity of range then display error
        if(range1 < 0||range2 < 0)
            cout << "Invalid range. Please try again." << endl;
        else
       {
            //loop to display peroid names within range
            for(name = NEOGENE; name <= PRECAMBRIAN;
                name = PeriodName(name + 1))
            {
				if(period.toInt(name) >= range1 &&
				period.toInt(name)< range2)
				cout << "Period Name: " << period.toString(name) << endl << "The Period Began At " << period.toInt(name) << " Million Years." << endl << endl;
            }//end of for statement
            cout << endl << endl;
            //prompt user to continue
            cout << "Do you want to continue?"
            << "(Press 'n' to Exit 'y' to continue):";
            cin >> ch;
            cout << endl;
		}
    }
    system("Pause");
    return 0;
}
Beispiel #9
0
void    IsoffMainParser::print              ()
{
    if(this->mpd)
    {
        msg_Dbg(this->p_stream, "MPD profile=%d mediaPresentationDuration=%ld minBufferTime=%ld", this->mpd->getProfile(),
                                                                                                  this->mpd->getDuration(),
                                                                                                  this->mpd->getMinBufferTime());
        const std::vector<BaseUrl *> baseurls = this->mpd->getBaseUrls();

        for(size_t i = 0; i < baseurls.size(); i++)
            msg_Dbg(this->p_stream, "BaseUrl=%s", baseurls.at(i)->getUrl().c_str());

        const std::vector<Period *> periods = this->mpd->getPeriods();

        for(size_t i = 0; i < periods.size(); i++)
        {
            Period *period = periods.at(i);
            msg_Dbg(this->p_stream, " Period");
            for(size_t j = 0; j < period->getAdaptationSets().size(); j++)
            {
                AdaptationSet *aset = period->getAdaptationSets().at(j);
                msg_Dbg(this->p_stream, "  AdaptationSet");
                for(size_t k = 0; k < aset->getRepresentations().size(); k++)
                {
                    Representation *rep = aset->getRepresentations().at(k);
                    msg_Dbg(this->p_stream, "   Representation");
                    Segment *initSeg = rep->getSegmentBase()->getInitSegment();
                    msg_Dbg(this->p_stream, "    InitSeg url=%s", initSeg->getSourceUrl().c_str());
                    for(size_t l = 0; l < rep->getSegmentList()->getSegments().size(); l++)
                    {
                        Segment *seg = rep->getSegmentList()->getSegments().at(l);
                        msg_Dbg(this->p_stream, "    Segment url=%s", seg->getSourceUrl().c_str());
                    }
                }
            }
        }
    }
}
 void CallableBondVolatilityStructure::checkRange(const Date& optionDate,
                                                  const Period& bondTenor,
                                                  Rate k,
                                                  bool extrapolate) const {
     TermStructure::checkRange(timeFromReference(optionDate),
                               extrapolate);
     QL_REQUIRE(bondTenor.length() > 0,
                "negative bond tenor (" << bondTenor << ") given");
     QL_REQUIRE(extrapolate || allowsExtrapolation() ||
                bondTenor <= maxBondTenor(),
                "bond tenor (" << bondTenor << ") is past max tenor ("
                << maxBondTenor() << ")");
     QL_REQUIRE(extrapolate || allowsExtrapolation() ||
                (k >= minStrike() && k <= maxStrike()),
                "strike (" << k << ") is outside the curve domain ["
                << minStrike() << "," << maxStrike()<< "]");
 }
Beispiel #11
0
 inline Date Date::operator-(const Period& p) const {
     return advance(*this,-p.length(),p.units());
 }
Beispiel #12
0
 /*!
  * @brief Add period to Date
  */
 Date operator+(const Period& add) const
 { return (utc + add.get_nsecs()); }
Beispiel #13
0
 /*!
  * @brief Decrement period from Date
  */
 Date operator-(const Period& dec) const
 { return (utc - dec.get_nsecs()); }
Beispiel #14
0
void load_courses_from_csv(SchoolSchedule *sopti, string periods_file)
{
	ifstream period_list;
	string tmps;
	char tmpa[500];
	vector<string> fields;
	
	// Open the file
	period_list.open(periods_file.c_str());
	if(period_list.fail()) {
		error("error opening file %s", periods_file.c_str());
	}
	
	// Ignore header line
	period_list.getline(tmpa, 500);
	
	while(1) {
		period_list.getline(tmpa, 500);
		if(!period_list.good()) {
			break;
		}
		
		tmps = tmpa;
		if(tmps[tmps.size()-1] == '\r')
			tmps.erase(tmps.size()-1, 1);
	
		fields = split_string(tmps, ";");
		if(fields.size() != 15) {
			error("invalid course file format (field_num != 15)");
		}
		
		// prepare some variables in advance
		bool islab;
		int type;
		SchoolCourse *current_course;
		
		if(fields[COURSEFILE_FIELD_COURSELAB] == "L")
			islab=true;
		else if(fields[COURSEFILE_FIELD_COURSELAB] == "C")
			islab=false;
		else
			error("unrecognized course type");
		
		if(fields[COURSEFILE_FIELD_COURSETYPE] == "T")
			type = COURSE_TYPE_THEORYONLY;
		else if(fields[COURSEFILE_FIELD_COURSETYPE] == "L")
			type = COURSE_TYPE_LABONLY;
		else if(fields[COURSEFILE_FIELD_COURSETYPE] == "TL")
			type = COURSE_TYPE_THEORYLABSAME;
		else if(fields[COURSEFILE_FIELD_COURSETYPE] == "TLS")
			type = COURSE_TYPE_THEORYLABIND;
		
		// Add course if not exists
		if(!sopti->course_exists(fields[COURSEFILE_FIELD_SYMBOL])) {
			SchoolCourse newcourse(fields[COURSEFILE_FIELD_SYMBOL]);
			newcourse.set_title(fields[COURSEFILE_FIELD_TITLE]);
			newcourse.set_type(type);
			sopti->course_add(newcourse);
		}
		
		current_course = sopti->course(fields[COURSEFILE_FIELD_SYMBOL]);
		
		// Add group if not exists
		if(!current_course->group_exists(fields[COURSEFILE_FIELD_GROUP], islab)) {
			Group newgroup(fields[COURSEFILE_FIELD_GROUP]);
			newgroup.set_lab(islab);
			
			current_course->add_group(newgroup, islab);
		}
		
		// Add period. It should not exist.
		
		int period_no = poly_make_period_no(fields[COURSEFILE_FIELD_DAY], fields[COURSEFILE_FIELD_TIME]);
		if(current_course->group(fields[COURSEFILE_FIELD_GROUP], islab)->has_period(period_no)) {
			error("two occurences of the same period in course file");
		}
		
		Period newperiod;
		newperiod.set_room(fields[COURSEFILE_FIELD_ROOM]);
		newperiod.set_period_no(period_no);
		if(fields[COURSEFILE_FIELD_LABWEEK] == "I") {
			newperiod.set_week(1);
		}
		else if(fields[COURSEFILE_FIELD_LABWEEK] == "P") {
			newperiod.set_week(2);
		}
		else {
			newperiod.set_week(0);
		}
		current_course->group(fields[COURSEFILE_FIELD_GROUP], islab)->add_period(newperiod);
	}
	
	period_list.close();
}
Beispiel #15
0
 Date Calendar::advance(const Date & d,
                        const Period & p,
                        BusinessDayConvention c,
                        bool endOfMonth) const {
     return advance(d, p.length(), p.units(), c, endOfMonth);
 }
    void InterpolatedCPICapFloorTermPriceSurface<I2D>::
    performCalculations() const {
        
		
		Size nMat = cfMaturities_.size(), ncK = cStrikes_.size(), nfK = fStrikes_.size(),
			nK = ncK + nfK;
		Matrix cP(nK, nMat), fP(nK, nMat);
		Handle<ZeroInflationTermStructure> zts = zii_->zeroInflationTermStructure();
		Handle<YieldTermStructure> yts = this->nominalTermStructure();
		QL_REQUIRE(!zts.empty(),"Zts is empty!!!");
		QL_REQUIRE(!yts.empty(),"Yts is empty!!!");
		
		for (Size i =0; i<nfK; i++){
			allStrikes_.push_back(fStrikes_[i]);
			for (Size j=0; j<nMat; j++) {
				Period mat = cfMaturities_[j];
				Real df = yts->discount(cpiOptionDateFromTenor(mat));
				Real atm_quote = zts->zeroRate(cpiOptionDateFromTenor(mat));
				Real atm = pow(1.0+atm_quote, mat.length());
				Real S = atm * df;
				Real K_quote = fStrikes_[i]/100.0;
				Real K = pow(1.0+K_quote, mat.length());
				cP[i][j] = fPrice_[i][j] + S - K * df;
				fP[i][j] = fPrice_[i][j];
			}
		}
		for (Size i =0; i<ncK; i++){
			allStrikes_.push_back(cStrikes_[i]);
			for (Size j=0; j<nMat; j++) {
				Period mat = cfMaturities_[j];
				Real df = yts->discount(cpiOptionDateFromTenor(mat));
				Real atm_quote = zts->zeroRate(cpiOptionDateFromTenor(mat));
				Real atm = pow(1.0+atm_quote, mat.length());
				Real S = atm * df;
				Real K_quote = cStrikes_[i]/100.0;
				Real K = pow(1.0+K_quote, mat.length());
				cP[i+nfK][j] = cPrice_[i][j];
				fP[i+nfK][j] = cPrice_[i][j] + K * df - S;
			}
		}
		
		// copy to store		
		cPriceB_ = cP;
		fPriceB_ = fP;
		
		cfMaturityTimes_.clear();
        for (Size i=0; i<cfMaturities_.size();i++) {
            cfMaturityTimes_.push_back(timeFromReference(cpiOptionDateFromTenor(cfMaturities_[i])));
        }
		
        capPrice_ = interpolator2d_.interpolate(cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
												allStrikes_.begin(), allStrikes_.end(),
												cPriceB_
												);
        capPrice_.enableExtrapolation();
		
        floorPrice_ = interpolator2d_.interpolate(cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
												  allStrikes_.begin(), allStrikes_.end(),
												  fPriceB_
												  );
        floorPrice_.enableExtrapolation();
		
		/* test code - note order of indices
		for (Size i =0; i<nK; i++){
			std::cout << allStrikes_[i] << ":  ";
			Real qK = allStrikes_[i];
			for (Size j=0; j<nMat; j++) {
				Real t = cfMaturityTimes_[j];
				std::cout << fP[i][j] << "," << floorPrice_(t,qK) << " | " ;
			}
			std::cout << std::endl;
		}
		
		for (Size i =0; i<nK; i++){
			std::cout << allStrikes_[i] << ":  ";
			Real qK = allStrikes_[i];
			for (Size j=0; j<nMat; j++) {
				Real t = cfMaturityTimes_[j];
				std::cout << cP[i][j] << "," << capPrice_(t,qK) << " | " ;
			}
			std::cout << std::endl;
		}
		*/
    }
Beispiel #17
0
 Frequency frequencyFromPeriod(const Period& p) {
     return p.frequency();
 }
Beispiel #18
0
    bool operator<(const Period& p1, const Period& p2) {

        // special cases
        if (p1.length() == 0)
            return p2.length() > 0;
        if (p2.length() == 0)
            return p1.length() < 0;

        // exact comparisons
        if (p1.units() == p2.units())
            return p1.length() < p2.length();
        if (p1.units() == Months && p2.units() == Years)
            return p1.length() < 12*p2.length();
        if (p1.units() == Years && p2.units() == Months)
            return 12*p1.length() < p2.length();
        if (p1.units() == Days && p2.units() == Weeks)
            return p1.length() < 7*p2.length();
        if (p1.units() == Weeks && p2.units() == Days)
            return 7*p1.length() < p2.length();

        // inexact comparisons (handled by converting to days and using limits)
        std::pair<Integer, Integer> p1lim = daysMinMax(p1);
        std::pair<Integer, Integer> p2lim = daysMinMax(p2);

        if (p1lim.second < p2lim.first)
            return true;
        else if (p1lim.first > p2lim.second)
            return false;
        else
            QL_FAIL("undecidable comparison between " << p1 << " and " << p2);
    }
Beispiel #19
0
    Schedule::Schedule(Date effectiveDate,
                       const Date& terminationDate,
                       const Period& tenor,
                       const Calendar& cal,
                       BusinessDayConvention convention,
                       BusinessDayConvention terminationDateConvention,
                       DateGeneration::Rule rule,
                       bool endOfMonth,
                       const Date& first,
                       const Date& nextToLast)
    : tenor_(tenor), calendar_(cal), convention_(convention),
      terminationDateConvention_(terminationDateConvention), rule_(rule),
      endOfMonth_(allowsEndOfMonth(tenor) ? endOfMonth : false),
      firstDate_(first==effectiveDate ? Date() : first),
      nextToLastDate_(nextToLast==terminationDate ? Date() : nextToLast)
    {
        // sanity checks
        QL_REQUIRE(terminationDate != Date(), "null termination date");

        // in many cases (e.g. non-expired bonds) the effective date is not
        // really necessary. In these cases a decent placeholder is enough
        if (effectiveDate==Date() && first==Date()
                                  && rule==DateGeneration::Backward) {
            Date evalDate = Settings::instance().evaluationDate();
            QL_REQUIRE(evalDate < terminationDate, "null effective date");
            Natural y;
            if (nextToLast != Date()) {
                y = (nextToLast - evalDate)/366 + 1;
                effectiveDate = nextToLast - y*Years;
            } else {
                y = (terminationDate - evalDate)/366 + 1;
                effectiveDate = terminationDate - y*Years;
            }
        } else
            QL_REQUIRE(effectiveDate != Date(), "null effective date");

        QL_REQUIRE(effectiveDate < terminationDate,
                   "effective date (" << effectiveDate
                   << ") later than or equal to termination date ("
                   << terminationDate << ")");

        if (tenor.length()==0)
            rule_ = DateGeneration::Zero;
        else
            QL_REQUIRE(tenor.length()>0,
                       "non positive tenor (" << tenor << ") not allowed");

        if (firstDate_ != Date()) {
            switch (*rule_) {
              case DateGeneration::Backward:
              case DateGeneration::Forward:
                QL_REQUIRE(firstDate_ > effectiveDate &&
                           firstDate_ < terminationDate,
                           "first date (" << firstDate_ <<
                           ") out of effective-termination date range [" <<
                           effectiveDate << ", " << terminationDate << ")");
                // we should ensure that the above condition is still
                // verified after adjustment
                break;
              case DateGeneration::ThirdWednesday:
                  QL_REQUIRE(IMM::isIMMdate(firstDate_, false),
                             "first date (" << firstDate_ <<
                             ") is not an IMM date");
                break;
              case DateGeneration::Zero:
              case DateGeneration::Twentieth:
              case DateGeneration::TwentiethIMM:
              case DateGeneration::OldCDS:
              case DateGeneration::CDS:
                QL_FAIL("first date incompatible with " << *rule_ <<
                        " date generation rule");
              default:
                QL_FAIL("unknown rule (" << Integer(*rule_) << ")");
            }
        }
        if (nextToLastDate_ != Date()) {
            switch (*rule_) {
              case DateGeneration::Backward:
              case DateGeneration::Forward:
                QL_REQUIRE(nextToLastDate_ > effectiveDate &&
                           nextToLastDate_ < terminationDate,
                           "next to last date (" << nextToLastDate_ <<
                           ") out of effective-termination date range (" <<
                           effectiveDate << ", " << terminationDate << "]");
                // we should ensure that the above condition is still
                // verified after adjustment
                break;
              case DateGeneration::ThirdWednesday:
                QL_REQUIRE(IMM::isIMMdate(nextToLastDate_, false),
                           "next-to-last date (" << nextToLastDate_ <<
                           ") is not an IMM date");
                break;
              case DateGeneration::Zero:
              case DateGeneration::Twentieth:
              case DateGeneration::TwentiethIMM:
              case DateGeneration::OldCDS:
              case DateGeneration::CDS:
                QL_FAIL("next to last date incompatible with " << *rule_ <<
                        " date generation rule");
              default:
                QL_FAIL("unknown rule (" << Integer(*rule_) << ")");
            }
        }


        // calendar needed for endOfMonth adjustment
        Calendar nullCalendar = NullCalendar();
        Integer periods = 1;
        Date seed, exitDate;
        switch (*rule_) {

          case DateGeneration::Zero:
            tenor_ = 0*Years;
            dates_.push_back(effectiveDate);
            dates_.push_back(terminationDate);
            isRegular_.push_back(true);
            break;

          case DateGeneration::Backward:

            dates_.push_back(terminationDate);

            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_;
            }

            exitDate = effectiveDate;
            if (firstDate_ != Date())
                exitDate = firstDate_;

            for (;;) {
                Date temp = nullCalendar.advance(seed,
                    -periods*(*tenor_), convention, *endOfMonth_);
                if (temp < exitDate) {
                    if (firstDate_ != Date() &&
                        (calendar_.adjust(dates_.front(),convention)!=
                         calendar_.adjust(firstDate_,convention))) {
                        dates_.insert(dates_.begin(), firstDate_);
                        isRegular_.insert(isRegular_.begin(), false);
                    }
                    break;
                } else {
                    // skip dates that would result in duplicates
                    // after adjustment
                    if (calendar_.adjust(dates_.front(),convention)!=
                        calendar_.adjust(temp,convention)) {
                        dates_.insert(dates_.begin(), temp);
                        isRegular_.insert(isRegular_.begin(), true);
                    }
                    ++periods;
                }
            }

            if (calendar_.adjust(dates_.front(),convention)!=
                calendar_.adjust(effectiveDate,convention)) {
                dates_.insert(dates_.begin(), effectiveDate);
                isRegular_.insert(isRegular_.begin(), false);
            }
            break;

          case DateGeneration::Twentieth:
          case DateGeneration::TwentiethIMM:
          case DateGeneration::ThirdWednesday:
          case DateGeneration::OldCDS:
          case DateGeneration::CDS:
            QL_REQUIRE(!*endOfMonth_,
                       "endOfMonth convention incompatible with " << *rule_ <<
                       " date generation rule");
          // fall through
          case DateGeneration::Forward:

            if (*rule_ == DateGeneration::CDS) {
                dates_.push_back(previousTwentieth(effectiveDate,
                                                   DateGeneration::CDS));
            } else {
                dates_.push_back(effectiveDate);
            }

            seed = dates_.back();

            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_;
            } else if (*rule_ == DateGeneration::Twentieth ||
                       *rule_ == DateGeneration::TwentiethIMM ||
                       *rule_ == DateGeneration::OldCDS ||
                       *rule_ == DateGeneration::CDS) {
                Date next20th = nextTwentieth(effectiveDate, *rule_);
                if (*rule_ == DateGeneration::OldCDS) {
                    // distance rule inforced in natural days
                    static const BigInteger stubDays = 30;
                    if (next20th - effectiveDate < stubDays) {
                        // +1 will skip this one and get the next
                        next20th = nextTwentieth(next20th + 1, *rule_);
                    }
                }
                if (next20th != effectiveDate) {
                    dates_.push_back(next20th);
                    isRegular_.push_back(false);
                    seed = next20th;
                }
            }

            exitDate = terminationDate;
            if (nextToLastDate_ != Date())
                exitDate = nextToLastDate_;

            for (;;) {
                Date temp = nullCalendar.advance(seed, periods*(*tenor_),
                                                 convention, *endOfMonth_);
                if (temp > exitDate) {
                    if (nextToLastDate_ != Date() &&
                        (calendar_.adjust(dates_.back(),convention)!=
                         calendar_.adjust(nextToLastDate_,convention))) {
                        dates_.push_back(nextToLastDate_);
                        isRegular_.push_back(false);
                    }
                    break;
                } else {
                    // skip dates that would result in duplicates
                    // after adjustment
                    if (calendar_.adjust(dates_.back(),convention)!=
                        calendar_.adjust(temp,convention)) {
                        dates_.push_back(temp);
                        isRegular_.push_back(true);
                    }
                    ++periods;
                }
            }

            if (calendar_.adjust(dates_.back(),terminationDateConvention)!=
                calendar_.adjust(terminationDate,terminationDateConvention)) {
                if (*rule_ == DateGeneration::Twentieth ||
                    *rule_ == DateGeneration::TwentiethIMM ||
                    *rule_ == DateGeneration::OldCDS ||
                    *rule_ == DateGeneration::CDS) {
                    dates_.push_back(nextTwentieth(terminationDate, *rule_));
                    isRegular_.push_back(true);
                } else {
                    dates_.push_back(terminationDate);
                    isRegular_.push_back(false);
                }
            }

            break;

          default:
            QL_FAIL("unknown rule (" << Integer(*rule_) << ")");
        }

        // adjustments
        if (*rule_==DateGeneration::ThirdWednesday)
            for (Size i=1; i<dates_.size()-1; ++i)
                dates_[i] = Date::nthWeekday(3, Wednesday,
                                             dates_[i].month(),
                                             dates_[i].year());

        if (*endOfMonth_ && calendar_.isEndOfMonth(seed)) {
            // adjust to end of month
            if (convention == Unadjusted) {
                for (Size i=1; i<dates_.size()-1; ++i)
                    dates_[i] = Date::endOfMonth(dates_[i]);
            } else {
                for (Size i=1; i<dates_.size()-1; ++i)
                    dates_[i] = calendar_.endOfMonth(dates_[i]);
            }
            if (terminationDateConvention != Unadjusted) {
                dates_.front() = calendar_.endOfMonth(dates_.front());
                dates_.back() = calendar_.endOfMonth(dates_.back());
            } else {
                // the termination date is the first if going backwards,
                // the last otherwise.
                if (*rule_ == DateGeneration::Backward)
                    dates_.back() = Date::endOfMonth(dates_.back());
                else
                    dates_.front() = Date::endOfMonth(dates_.front());
            }
        } else {
            // first date not adjusted for CDS schedules
            if (*rule_ != DateGeneration::OldCDS)
                dates_[0] = calendar_.adjust(dates_[0], convention);
            for (Size i=1; i<dates_.size()-1; ++i)
                dates_[i] = calendar_.adjust(dates_[i], convention);

            // termination date is NOT adjusted as per ISDA
            // specifications, unless otherwise specified in the
            // confirmation of the deal or unless we're creating a CDS
            // schedule
            if (terminationDateConvention != Unadjusted
                || *rule_ == DateGeneration::Twentieth
                || *rule_ == DateGeneration::TwentiethIMM
                || *rule_ == DateGeneration::OldCDS
                || *rule_ == DateGeneration::CDS) {
                dates_.back() = calendar_.adjust(dates_.back(),
                                                terminationDateConvention);
            }
        }

        // Final safety checks to remove extra next-to-last date, if
        // necessary.  It can happen to be equal or later than the end
        // date due to EOM adjustments (see the Schedule test suite
        // for an example).
        if (dates_.size() >= 2 && dates_[dates_.size()-2] >= dates_.back()) {
            isRegular_[dates_.size()-2] =
                (dates_[dates_.size()-2] == dates_.back());
            dates_[dates_.size()-2] = dates_.back();
            dates_.pop_back();
            isRegular_.pop_back();
        }
        if (dates_.size() >= 2 && dates_[1] <= dates_.front()) {
            isRegular_[1] =
                (dates_[1] == dates_.front());
            dates_[1] = dates_.front();
            dates_.erase(dates_.begin());
            isRegular_.erase(isRegular_.begin());
        }

        QL_ENSURE(dates_.size()>1,
            "degenerate single date (" << dates_[0] << ") schedule" <<
            "\n seed date: " << seed <<
            "\n exit date: " << exitDate <<
            "\n effective date: " << effectiveDate <<
            "\n first date: " << first <<
            "\n next to last date: " << nextToLast <<
            "\n termination date: " << terminationDate <<
            "\n generation rule: " << *rule_ <<
            "\n end of month: " << *endOfMonth_);

    }