예제 #1
0
 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();
    }
예제 #3
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()) << ")");
        }
    }
예제 #4
0
 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() << ")");
 }
예제 #5
0
 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()<< "]");
 }
예제 #6
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;
		}
		*/
    }
예제 #8
0
 inline Date Date::operator-(const Period& p) const {
     return advance(*this,-p.length(),p.units());
 }
예제 #9
0
파일: schedule.cpp 프로젝트: 21hub/QuantLib
    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_);

    }
예제 #10
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);
    }