public AmortizingFixedRateBond( int settlementDays, Calendar calendar, double faceAmount, Date startDate, Period bondTenor, Frequency sinkingFrequency, double coupon, DayCounter accrualDayCounter, BusinessDayConvention paymentConvention = BusinessDayConvention.Following, Date issueDate = null) : base(settlementDays, calendar, issueDate) { frequency_ = sinkingFrequency; dayCounter_ = accrualDayCounter; Utils.QL_REQUIRE(bondTenor.length() > 0, () => "bond tenor must be positive. " + bondTenor + " is not allowed."); maturityDate_ = startDate + bondTenor; schedule_ = sinkingSchedule(startDate, bondTenor, sinkingFrequency, calendar); cashflows_ = new FixedRateLeg(schedule_) .withCouponRates(coupon, accrualDayCounter) .withNotionals(sinkingNotionals(bondTenor, sinkingFrequency, coupon, faceAmount)) .withPaymentAdjustment(paymentConvention).value(); addRedemptionsToCashflows(); }
//! implements the conversion between swap tenor and swap (time) length public double swapLength(Period swapTenor) { Utils.QL_REQUIRE(swapTenor.length() > 0, () => "non-positive swap tenor (" + swapTenor + ") given"); switch (swapTenor.units()) { case TimeUnit.Months: return(swapTenor.length() / 12.0); case TimeUnit.Years: return(swapTenor.length()); default: Utils.QL_FAIL("invalid Time Unit (" + swapTenor.units() + ") for swap length"); return(0); } }
//! The factor returned is NOT normalized relative to ANYTHING. public virtual double seasonalityFactor(Date to) { Date from = seasonalityBaseDate(); Frequency factorFrequency = frequency(); int nFactors = seasonalityFactors().Count; Period factorPeriod = new Period(factorFrequency); int which = 0; if (from==to) { which = 0; } else { // days, weeks, months, years are the only time unit possibilities int diffDays = Math.Abs(to - from); // in days int dir = 1; if(from > to)dir = -1; int diff; if (factorPeriod.units() == TimeUnit.Days) { diff = dir*diffDays; } else if (factorPeriod.units() == TimeUnit.Weeks) { diff = dir * (diffDays / 7); } else if (factorPeriod.units() == TimeUnit.Months) { KeyValuePair<Date,Date> lim = Utils.inflationPeriod(to, factorFrequency); diff = diffDays / (31*factorPeriod.length()); Date go = from + dir*diff*factorPeriod; while ( !(lim.Key <= go && go <= lim.Value) ) { go += dir*factorPeriod; diff++; } diff=dir*diff; } else if (factorPeriod.units() == TimeUnit.Years) { throw new ApplicationException( "seasonality period time unit is not allowed to be : " + factorPeriod.units()); } else { throw new ApplicationException("Unknown time unit: " + factorPeriod.units()); } // now adjust to the available number of factors, direction dependent if (dir==1) { which = diff % nFactors; } else { which = (nFactors - (-diff % nFactors)) % nFactors; } } return seasonalityFactors()[which]; }
public AmortizingFixedRateBond( int settlementDays, Calendar calendar, double faceAmount, Date startDate, Period bondTenor, Frequency sinkingFrequency, double coupon, DayCounter accrualDayCounter, BusinessDayConvention paymentConvention = BusinessDayConvention.Following, Date issueDate = null) :base(settlementDays, calendar, issueDate) { frequency_ = sinkingFrequency; dayCounter_ = accrualDayCounter; Utils.QL_REQUIRE( bondTenor.length() > 0,() => "bond tenor must be positive. " + bondTenor + " is not allowed." ); maturityDate_ = startDate + bondTenor; maturityDate_ = startDate + bondTenor; schedule_ = sinkingSchedule(startDate, bondTenor, sinkingFrequency, calendar); cashflows_ = new FixedRateLeg(schedule_) .withCouponRates(coupon, accrualDayCounter) .withNotionals(sinkingNotionals(bondTenor, sinkingFrequency, coupon, faceAmount)) .withPaymentAdjustment(paymentConvention).value(); addRedemptionsToCashflows(); }
protected void checkSwapTenor(Period swapTenor, bool extrapolate) { if (!(swapTenor.length() > 0)) { throw new ApplicationException("non-positive swap tenor (" + swapTenor + ") given"); } if (!(extrapolate || allowsExtrapolation() || swapTenor <= maxSwapTenor())) { throw new ApplicationException("swap tenor (" + swapTenor + ") is past max tenor (" + maxSwapTenor() + ")"); } }
//@} //! implements the conversion between swap tenor and swap (time) length public double swapLength(Period p) { if (!(p.length() > 0)) { throw new ApplicationException("non-positive swap tenor (" + p + ") given"); } // while using the reference date is arbitrary it is coherent between // different swaption structures defined on the same reference date. // Date start = referenceDate(); Date end = start + p; return(swapLength(start, end)); }
protected void checkRange(Date optionDate, Period bondTenor, double k, bool extrapolate) { base.checkRange(timeFromReference(optionDate), extrapolate); Utils.QL_REQUIRE(bondTenor.length() > 0, () => "negative bond tenor (" + bondTenor + ") given"); Utils.QL_REQUIRE(extrapolate || allowsExtrapolation() || bondTenor <= maxBondTenor(), () => "bond tenor (" + bondTenor + ") is past max tenor (" + maxBondTenor() + ")"); Utils.QL_REQUIRE(extrapolate || allowsExtrapolation() || (k >= minStrike() && k <= maxStrike()), () => "strike (" + k + ") is outside the curve domain [" + minStrike() + "," + maxStrike() + "]"); }
KeyValuePair <int, int> daysMinMax(Period p) { switch (p.units()) { case TimeUnit.Days: return(new KeyValuePair <int, int>(p.length(), p.length())); case TimeUnit.Weeks: return(new KeyValuePair <int, int>(7 * p.length(), 7 * p.length())); case TimeUnit.Months: return(new KeyValuePair <int, int>(28 * p.length(), 31 * p.length())); case TimeUnit.Years: return(new KeyValuePair <int, int>(365 * p.length(), 366 * p.length())); default: throw new ApplicationException("unknown time unit (" + p.units() + ")"); } }
public pair(Period p) { switch (p.units()) { case TimeUnit.Days: lo = hi = p.length(); break; case TimeUnit.Weeks: lo = hi = 7 * p.length(); break; case TimeUnit.Months: lo = 28 * p.length(); hi = 31 * p.length(); break; case TimeUnit.Years: lo = 365 * p.length(); hi = 366 * p.length(); break; default: throw new ArgumentException("Unknown TimeUnit: " + p.units()); } }
public pair(Period p) { switch (p.units()) { case TimeUnit.Days: lo = hi = p.length(); break; case TimeUnit.Weeks: lo = hi = 7 * p.length(); break; case TimeUnit.Months: lo = 28 * p.length(); hi = 31 * p.length(); break; case TimeUnit.Years: lo = 365 * p.length(); hi = 366 * p.length(); break; default: Utils.QL_FAIL("Unknown TimeUnit: " + p.units()); lo = hi = 0; break; } }
public OvernightIndexedSwap value() { Date startDate; if (effectiveDate_ != null) { startDate = effectiveDate_; } else { Date refDate = Settings.evaluationDate(); // if the evaluation date is not a business day // then move to the next business day refDate = calendar_.adjust(refDate); Date spotDate = calendar_.advance(refDate, new Period(settlementDays_, TimeUnit.Days)); startDate = spotDate + forwardStart_; if (forwardStart_.length() < 0) { startDate = calendar_.adjust(startDate, BusinessDayConvention.Preceding); } else { startDate = calendar_.adjust(startDate, BusinessDayConvention.Following); } } // OIS end of month default bool usedEndOfMonth = isDefaultEOM_ ? calendar_.isEndOfMonth(startDate) : endOfMonth_; Date endDate = terminationDate_; if (endDate == null) { if (usedEndOfMonth) { endDate = calendar_.advance(startDate, swapTenor_, BusinessDayConvention.ModifiedFollowing, usedEndOfMonth); } else { endDate = startDate + swapTenor_; } } Schedule schedule = new Schedule(startDate, endDate, new Period(paymentFrequency_), calendar_, BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, rule_, usedEndOfMonth); double?usedFixedRate = fixedRate_; if (fixedRate_ == null) { OvernightIndexedSwap temp = new OvernightIndexedSwap(type_, nominal_, schedule, 0.0, // fixed rate fixedDayCount_, overnightIndex_, overnightSpread_); if (engine_ == null) { Handle <YieldTermStructure> disc = overnightIndex_.forwardingTermStructure(); Utils.QL_REQUIRE(!disc.empty(), () => "null term structure set to this instance of " + overnightIndex_.name()); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); temp.setPricingEngine(engine); } else { temp.setPricingEngine(engine_); } usedFixedRate = temp.fairRate(); } OvernightIndexedSwap ois = new OvernightIndexedSwap(type_, nominal_, schedule, usedFixedRate.Value, fixedDayCount_, overnightIndex_, overnightSpread_); if (engine_ == null) { Handle <YieldTermStructure> disc = overnightIndex_.forwardingTermStructure(); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); ois.setPricingEngine(engine); } else { ois.setPricingEngine(engine_); } return(ois); }
//! set up the interpolations for capPrice_ and floorPrice_ //! since we know ATM, and we have single flows, //! we can use put/call parity to extend the surfaces //! across all strikes protected override void performCalculations() { allStrikes_ = new List <double>(); int nMat = cfMaturities_.Count, ncK = cStrikes_.Count, nfK = fStrikes_.Count, nK = ncK + nfK; Matrix cP = new Matrix(nK, nMat), fP = new Matrix(nK, nMat); Handle <ZeroInflationTermStructure> zts = zii_.link.zeroInflationTermStructure(); Handle <YieldTermStructure> yts = this.nominalTermStructure(); Utils.QL_REQUIRE(!zts.empty(), () => "Zts is empty!!!"); Utils.QL_REQUIRE(!yts.empty(), () => "Yts is empty!!!"); for (int i = 0; i < nfK; i++) { allStrikes_.Add(fStrikes_[i]); for (int j = 0; j < nMat; j++) { Period mat = cfMaturities_[j]; double df = yts.link.discount(cpiOptionDateFromTenor(mat)); double atm_quote = zts.link.zeroRate(cpiOptionDateFromTenor(mat)); double atm = Math.Pow(1.0 + atm_quote, mat.length()); double S = atm * df; double K_quote = fStrikes_[i] / 100.0; double K = Math.Pow(1.0 + K_quote, mat.length()); cP[i, j] = fPrice_[i, j] + S - K * df; fP[i, j] = fPrice_[i, j]; } } for (int i = 0; i < ncK; i++) { allStrikes_.Add(cStrikes_[i]); for (int j = 0; j < nMat; j++) { Period mat = cfMaturities_[j]; double df = yts.link.discount(cpiOptionDateFromTenor(mat)); double atm_quote = zts.link.zeroRate(cpiOptionDateFromTenor(mat)); double atm = Math.Pow(1.0 + atm_quote, mat.length()); double S = atm * df; double K_quote = cStrikes_[i] / 100.0; double K = Math.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_ = new List <double>(); for (int i = 0; i < cfMaturities_.Count; i++) { cfMaturityTimes_.Add(timeFromReference(cpiOptionDateFromTenor(cfMaturities_[i]))); } capPrice_ = interpolator2d_.interpolate(cfMaturityTimes_, cfMaturityTimes_.Count, allStrikes_, allStrikes_.Count, cPriceB_); capPrice_.enableExtrapolation(); floorPrice_ = interpolator2d_.interpolate(cfMaturityTimes_, cfMaturityTimes_.Count, allStrikes_, allStrikes_.Count, fPriceB_); floorPrice_.enableExtrapolation(); }
protected void checkSwapTenor(Period swapTenor, bool extrapolate) { Utils.QL_REQUIRE(swapTenor.length() > 0, () => "non-positive swap tenor (" + swapTenor + ") given"); Utils.QL_REQUIRE(extrapolate || allowsExtrapolation() || swapTenor <= maxSwapTenor(), () => "swap tenor (" + swapTenor + ") is past max tenor (" + maxSwapTenor() + ")"); }
KeyValuePair<int, int> daysMinMax(Period p) { switch (p.units()) { case TimeUnit.Days: return new KeyValuePair<int, int>(p.length(), p.length()); case TimeUnit.Weeks: return new KeyValuePair<int, int>(7*p.length(), 7*p.length()); case TimeUnit.Months: return new KeyValuePair<int, int>(28*p.length(), 31*p.length()); case TimeUnit.Years: return new KeyValuePair<int, int>(365 * p.length(), 366 * p.length()); default: throw new ApplicationException("unknown time unit (" + p.units() + ")"); } }
protected void checkSwapTenor(Period swapTenor, bool extrapolate) { Utils.QL_REQUIRE(swapTenor.length() > 0, "non-positive swap tenor (" + swapTenor + ") given"); Utils.QL_REQUIRE(extrapolate || allowsExtrapolation() || swapTenor <= maxSwapTenor(), "swap tenor (" + swapTenor + ") is past max tenor (" + maxSwapTenor() + ")"); }
public Schedule(Date effectiveDate__, Date terminationDate__, Period tenor__, Calendar calendar__, BusinessDayConvention convention__, BusinessDayConvention terminationDateConvention__, DateGeneration.Rule rule__, bool endOfMonth__, Date firstDate__, Date nextToLastDate__) { // first save the properties fullInterface_ = true; tenor_ = tenor__; calendar_ = calendar__; convention_ = convention__; terminationDateConvention_ = terminationDateConvention__; rule_ = rule__; endOfMonth_ = endOfMonth__; firstDate_ = firstDate__; nextToLastDate_ = nextToLastDate__; // sanity checks if (effectiveDate__ == null) { throw new ArgumentException("Null effective date"); } if (terminationDate__ == null) { throw new ArgumentException("Null termination date"); } if (effectiveDate__ >= terminationDate__) { throw new ArgumentException("Effective date (" + effectiveDate__ + ") is later than or equal to termination date (" + terminationDate__ + ")"); } if (tenor_.length() == 0) { rule_ = DateGeneration.Rule.Zero; } else if (tenor_.length() < 0) { throw new ArgumentException("Non positive tenor (" + tenor_ + ") is not allowed"); } if (firstDate_ != null) { switch (rule_) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: if (!(firstDate_ > effectiveDate__ && firstDate_ < terminationDate__)) { throw new ArgumentException("First date (" + firstDate_ + ") is out of range [effective date (" + effectiveDate__ + "), termination date (" + terminationDate__ + ")]"); } // we should ensure that the above condition is still verified after adjustment break; case DateGeneration.Rule.ThirdWednesday: if (!IMM.isIMMdate(firstDate_, false)) { throw new ArgumentException("first date (" + firstDate_ + ") is not an IMM date"); } break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: throw new ArgumentException("First date is incompatible with " + rule_ + " date generation rule"); default: throw new ArgumentException("Unknown DateGeneration rule: " + rule_); } } if (nextToLastDate_ != null) { switch (rule_) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: if (!(nextToLastDate_ > effectiveDate__ && nextToLastDate_ < terminationDate__)) { throw new ArgumentException("Next to last date (" + nextToLastDate_ + ") out of range [effective date (" + effectiveDate__ + "), termination date (" + terminationDate__ + ")]"); } // we should ensure that the above condition is still verified after adjustment break; case DateGeneration.Rule.ThirdWednesday: if (!IMM.isIMMdate(firstDate_, false)) { throw new ArgumentException("first date (" + firstDate_ + ") is not an IMM date"); } break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: throw new ArgumentException("next to last is incompatible with " + rule_ + " date generation rule"); default: throw new ArgumentException("Unknown DateGeneration rule: " + rule_); } } // calendar needed for endOfMonth adjustment Calendar nullCalendar = new NullCalendar(); int periods = 1; Date seed = new Date(), exitDate; switch (rule_) { case DateGeneration.Rule.Zero: tenor_ = new Period(0, TimeUnit.Years); originalDates_.Add(effectiveDate__); originalDates_.Add(terminationDate__); isRegular_.Add(true); break; case DateGeneration.Rule.Backward: originalDates_.Add(terminationDate__); seed = terminationDate__; if (nextToLastDate_ != null) { originalDates_.Insert(0, nextToLastDate_); Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_); isRegular_.Insert(0, temp == nextToLastDate_); seed = nextToLastDate_; } exitDate = effectiveDate__; if (firstDate_ != null) { exitDate = firstDate_; } while (true) { Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_); if (temp < exitDate) { if (firstDate_ != null && (calendar_.adjust(originalDates_.First(), convention_) != calendar_.adjust(firstDate_, convention_))) { originalDates_.Insert(0, firstDate_); isRegular_.Insert(0, false); } break; } else { originalDates_.Insert(0, temp); isRegular_.Insert(0, true); ++periods; } } if (endOfMonth_ && calendar_.isEndOfMonth(seed)) { convention_ = BusinessDayConvention.Preceding; } if (calendar_.adjust(originalDates_[0], convention_) != calendar_.adjust(effectiveDate__, convention_)) { originalDates_.Insert(0, effectiveDate__); isRegular_.Insert(0, false); } break; case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.ThirdWednesday: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: if (endOfMonth_) { throw new ArgumentException("endOfMonth convention is incompatible with " + rule_ + " date generation rule"); } goto case DateGeneration.Rule.Forward; // fall through case DateGeneration.Rule.Forward: if (rule_ == DateGeneration.Rule.CDS) { originalDates_.Add(previousTwentieth(effectiveDate__, DateGeneration.Rule.CDS)); } else { originalDates_.Add(effectiveDate__); } seed = effectiveDate__; if (firstDate_ != null) { originalDates_.Add(firstDate_); Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_); isRegular_.Add(temp == firstDate_); seed = firstDate_; } else if (rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { Date next20th = nextTwentieth(effectiveDate__, rule_); if (rule_ == DateGeneration.Rule.OldCDS) { // distance rule inforced in natural days long stubDays = 30; if (next20th - effectiveDate__ < stubDays) { // +1 will skip this one and get the next next20th = nextTwentieth(next20th + 1, rule_); } } if (next20th != effectiveDate__) { originalDates_.Add(next20th); isRegular_.Add(false); seed = next20th; } } exitDate = terminationDate__; if (nextToLastDate_ != null) { exitDate = nextToLastDate_; } while (true) { Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_); if (temp > exitDate) { if (nextToLastDate_ != null && (calendar_.adjust(originalDates_.Last(), convention_) != calendar_.adjust(nextToLastDate_, convention_))) { originalDates_.Add(nextToLastDate_); isRegular_.Add(false); } break; } else { originalDates_.Add(temp); isRegular_.Add(true); ++periods; } } if (endOfMonth_ && calendar_.isEndOfMonth(seed)) { convention_ = BusinessDayConvention.Preceding; } if (calendar_.adjust(originalDates_.Last(), terminationDateConvention_) != calendar_.adjust(terminationDate__, terminationDateConvention_)) { if (rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { originalDates_.Add(nextTwentieth(terminationDate__, rule_)); isRegular_.Add(true); } else { originalDates_.Add(terminationDate__); isRegular_.Add(false); } } break; default: throw new ArgumentException("Unknown DateGeneration rule: " + rule_); } // adjustments to holidays, etc. if (rule_ == DateGeneration.Rule.ThirdWednesday) { for (int i = 1; i < originalDates_.Count; ++i) { originalDates_[i] = Date.nthWeekday(3, DayOfWeek.Wednesday, originalDates_[i].Month, originalDates_[i].Year); } } if (endOfMonth && calendar_.isEndOfMonth(seed)) { // adjust to end of month if (convention_ == BusinessDayConvention.Unadjusted) { for (int i = 0; i < originalDates_.Count; ++i) { originalDates_[i] = Date.endOfMonth(originalDates_[i]); } } else { for (int i = 0; i < originalDates_.Count; ++i) { originalDates_[i] = calendar_.endOfMonth(originalDates_[i]); } } if (terminationDateConvention_ == BusinessDayConvention.Unadjusted) { originalDates_[originalDates_.Count - 1] = Date.endOfMonth(originalDates_.Last()); } else { originalDates_[originalDates_.Count - 1] = calendar_.endOfMonth(originalDates_.Last()); } } else { // first date not adjusted for CDS schedules if (rule_ != DateGeneration.Rule.OldCDS) { originalDates_[0] = calendar_.adjust(originalDates_[0], convention_); } for (int i = 1; i < originalDates_.Count; ++i) { originalDates_[i] = calendar_.adjust(originalDates_[i], convention_); } foreach (Date d in originalDates_) { adjustedDates_.Add(d); } // 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_ != BusinessDayConvention.Unadjusted || rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { adjustedDates_[adjustedDates_.Count - 1] = calendar_.adjust(originalDates_.Last(), terminationDateConvention_); } } }
public override void initialize(FloatingRateCoupon coupon) { coupon_ = coupon as CmsCoupon; Utils.QL_REQUIRE( coupon_ != null, () => "CMS coupon needed" ); gearing_ = coupon_.gearing(); spread_ = coupon_.spread(); fixingDate_ = coupon_.fixingDate(); paymentDate_ = coupon_.date(); SwapIndex swapIndex = coupon_.swapIndex(); rateCurve_ = swapIndex.forwardingTermStructure().link; Date today = Settings.evaluationDate(); if (paymentDate_ > today) discount_ = rateCurve_.discount(paymentDate_); else discount_ = 1.0; spreadLegValue_ = spread_ * coupon_.accrualPeriod() * discount_; if (fixingDate_ > today) { swapTenor_ = swapIndex.tenor(); VanillaSwap swap = swapIndex.underlyingSwap(fixingDate_); swapRateValue_ = swap.fairRate(); double bp = 1.0e-4; annuity_ = (swap.floatingLegBPS() / bp); int q = (int)swapIndex.fixedLegTenor().frequency(); Schedule schedule = swap.fixedSchedule(); DayCounter dc = swapIndex.dayCounter(); //DayCounter dc = coupon.dayCounter(); double startTime = dc.yearFraction(rateCurve_.referenceDate(), swap.startDate()); double swapFirstPaymentTime = dc.yearFraction(rateCurve_.referenceDate(), schedule.date(1)); double paymentTime = dc.yearFraction(rateCurve_.referenceDate(), paymentDate_); double delta = (paymentTime - startTime) / (swapFirstPaymentTime - startTime); switch (modelOfYieldCurve_) { case GFunctionFactory.YieldCurveModel.Standard: gFunction_ = GFunctionFactory.newGFunctionStandard(q, delta, swapTenor_.length()); break; case GFunctionFactory.YieldCurveModel.ExactYield: gFunction_ = GFunctionFactory.newGFunctionExactYield(coupon_); break; case GFunctionFactory.YieldCurveModel.ParallelShifts: { Handle<Quote> nullMeanReversionQuote = new Handle<Quote>(new SimpleQuote(0.0)); gFunction_ = GFunctionFactory.newGFunctionWithShifts(coupon_, nullMeanReversionQuote); } break; case GFunctionFactory.YieldCurveModel.NonParallelShifts: gFunction_ = GFunctionFactory.newGFunctionWithShifts(coupon_, meanReversion_); break; default: throw new ApplicationException("unknown/illegal gFunction type"); } vanillaOptionPricer_ = new BlackVanillaOptionPricer(swapRateValue_, fixingDate_, swapTenor_, swaptionVolatility().link); } }
/// <summary> /// Advances the given date as specified by the given period and /// returns the result. /// </summary> /// <remarks>The input date is not modified.</remarks> public Date advance(Date d, Period p, BusinessDayConvention c = BusinessDayConvention.Following, bool endOfMonth = false) { return(advance(d, p.length(), p.units(), c, endOfMonth)); }
public Date advance(Date d, Period p, BusinessDayConvention c, bool endOfMonth) { return advance(d, p.length(), p.units(), c, endOfMonth); }
public VanillaSwap value() { Date startDate; if (effectiveDate_ != null) { startDate = effectiveDate_; } else { //int fixingDays = iborIndex_.fixingDays(); Date refDate = Settings.evaluationDate(); // if the evaluation date is not a business day // then move to the next business day refDate = floatCalendar_.adjust(refDate); Date spotDate = floatCalendar_.advance(refDate, new Period(settlementDays_, TimeUnit.Days)); startDate = spotDate + forwardStart_; if (forwardStart_.length() < 0) { startDate = floatCalendar_.adjust(startDate, BusinessDayConvention.Preceding); } else { startDate = floatCalendar_.adjust(startDate, BusinessDayConvention.Following); } } Date endDate = terminationDate_; if (endDate == null) { if (floatEndOfMonth_) { endDate = floatCalendar_.advance(startDate, swapTenor_, BusinessDayConvention.ModifiedFollowing, floatEndOfMonth_); } else { endDate = startDate + swapTenor_; } } Currency curr = iborIndex_.currency(); Period fixedTenor = null; if (fixedTenor_ != null) { fixedTenor = fixedTenor_; } else { if ((curr == new EURCurrency()) || (curr == new USDCurrency()) || (curr == new CHFCurrency()) || (curr == new SEKCurrency()) || (curr == new GBPCurrency() && swapTenor_ <= new Period(1, TimeUnit.Years))) { fixedTenor = new Period(1, TimeUnit.Years); } else if ((curr == new GBPCurrency() && swapTenor_ > new Period(1, TimeUnit.Years) || (curr == new JPYCurrency()) || (curr == new AUDCurrency() && swapTenor_ >= new Period(4, TimeUnit.Years)))) { fixedTenor = new Period(6, TimeUnit.Months); } else if ((curr == new HKDCurrency() || (curr == new AUDCurrency() && swapTenor_ < new Period(4, TimeUnit.Years)))) { fixedTenor = new Period(3, TimeUnit.Months); } else { Utils.QL_FAIL("unknown fixed leg default tenor for " + curr); } } Schedule fixedSchedule = new Schedule(startDate, endDate, fixedTenor, fixedCalendar_, fixedConvention_, fixedTerminationDateConvention_, fixedRule_, fixedEndOfMonth_, fixedFirstDate_, fixedNextToLastDate_); Schedule floatSchedule = new Schedule(startDate, endDate, floatTenor_, floatCalendar_, floatConvention_, floatTerminationDateConvention_, floatRule_, floatEndOfMonth_, floatFirstDate_, floatNextToLastDate_); DayCounter fixedDayCount = null; if (fixedDayCount_ != null) { fixedDayCount = fixedDayCount_; } else { if (curr == new USDCurrency()) { fixedDayCount = new Actual360(); } else if (curr == new EURCurrency() || curr == new CHFCurrency() || curr == new SEKCurrency()) { fixedDayCount = new Thirty360(Thirty360.Thirty360Convention.BondBasis); } else if (curr == new GBPCurrency() || curr == new JPYCurrency() || curr == new AUDCurrency() || curr == new HKDCurrency()) { fixedDayCount = new Actual365Fixed(); } else { Utils.QL_FAIL("unknown fixed leg day counter for " + curr); } } double?usedFixedRate = fixedRate_; if (fixedRate_ == null) { VanillaSwap temp = new VanillaSwap(type_, nominal_, fixedSchedule, 0.0, fixedDayCount, floatSchedule, iborIndex_, floatSpread_, floatDayCount_); if (engine_ == null) { Handle <YieldTermStructure> disc = iborIndex_.forwardingTermStructure(); Utils.QL_REQUIRE(!disc.empty(), () => "null term structure set to this instance of " + iborIndex_.name()); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); temp.setPricingEngine(engine); } else { temp.setPricingEngine(engine_); } usedFixedRate = temp.fairRate(); } VanillaSwap swap = new VanillaSwap(type_, nominal_, fixedSchedule, usedFixedRate.Value, fixedDayCount, floatSchedule, iborIndex_, floatSpread_, floatDayCount_); if (engine_ == null) { Handle <YieldTermStructure> disc = iborIndex_.forwardingTermStructure(); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); swap.setPricingEngine(engine); } else { swap.setPricingEngine(engine_); } return(swap); }
/// <summary> /// rule based constructor /// </summary> /// <param name="effectiveDate"></param> /// <param name="terminationDate"></param> /// <param name="tenor"></param> /// <param name="calendar"></param> /// <param name="convention"></param> /// <param name="terminationDateConvention"></param> /// <param name="rule"></param> /// <param name="endOfMonth"></param> /// <param name="firstDate"></param> /// <param name="nextToLastDate"></param> public Schedule(Date effectiveDate, Date terminationDate, Period tenor, Calendar calendar, BusinessDayConvention convention, BusinessDayConvention terminationDateConvention, DateGeneration.Rule rule, bool endOfMonth, Date firstDate = null, Date nextToLastDate = null) { calendar_ = calendar ?? new NullCalendar(); firstDate_ = firstDate == effectiveDate ? null : firstDate; nextToLastDate_ = nextToLastDate == terminationDate ? null : nextToLastDate; tenor_ = tenor; convention_ = convention; terminationDateConvention_ = terminationDateConvention; rule_ = rule; endOfMonth_ = allowsEndOfMonth(tenor) && endOfMonth; // sanity checks Utils.QL_REQUIRE(terminationDate != null, () => "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 == null && firstDate == null && rule == DateGeneration.Rule.Backward) { Date evalDate = Settings.evaluationDate(); Utils.QL_REQUIRE(evalDate < terminationDate, () => "null effective date", QLNetExceptionEnum.NullEffectiveDate); int y; if (nextToLastDate != null) { y = (nextToLastDate - evalDate) / 366 + 1; effectiveDate = nextToLastDate - new Period(y, TimeUnit.Years); } else { y = (terminationDate - evalDate) / 366 + 1; effectiveDate = terminationDate - new Period(y, TimeUnit.Years); } // More accurate , is the previous coupon date if (effectiveDate > evalDate) { effectiveDate = effectiveDate - new Period(tenor_.length(), TimeUnit.Months); } else if (effectiveDate + new Period(tenor_.length(), TimeUnit.Months) < evalDate) { effectiveDate = effectiveDate + new Period(tenor_.length(), TimeUnit.Months); } } else { Utils.QL_REQUIRE(effectiveDate != null, () => "null effective date", QLNetExceptionEnum.NullEffectiveDate); } Utils.QL_REQUIRE(effectiveDate < terminationDate, () => "effective date (" + effectiveDate + ") later than or equal to termination date (" + terminationDate + ")" ); if (tenor_.length() == 0) { rule_ = DateGeneration.Rule.Zero; } else { Utils.QL_REQUIRE(tenor.length() > 0, () => "non positive tenor (" + tenor + ") not allowed"); } if (firstDate_ != null) { switch (rule_.Value) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: Utils.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.Rule.ThirdWednesday: Utils.QL_REQUIRE(IMM.isIMMdate(firstDate_, false), () => "first date (" + firstDate_ + ") is not an IMM date"); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: case DateGeneration.Rule.CDS2015: Utils.QL_FAIL("first date incompatible with " + rule_.Value + " date generation rule"); break; default: Utils.QL_FAIL("unknown rule (" + rule_.Value + ")"); break; } } if (nextToLastDate_ != null) { switch (rule_.Value) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: Utils.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.Rule.ThirdWednesday: Utils.QL_REQUIRE(IMM.isIMMdate(nextToLastDate_, false), () => "next-to-last date (" + nextToLastDate_ + ") is not an IMM date"); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: case DateGeneration.Rule.CDS2015: Utils.QL_FAIL("next to last date incompatible with " + rule_.Value + " date generation rule"); break; default: Utils.QL_FAIL("unknown rule (" + rule_.Value + ")"); break; } } // calendar needed for endOfMonth adjustment Calendar nullCalendar = new NullCalendar(); int periods = 1; Date seed = new Date(), exitDate = new Date(); switch (rule_.Value) { case DateGeneration.Rule.Zero: tenor_ = new Period(0, TimeUnit.Years); dates_.Add(effectiveDate); dates_.Add(terminationDate); isRegular_.Add(true); break; case DateGeneration.Rule.Backward: dates_.Add(terminationDate); seed = terminationDate; if (nextToLastDate_ != null) { dates_.Insert(0, nextToLastDate_); Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_.Value); if (temp != nextToLastDate_) { isRegular_.Insert(0, false); } else { isRegular_.Insert(0, true); } seed = nextToLastDate_; } exitDate = effectiveDate; if (firstDate_ != null) { exitDate = firstDate_; } while (true) { Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_.Value); if (temp < exitDate) { if (firstDate_ != null && (calendar_.adjust(dates_.First(), convention_) != calendar_.adjust(firstDate_, convention_))) { dates_.Insert(0, firstDate_); isRegular_.Insert(0, false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.First(), convention_) != calendar_.adjust(temp, convention_)) { dates_.Insert(0, temp); isRegular_.Insert(0, true); } ++periods; } } if (calendar_.adjust(dates_.First(), convention) != calendar_.adjust(effectiveDate, convention)) { dates_.Insert(0, effectiveDate); isRegular_.Insert(0, false); } break; case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.ThirdWednesday: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: case DateGeneration.Rule.CDS2015: Utils.QL_REQUIRE(!endOfMonth, () => "endOfMonth convention incompatible with " + rule_.Value + " date generation rule"); goto case DateGeneration.Rule.Forward; // fall through case DateGeneration.Rule.Forward: if (rule_.Value == DateGeneration.Rule.CDS || rule_.Value == DateGeneration.Rule.CDS2015) { dates_.Add(previousTwentieth(effectiveDate, rule_.Value)); } else { dates_.Add(effectiveDate); } seed = dates_.Last(); if (firstDate_ != null) { dates_.Add(firstDate_); Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_.Value); if (temp != firstDate_) { isRegular_.Add(false); } else { isRegular_.Add(true); } seed = firstDate_; } else if (rule_.Value == DateGeneration.Rule.Twentieth || rule_.Value == DateGeneration.Rule.TwentiethIMM || rule_.Value == DateGeneration.Rule.OldCDS || rule_.Value == DateGeneration.Rule.CDS || rule_.Value == DateGeneration.Rule.CDS2015) { Date next20th = nextTwentieth(effectiveDate, rule_.Value); if (rule_ == DateGeneration.Rule.OldCDS) { // distance rule inforced in natural days long stubDays = 30; if (next20th - effectiveDate < stubDays) { // +1 will skip this one and get the next next20th = nextTwentieth(next20th + 1, rule_.Value); } } if (next20th != effectiveDate) { dates_.Add(next20th); isRegular_.Add(false); seed = next20th; } } exitDate = terminationDate; if (nextToLastDate_ != null) { exitDate = nextToLastDate_; } if (rule_ == DateGeneration.Rule.CDS2015 && nextTwentieth(terminationDate, rule_.Value) == terminationDate && terminationDate.month() % 2 == 1) { exitDate = nextTwentieth(terminationDate + 1, rule_.Value); } while (true) { Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_.Value); if (temp > exitDate) { if (nextToLastDate_ != null && (calendar_.adjust(dates_.Last(), convention_) != calendar_.adjust(nextToLastDate_, convention_))) { dates_.Add(nextToLastDate_); isRegular_.Add(false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.Last(), convention_) != calendar_.adjust(temp, convention_)) { dates_.Add(temp); isRegular_.Add(true); } ++periods; } } if (calendar_.adjust(dates_.Last(), terminationDateConvention_.Value) != calendar_.adjust(terminationDate, terminationDateConvention_.Value)) { if (rule_.Value == DateGeneration.Rule.Twentieth || rule_.Value == DateGeneration.Rule.TwentiethIMM || rule_.Value == DateGeneration.Rule.OldCDS || rule_.Value == DateGeneration.Rule.CDS) { dates_.Add(nextTwentieth(terminationDate, rule_.Value)); isRegular_.Add(true); } else if (rule_ == DateGeneration.Rule.CDS2015) { Date tentativeTerminationDate = nextTwentieth(terminationDate, rule_.Value); if (tentativeTerminationDate.month() % 2 == 0) { dates_.Add(tentativeTerminationDate); isRegular_.Add(true); } } else { dates_.Add(terminationDate); isRegular_.Add(false); } } break; default: Utils.QL_FAIL("unknown rule (" + rule_.Value + ")"); break; } // adjustments if (rule_ == DateGeneration.Rule.ThirdWednesday) { for (int i = 1; i < dates_.Count - 1; ++i) { dates_[i] = Date.nthWeekday(3, DayOfWeek.Wednesday, dates_[i].Month, dates_[i].Year); } } if (endOfMonth && calendar_.isEndOfMonth(seed)) { // adjust to end of month if (convention_ == BusinessDayConvention.Unadjusted) { for (int i = 1; i < dates_.Count - 1; ++i) { dates_[i] = Date.endOfMonth(dates_[i]); } } else { for (int i = 1; i < dates_.Count - 1; ++i) { dates_[i] = calendar_.endOfMonth(dates_[i]); } } if (terminationDateConvention_ != BusinessDayConvention.Unadjusted) { dates_[0] = calendar_.endOfMonth(dates_.First()); dates_[dates_.Count - 1] = calendar_.endOfMonth(dates_.Last()); } else { // the termination date is the first if going backwards, // the last otherwise. if (rule_ == DateGeneration.Rule.Backward) { dates_[dates_.Count - 1] = Date.endOfMonth(dates_.Last()); } else { dates_[0] = Date.endOfMonth(dates_.First()); } } } else { // first date not adjusted for CDS schedules if (rule_ != DateGeneration.Rule.OldCDS) { dates_[0] = calendar_.adjust(dates_[0], convention_); } for (int i = 1; i < dates_.Count - 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_.Value != BusinessDayConvention.Unadjusted && rule_.Value != DateGeneration.Rule.CDS && rule_.Value != DateGeneration.Rule.CDS2015) { dates_[dates_.Count - 1] = calendar_.adjust(dates_.Last(), terminationDateConvention_.Value); } } // 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_.Count >= 2 && dates_[dates_.Count - 2] >= dates_.Last()) { isRegular_[isRegular_.Count - 2] = (dates_[dates_.Count - 2] == dates_.Last()); dates_[dates_.Count - 2] = dates_.Last(); dates_.RemoveAt(dates_.Count - 1); isRegular_.RemoveAt(isRegular_.Count - 1); } if (dates_.Count >= 2 && dates_[1] <= dates_.First()) { isRegular_[1] = (dates_[1] == dates_.First()); dates_[1] = dates_.First(); dates_.RemoveAt(0); isRegular_.RemoveAt(0); } Utils.QL_REQUIRE(dates_.Count > 1, () => "degenerate single date (" + dates_[0] + ") schedule" + "\n seed date: " + seed + "\n exit date: " + exitDate + "\n effective date: " + effectiveDate + "\n first date: " + firstDate + "\n next to last date: " + nextToLastDate + "\n termination date: " + terminationDate + "\n generation rule: " + rule_.Value + "\n end of month: " + endOfMonth_.Value); }
public Schedule(Date effectiveDate, Date terminationDate, Period tenor, Calendar calendar, BusinessDayConvention convention, BusinessDayConvention terminationDateConvention, DateGeneration.Rule rule, bool endOfMonth, Date firstDate, Date nextToLastDate) { // first save the properties fullInterface_ = true; tenor_ = tenor; calendar_ = calendar; convention_ = convention; terminationDateConvention_ = terminationDateConvention; rule_ = rule; endOfMonth_ = endOfMonth; if (firstDate == effectiveDate) { firstDate_ = null; } else { firstDate_ = firstDate; } if (nextToLastDate == terminationDate) { nextToLastDate_ = null; } else { nextToLastDate_ = nextToLastDate; } // sanity checks Utils.QL_REQUIRE(terminationDate != null, "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 == null && firstDate == null && rule == DateGeneration.Rule.Backward) { Date evalDate = Settings.evaluationDate(); Utils.QL_REQUIRE(evalDate < terminationDate, "null effective date"); int y; if (nextToLastDate != null) { y = (nextToLastDate - evalDate) / 366 + 1; effectiveDate = nextToLastDate - new Period(y, TimeUnit.Years); } else { y = (terminationDate - evalDate) / 366 + 1; effectiveDate = terminationDate - new Period(y, TimeUnit.Years); } } else { Utils.QL_REQUIRE(effectiveDate != null, "null effective date"); } if (tenor_.length() == 0) { rule_ = DateGeneration.Rule.Zero; } else { Utils.QL_REQUIRE(tenor.length() > 0, "non positive tenor (" + tenor + ") not allowed"); } if (firstDate_ != null) { switch (rule_) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: Utils.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.Rule.ThirdWednesday: Utils.QL_REQUIRE(IMM.isIMMdate(firstDate_, false), "first date (" + firstDate_ + ") is not an IMM date"); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: Utils.QL_FAIL("first date incompatible with " + rule_ + " date generation rule"); break; default: Utils.QL_FAIL("unknown rule (" + rule_ + ")"); break; } } if (nextToLastDate_ != null) { switch (rule_) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: Utils.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.Rule.ThirdWednesday: Utils.QL_REQUIRE(IMM.isIMMdate(nextToLastDate_, false), "next-to-last date (" + nextToLastDate_ + ") is not an IMM date"); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: Utils.QL_FAIL("next to last date incompatible with " + rule_ + " date generation rule"); break; default: Utils.QL_FAIL("unknown rule (" + rule_ + ")"); break; } } // calendar needed for endOfMonth adjustment Calendar nullCalendar = new NullCalendar(); int periods = 1; Date seed = new Date(), exitDate; switch (rule_) { case DateGeneration.Rule.Zero: tenor_ = new Period(0, TimeUnit.Years); dates_.Add(effectiveDate); dates_.Add(terminationDate); isRegular_.Add(true); break; case DateGeneration.Rule.Backward: dates_.Add(terminationDate); seed = terminationDate; if (nextToLastDate_ != null) { dates_.Insert(0, nextToLastDate_); Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_); if (temp != nextToLastDate_) { isRegular_.Insert(0, false); } else { isRegular_.Insert(0, true); } seed = nextToLastDate_; } exitDate = effectiveDate; if (firstDate_ != null) { exitDate = firstDate_; } while (true) { Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_); if (temp < exitDate) { if (firstDate_ != null && (calendar_.adjust(dates_.First(), convention_) != calendar_.adjust(firstDate_, convention_))) { dates_.Insert(0, firstDate_); isRegular_.Insert(0, false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.First(), convention_) != calendar_.adjust(temp, convention_)) { dates_.Insert(0, temp); isRegular_.Insert(0, true); } ++periods; } } if (calendar_.adjust(dates_.First(), convention) != calendar_.adjust(effectiveDate, convention)) { dates_.Insert(0, effectiveDate); isRegular_.Insert(0, false); } break; case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.ThirdWednesday: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: Utils.QL_REQUIRE(!endOfMonth, "endOfMonth convention incompatible with " + rule_ + " date generation rule"); goto case DateGeneration.Rule.Forward; // fall through case DateGeneration.Rule.Forward: if (rule_ == DateGeneration.Rule.CDS) { dates_.Add(previousTwentieth(effectiveDate, DateGeneration.Rule.CDS)); } else { dates_.Add(effectiveDate); } seed = dates_.Last(); if (firstDate_ != null) { dates_.Add(firstDate_); Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_); if (temp != firstDate_) { isRegular_.Add(false); } else { isRegular_.Add(true); } seed = firstDate_; } else if (rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { Date next20th = nextTwentieth(effectiveDate, rule_); if (rule_ == DateGeneration.Rule.OldCDS) { // distance rule inforced in natural days long stubDays = 30; if (next20th - effectiveDate < stubDays) { // +1 will skip this one and get the next next20th = nextTwentieth(next20th + 1, rule_); } } if (next20th != effectiveDate) { dates_.Add(next20th); isRegular_.Add(false); seed = next20th; } } exitDate = terminationDate; if (nextToLastDate_ != null) { exitDate = nextToLastDate_; } while (true) { Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_); if (temp > exitDate) { if (nextToLastDate_ != null && (calendar_.adjust(dates_.Last(), convention_) != calendar_.adjust(nextToLastDate_, convention_))) { dates_.Add(nextToLastDate_); isRegular_.Add(false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.Last(), convention_) != calendar_.adjust(temp, convention_)) { dates_.Add(temp); isRegular_.Add(true); } ++periods; } } if (calendar_.adjust(dates_.Last(), terminationDateConvention_) != calendar_.adjust(terminationDate, terminationDateConvention_)) { if (rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { dates_.Add(nextTwentieth(terminationDate, rule_)); isRegular_.Add(true); } else { dates_.Add(terminationDate); isRegular_.Add(false); } } break; default: Utils.QL_FAIL("unknown rule (" + rule_ + ")"); break; } // adjustments if (rule_ == DateGeneration.Rule.ThirdWednesday) { for (int i = 1; i < dates_.Count - 1; ++i) { dates_[i] = Date.nthWeekday(3, DayOfWeek.Wednesday, dates_[i].Month, dates_[i].Year); } } if (endOfMonth && calendar_.isEndOfMonth(seed)) { // adjust to end of month if (convention_ == BusinessDayConvention.Unadjusted) { for (int i = 0; i < dates_.Count - 1; ++i) { dates_[i] = Date.endOfMonth(dates_[i]); } } else { for (int i = 0; i < dates_.Count - 1; ++i) { dates_[i] = calendar_.endOfMonth(dates_[i]); } } if (terminationDateConvention_ != BusinessDayConvention.Unadjusted) { dates_[dates_.Count - 1] = calendar_.endOfMonth(dates_.Last()); } } else { // first date not adjusted for CDS schedules if (rule_ != DateGeneration.Rule.OldCDS) { dates_[0] = calendar_.adjust(dates_[0], convention_); } for (int i = 1; i < dates_.Count - 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_ != BusinessDayConvention.Unadjusted || rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { dates_[dates_.Count - 1] = calendar_.adjust(dates_.Last(), terminationDateConvention_); } } // final safety check to remove duplicated last dates, if any // it can happen if EOM is applied to two near dates if (dates_.Count >= 2 && dates_[dates_.Count - 2] >= dates_.Last()) { isRegular_[dates_.Count() - 2] = (dates_[dates_.Count() - 2] == dates_.Last()); dates_[dates_.Count() - 2] = dates_.Last(); dates_.RemoveAt(dates_.Count - 1); isRegular_.RemoveAt(isRegular_.Count - 1); } }
protected void checkRange(Date optionDate, Period bondTenor, double k, bool extrapolate) { base.checkRange(timeFromReference(optionDate), extrapolate); Utils.QL_REQUIRE( bondTenor.length() > 0, () => "negative bond tenor (" + bondTenor + ") given"); Utils.QL_REQUIRE(extrapolate || allowsExtrapolation() || bondTenor <= maxBondTenor(), () => "bond tenor (" + bondTenor + ") is past max tenor (" + maxBondTenor() + ")"); Utils.QL_REQUIRE(extrapolate || allowsExtrapolation() || ( k >= minStrike() && k <= maxStrike() ), () => "strike (" + k + ") is outside the curve domain [" + minStrike() + "," + maxStrike()+ "]"); }
/// <summary> /// Advances the given date as specified by the given period and /// returns the result. /// </summary> /// <remarks>The input date is not modified.</remarks> public Date advance( Date d, Period p, BusinessDayConvention c = BusinessDayConvention.Following, bool endOfMonth = false) { return advance(d, p.length(), p.units(), c, endOfMonth); }
public Schedule( Date effectiveDate, Date terminationDate, Period tenor, Calendar calendar, BusinessDayConvention convention, BusinessDayConvention terminationDateConvention, DateGeneration.Rule rule, bool endOfMonth, Date firstDate = null, Date nextToLastDate = null) { // first save the properties fullInterface_ = true; tenor_ = tenor; if ( calendar == null ) calendar_ = new NullCalendar(); else calendar_ = calendar; convention_ = convention; terminationDateConvention_ = terminationDateConvention; rule_ = rule; endOfMonth_ = endOfMonth; if ( firstDate == effectiveDate ) firstDate_ = null; else firstDate_ = firstDate; if ( nextToLastDate == terminationDate ) nextToLastDate_ = null; else nextToLastDate_ = nextToLastDate; // sanity checks Utils.QL_REQUIRE( terminationDate != null, () => "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 == null && firstDate == null && rule== DateGeneration.Rule.Backward) { Date evalDate = Settings.evaluationDate(); Utils.QL_REQUIRE( evalDate < terminationDate, () => "null effective date" ); int y; if (nextToLastDate != null) { y = (nextToLastDate - evalDate)/366 + 1; effectiveDate = nextToLastDate - new Period(y,TimeUnit.Years); } else { y = (terminationDate - evalDate)/366 + 1; effectiveDate = terminationDate - new Period(y,TimeUnit.Years); } } else Utils.QL_REQUIRE( effectiveDate != null, () => "null effective date" ); if (tenor_.length() == 0) rule_ = DateGeneration.Rule.Zero; else Utils.QL_REQUIRE( tenor.length() > 0, () => "non positive tenor (" + tenor + ") not allowed" ); if (firstDate_ != null) { switch (rule_) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: Utils.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.Rule.ThirdWednesday: Utils.QL_REQUIRE( IMM.isIMMdate( firstDate_, false ), () => "first date (" + firstDate_ + ") is not an IMM date" ); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: Utils.QL_FAIL("first date incompatible with " + rule_ + " date generation rule"); break; default: Utils.QL_FAIL("unknown rule (" + rule_ + ")"); break; } } if (nextToLastDate_ != null) { switch (rule_) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: Utils.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.Rule.ThirdWednesday: Utils.QL_REQUIRE( IMM.isIMMdate( nextToLastDate_, false ), () => "next-to-last date (" + nextToLastDate_ + ") is not an IMM date"); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: Utils.QL_FAIL("next to last date incompatible with " + rule_ + " date generation rule"); break; default: Utils.QL_FAIL("unknown rule (" + rule_ + ")"); break; } } // calendar needed for endOfMonth adjustment Calendar nullCalendar = new NullCalendar(); int periods = 1; Date seed = new Date() , exitDate; switch (rule_) { case DateGeneration.Rule.Zero: tenor_ = new Period(0, TimeUnit.Years); dates_.Add(effectiveDate); dates_.Add(terminationDate); isRegular_.Add(true); break; case DateGeneration.Rule.Backward: dates_.Add(terminationDate); seed = terminationDate; if (nextToLastDate_ != null) { dates_.Insert(0, nextToLastDate_); Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_); if (temp != nextToLastDate_) isRegular_.Insert(0, false); else isRegular_.Insert(0, true); seed = nextToLastDate_; } exitDate = effectiveDate; if (firstDate_ != null) exitDate = firstDate_; while (true) { Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_); if (temp < exitDate) { if (firstDate_ != null && (calendar_.adjust(dates_.First(), convention_) != calendar_.adjust(firstDate_, convention_))) { dates_.Insert(0, firstDate_); isRegular_.Insert(0, false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.First(), convention_) != calendar_.adjust(temp, convention_)) { dates_.Insert(0, temp); isRegular_.Insert(0, true); } ++periods; } } if (calendar_.adjust(dates_.First(), convention) != calendar_.adjust(effectiveDate, convention)) { dates_.Insert(0, effectiveDate); isRegular_.Insert(0, false); } break; case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.ThirdWednesday: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: Utils.QL_REQUIRE( !endOfMonth, () => "endOfMonth convention incompatible with " + rule_ + " date generation rule" ); goto case DateGeneration.Rule.Forward; // fall through case DateGeneration.Rule.Forward: if (rule_ == DateGeneration.Rule.CDS) { dates_.Add(previousTwentieth(effectiveDate, DateGeneration.Rule.CDS)); } else { dates_.Add(effectiveDate); } seed = dates_.Last(); if (firstDate_ != null) { dates_.Add(firstDate_); Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_); if (temp != firstDate_) isRegular_.Add(false); else isRegular_.Add(true); seed = firstDate_; } else if (rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { Date next20th = nextTwentieth(effectiveDate, rule_); if (rule_ == DateGeneration.Rule.OldCDS) { // distance rule inforced in natural days long stubDays = 30; if (next20th - effectiveDate < stubDays) { // +1 will skip this one and get the next next20th = nextTwentieth(next20th + 1, rule_); } } if (next20th != effectiveDate) { dates_.Add(next20th); isRegular_.Add(false); seed = next20th; } } exitDate = terminationDate; if (nextToLastDate_ != null) exitDate = nextToLastDate_; while (true) { Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_); if (temp > exitDate) { if (nextToLastDate_ != null && (calendar_.adjust(dates_.Last(), convention_) != calendar_.adjust(nextToLastDate_, convention_))) { dates_.Add(nextToLastDate_); isRegular_.Add(false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.Last(), convention_) != calendar_.adjust(temp, convention_)) { dates_.Add(temp); isRegular_.Add(true); } ++periods; } } if (calendar_.adjust(dates_.Last(), terminationDateConvention_) != calendar_.adjust(terminationDate, terminationDateConvention_)) { if (rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { dates_.Add(nextTwentieth(terminationDate, rule_)); isRegular_.Add(true); } else { dates_.Add(terminationDate); isRegular_.Add(false); } } break; default: Utils.QL_FAIL("unknown rule (" + rule_ + ")"); break; } // adjustments if (rule_ == DateGeneration.Rule.ThirdWednesday) for (int i = 1; i < dates_.Count-1; ++i) dates_[i] = Date.nthWeekday(3, DayOfWeek.Wednesday, dates_[i].Month, dates_[i].Year); if (endOfMonth && calendar_.isEndOfMonth(seed)) { // adjust to end of month if (convention_ == BusinessDayConvention.Unadjusted) { for (int i = 0; i < dates_.Count-1; ++i) dates_[i] = Date.endOfMonth(dates_[i]); } else { for (int i = 0; i < dates_.Count-1; ++i) dates_[i] = calendar_.endOfMonth(dates_[i]); } if (terminationDateConvention_ != BusinessDayConvention.Unadjusted) dates_[dates_.Count - 1] = calendar_.endOfMonth(dates_.Last()); } else { // first date not adjusted for CDS schedules if (rule_ != DateGeneration.Rule.OldCDS) dates_[0] = calendar_.adjust(dates_[0], convention_); for (int i = 1; i < dates_.Count-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_ != BusinessDayConvention.Unadjusted || rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) dates_[dates_.Count - 1] = calendar_.adjust(dates_.Last(), terminationDateConvention_); } // final safety check to remove duplicated last dates, if any // it can happen if EOM is applied to two near dates if (dates_.Count >= 2 && dates_[dates_.Count - 2] >= dates_.Last()) { isRegular_[dates_.Count() - 2] = (dates_[dates_.Count() - 2] == dates_.Last()); dates_[dates_.Count() - 2] = dates_.Last(); dates_.RemoveAt(dates_.Count - 1); isRegular_.RemoveAt(isRegular_.Count - 1); } }
public Date advance(Date d, Period p, BusinessDayConvention c, bool endOfMonth) { return(advance(d, p.length(), p.units(), c, endOfMonth)); }
//@} //! implements the conversion between swap tenor and swap (time) length public double swapLength(Period p) { if (!(p.length()>0)) throw new ApplicationException("non-positive swap tenor (" + p + ") given"); // while using the reference date is arbitrary it is coherent between // different swaption structures defined on the same reference date. // Date start = referenceDate(); Date end = start + p; return swapLength(start, end); }
//! implements the conversion between swap tenor and swap (time) length public double swapLength(Period swapTenor) { Utils.QL_REQUIRE(swapTenor.length() > 0, "non-positive swap tenor (" + swapTenor + ") given"); switch (swapTenor.units()) { case TimeUnit.Months: return swapTenor.length() / 12.0; case TimeUnit.Years: return swapTenor.length(); default: Utils.QL_FAIL("invalid Time Unit (" + swapTenor.units() + ") for swap length"); return 0; } }
protected void checkSwapTenor(Period swapTenor, bool extrapolate) { if (!(swapTenor.length() > 0)) throw new ApplicationException("non-positive swap tenor (" + swapTenor + ") given"); if (!(extrapolate || allowsExtrapolation() || swapTenor <= maxSwapTenor())) throw new ApplicationException("swap tenor (" + swapTenor + ") is past max tenor (" + maxSwapTenor() + ")"); }
public Schedule(Date effectiveDate__, Date terminationDate__, Period tenor__, Calendar calendar__, BusinessDayConvention convention__, BusinessDayConvention terminationDateConvention__, DateGeneration.Rule rule__, bool endOfMonth__, Date firstDate__, Date nextToLastDate__) { // first save the properties fullInterface_ = true; tenor_ = tenor__; calendar_ = calendar__; convention_ = convention__; terminationDateConvention_ = terminationDateConvention__; rule_ = rule__; endOfMonth_ = endOfMonth__; firstDate_ = firstDate__; nextToLastDate_ = nextToLastDate__; // sanity checks if (effectiveDate__ == null) throw new ArgumentException("Null effective date"); if (terminationDate__ == null) throw new ArgumentException("Null termination date"); if (effectiveDate__ >= terminationDate__) throw new ArgumentException("Effective date (" + effectiveDate__ + ") is later than or equal to termination date (" + terminationDate__ + ")"); if (tenor_.length() == 0) rule_ = DateGeneration.Rule.Zero; else if (tenor_.length() < 0) throw new ArgumentException("Non positive tenor (" + tenor_ + ") is not allowed"); if (firstDate_ != null) { switch (rule_) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: if (!(firstDate_ > effectiveDate__ && firstDate_ < terminationDate__)) throw new ArgumentException("First date (" + firstDate_ + ") is out of range [effective date (" + effectiveDate__ + "), termination date (" + terminationDate__ + ")]"); // we should ensure that the above condition is still verified after adjustment break; case DateGeneration.Rule.ThirdWednesday: if (!IMM.isIMMdate(firstDate_, false)) throw new ArgumentException("first date (" + firstDate_ + ") is not an IMM date"); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: throw new ArgumentException("First date is incompatible with " + rule_ + " date generation rule"); default: throw new ArgumentException("Unknown DateGeneration rule: " + rule_); } } if (nextToLastDate_ != null) { switch (rule_) { case DateGeneration.Rule.Backward: case DateGeneration.Rule.Forward: if (!(nextToLastDate_ > effectiveDate__ && nextToLastDate_ < terminationDate__)) throw new ArgumentException("Next to last date (" + nextToLastDate_ + ") out of range [effective date (" + effectiveDate__ + "), termination date (" + terminationDate__ + ")]"); // we should ensure that the above condition is still verified after adjustment break; case DateGeneration.Rule.ThirdWednesday: if (!IMM.isIMMdate(firstDate_, false)) throw new ArgumentException("first date (" + firstDate_ + ") is not an IMM date"); break; case DateGeneration.Rule.Zero: case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: throw new ArgumentException("next to last is incompatible with " + rule_ + " date generation rule"); default: throw new ArgumentException("Unknown DateGeneration rule: " + rule_); } } // calendar needed for endOfMonth adjustment Calendar nullCalendar = new NullCalendar(); int periods = 1; Date seed = new Date(), exitDate; switch (rule_) { case DateGeneration.Rule.Zero: tenor_ = new Period(0, TimeUnit.Years); originalDates_.Add(effectiveDate__); originalDates_.Add(terminationDate__); isRegular_.Add(true); break; case DateGeneration.Rule.Backward: originalDates_.Add(terminationDate__); seed = terminationDate__; if (nextToLastDate_ != null) { originalDates_.Insert(0, nextToLastDate_); Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_); isRegular_.Insert(0, temp == nextToLastDate_); seed = nextToLastDate_; } exitDate = effectiveDate__; if (firstDate_ != null) exitDate = firstDate_; while (true) { Date temp = nullCalendar.advance(seed, -periods * tenor_, convention_, endOfMonth_); if (temp < exitDate) { if (firstDate_ != null && (calendar_.adjust(originalDates_.First(), convention_) != calendar_.adjust(firstDate_, convention_))) { originalDates_.Insert(0, firstDate_); isRegular_.Insert(0, false); } break; } else { originalDates_.Insert(0, temp); isRegular_.Insert(0, true); ++periods; } } if (endOfMonth_ && calendar_.isEndOfMonth(seed)) convention_ = BusinessDayConvention.Preceding; if (calendar_.adjust(originalDates_[0], convention_) != calendar_.adjust(effectiveDate__, convention_)) { originalDates_.Insert(0, effectiveDate__); isRegular_.Insert(0, false); } break; case DateGeneration.Rule.Twentieth: case DateGeneration.Rule.TwentiethIMM: case DateGeneration.Rule.ThirdWednesday: case DateGeneration.Rule.OldCDS: case DateGeneration.Rule.CDS: if (endOfMonth_) throw new ArgumentException("endOfMonth convention is incompatible with " + rule_ + " date generation rule"); goto case DateGeneration.Rule.Forward; // fall through case DateGeneration.Rule.Forward: if (rule_ == DateGeneration.Rule.CDS) { originalDates_.Add(previousTwentieth(effectiveDate__,DateGeneration.Rule.CDS)); } else { originalDates_.Add(effectiveDate__); } seed = effectiveDate__; if (firstDate_ != null) { originalDates_.Add(firstDate_); Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_); isRegular_.Add(temp == firstDate_); seed = firstDate_; } else if (rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) { Date next20th = nextTwentieth(effectiveDate__, rule_); if (rule_ == DateGeneration.Rule.OldCDS) { // distance rule inforced in natural days long stubDays = 30; if (next20th - effectiveDate__ < stubDays) { // +1 will skip this one and get the next next20th = nextTwentieth(next20th + 1, rule_); } } if (next20th != effectiveDate__) { originalDates_.Add(next20th); isRegular_.Add(false); seed = next20th; } } exitDate = terminationDate__; if (nextToLastDate_ != null) exitDate = nextToLastDate_; while (true) { Date temp = nullCalendar.advance(seed, periods * tenor_, convention_, endOfMonth_); if (temp > exitDate) { if (nextToLastDate_ != null && (calendar_.adjust(originalDates_.Last(), convention_) != calendar_.adjust(nextToLastDate_, convention_))) { originalDates_.Add(nextToLastDate_); isRegular_.Add(false); } break; } else { originalDates_.Add(temp); isRegular_.Add(true); ++periods; } } if (endOfMonth_ && calendar_.isEndOfMonth(seed)) convention_ = BusinessDayConvention.Preceding; if (calendar_.adjust(originalDates_.Last(), terminationDateConvention_) != calendar_.adjust(terminationDate__, terminationDateConvention_)) { if (rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS ) { originalDates_.Add(nextTwentieth(terminationDate__, rule_)); isRegular_.Add(true); } else { originalDates_.Add(terminationDate__); isRegular_.Add(false); } } break; default: throw new ArgumentException("Unknown DateGeneration rule: " + rule_); } // adjustments to holidays, etc. if (rule_ == DateGeneration.Rule.ThirdWednesday) for (int i = 1; i < originalDates_.Count; ++i) originalDates_[i] = Date.nthWeekday(3, DayOfWeek.Wednesday, originalDates_[i].Month, originalDates_[i].Year); if (endOfMonth && calendar_.isEndOfMonth(seed)) { // adjust to end of month if (convention_ == BusinessDayConvention.Unadjusted) { for (int i = 0; i < originalDates_.Count; ++i) originalDates_[i] = Date.endOfMonth(originalDates_[i]); } else { for (int i = 0; i < originalDates_.Count; ++i) originalDates_[i] = calendar_.endOfMonth(originalDates_[i]); } if (terminationDateConvention_ == BusinessDayConvention.Unadjusted) originalDates_[originalDates_.Count - 1] = Date.endOfMonth(originalDates_.Last()); else originalDates_[originalDates_.Count - 1] = calendar_.endOfMonth(originalDates_.Last()); } else { // first date not adjusted for CDS schedules if (rule_ != DateGeneration.Rule.OldCDS) originalDates_[0] = calendar_.adjust(originalDates_[0], convention_); for (int i = 1; i < originalDates_.Count; ++i) originalDates_[i] = calendar_.adjust(originalDates_[i], convention_); foreach (Date d in originalDates_) adjustedDates_.Add(d); // 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_ != BusinessDayConvention.Unadjusted || rule_ == DateGeneration.Rule.Twentieth || rule_ == DateGeneration.Rule.TwentiethIMM || rule_ == DateGeneration.Rule.OldCDS || rule_ == DateGeneration.Rule.CDS) adjustedDates_[adjustedDates_.Count - 1] = calendar_.adjust(originalDates_.Last(), terminationDateConvention_); } }