//! next ASX date following the given date /*! returns the 1st delivery date for next contract listed in the * Australian Securities Exchange. */ public static Date nextDate(Date date = null, bool mainCycle = true) { Date refDate = date ?? Settings.evaluationDate(); int y = refDate.year(); int m = refDate.month(); int offset = mainCycle ? 3 : 1; int skipMonths = offset - (m % offset); if (skipMonths != offset || refDate.Day > 14) { skipMonths += m; if (skipMonths <= 12) { m = skipMonths; } else { m = (skipMonths - 12); y += 1; } } Date result = Date.nthWeekday(2, DayOfWeek.Friday, m, y); if (result <= refDate) { result = nextDate(new Date(15, m, y), mainCycle); } return(result); }
/*! returns the ECB code for the given date (e.g. MAR10 for March xxth, 2010). \warning It raises an exception if the input date is not an ECB date */ public static string code( Date ecbDate ) { Utils.QL_REQUIRE(isECBdate(ecbDate),() => ecbDate + " is not a valid ECB date"); string ECBcode = string.Empty; int y = ecbDate.year() % 100; string padding = string.Empty; if (y < 10) padding = "0"; switch(ecbDate.month()) { case (int)Month.January: ECBcode += "JAN" + padding + y; break; case (int)Month.February: ECBcode += "FEB" + padding + y; break; case (int)Month.March: ECBcode += "MAR" + padding + y; break; case (int)Month.April: ECBcode += "APR" + padding + y; break; case (int)Month.May: ECBcode += "MAY" + padding + y; break; case (int)Month.June: ECBcode += "JUN" + padding + y; break; case (int)Month.July: ECBcode += "JUL" + padding + y; break; case (int)Month.August: ECBcode += "AUG" + padding + y; break; case (int)Month.September: ECBcode += "SEP" + padding + y; break; case (int)Month.October: ECBcode += "OCT" + padding + y; break; case (int)Month.November: ECBcode += "NOV" + padding + y; break; case (int)Month.December: ECBcode += "DEC" + padding + y; break; default: Utils.QL_FAIL("not an ECB month (and it should have been)"); break; } #if(QL_EXTRA_SAFETY_CHECKS) QL_ENSURE(isECBcode(ECBcode.str()), "the result " << ECBcode.str() << " is an invalid ECB code"); #endif return ECBcode; }
public override int dayCount(Date d1, Date d2) { int s1, s2; s1 = d1.Day + MonthOffset[d1.month() - 1] + (d1.year() * 365); s2 = d2.Day + MonthOffset[d2.month() - 1] + (d2.year() * 365); if (d1.month() == (int)Month.Feb && d1.Day == 29) { --s1; } if (d2.month() == (int)Month.Feb && d2.Day == 29) { --s2; } return(s2 - s1); }
public override int dayCount(Date d1, Date d2) { int s1, s2; s1 = d1.Day + MonthOffset[d1.month()-1] + (d1.year() * 365); s2 = d2.Day + MonthOffset[d2.month()-1] + (d2.year() * 365); if (d1.month() == (int)Month.Feb && d1.Day == 29) { --s1; } if (d2.month() == (int)Month.Feb && d2.Day == 29) { --s2; } return s2 - s1; }
public EventSetSimulation(List <KeyValuePair <Date, double> > events, Date eventsStart, Date eventsEnd, Date start, Date end) : base(start, end) { events_ = events; eventsStart_ = eventsStart; eventsEnd_ = eventsEnd; i_ = 0; years_ = end_.year() - start_.year(); if (eventsStart_.month() < start_.month() || (eventsStart_.month() == start_.month() && eventsStart_.Day <= start_.Day)) { periodStart_ = new Date(start_.Day, start_.Month, eventsStart_.Year); } else { periodStart_ = new Date(start_.Day, start_.month(), eventsStart_.year() + 1); } periodEnd_ = new Date(end_.Day, end_.Month, periodStart_.Year + years_); while (i_ < events_.Count && (events_)[i_].Key < periodStart_) { ++i_; //i points to the first element after the start of the relevant period. } }
Date previousTwentieth(Date d, DateGeneration.Rule rule) { Date result = new Date(20, d.month(), d.year()); if (result > d) { result -= new Period(1, TimeUnit.Months); } if (rule == DateGeneration.Rule.TwentiethIMM || rule == DateGeneration.Rule.OldCDS || rule == DateGeneration.Rule.CDS) { int m = result.month(); if (m % 3 != 0) { // not a main IMM nmonth int skip = m % 3; result -= new Period(skip, TimeUnit.Months); } } return(result); }
Date previousTwentieth(Date d, DateGeneration.Rule rule) { Date result = new Date(20, d.month(), d.year()); if (result > d) result -= new Period(1, TimeUnit.Months); if (rule == DateGeneration.Rule.TwentiethIMM || rule == DateGeneration.Rule.OldCDS || rule == DateGeneration.Rule.CDS) { int m = result.month(); if (m % 3 != 0) { // not a main IMM nmonth int skip = m % 3; result -= new Period(skip, TimeUnit.Months); } } return result; }
/*! returns the ASX code for the given date * (e.g. M5 for June 12th, 2015). */ public static String code(Date date) { Utils.QL_REQUIRE(isASXdate(date, false), () => date + " is not an ASX date"); String ASXcode = String.Empty; String y = (date.year() % 10).ToString(); switch ((Month)date.month()) { case Month.January: ASXcode = 'F' + y; break; case Month.February: ASXcode = 'G' + y; break; case Month.March: ASXcode = 'H' + y; break; case Month.April: ASXcode = 'J' + y; break; case Month.May: ASXcode = 'K' + y; break; case Month.June: ASXcode = 'M' + y; break; case Month.July: ASXcode = 'N' + y; break; case Month.August: ASXcode = 'Q' + y; break; case Month.September: ASXcode = 'U' + y; break; case Month.October: ASXcode = 'V' + y; break; case Month.November: ASXcode = 'X' + y; break; case Month.December: ASXcode = 'Z' + y; break; default: Utils.QL_FAIL("not an ASX month (and it should have been)"); break; } return(ASXcode); }
/*! returns the ECB code for the given date * (e.g. MAR10 for March xxth, 2010). * * \warning It raises an exception if the input * date is not an ECB date */ public static string code(Date ecbDate) { Utils.QL_REQUIRE(isECBdate(ecbDate), () => ecbDate + " is not a valid ECB date"); string ECBcode = string.Empty; int y = ecbDate.year() % 100; string padding = string.Empty; if (y < 10) { padding = "0"; } switch (ecbDate.month()) { case (int)Month.January: ECBcode += "JAN" + padding + y; break; case (int)Month.February: ECBcode += "FEB" + padding + y; break; case (int)Month.March: ECBcode += "MAR" + padding + y; break; case (int)Month.April: ECBcode += "APR" + padding + y; break; case (int)Month.May: ECBcode += "MAY" + padding + y; break; case (int)Month.June: ECBcode += "JUN" + padding + y; break; case (int)Month.July: ECBcode += "JUL" + padding + y; break; case (int)Month.August: ECBcode += "AUG" + padding + y; break; case (int)Month.September: ECBcode += "SEP" + padding + y; break; case (int)Month.October: ECBcode += "OCT" + padding + y; break; case (int)Month.November: ECBcode += "NOV" + padding + y; break; case (int)Month.December: ECBcode += "DEC" + padding + y; break; default: Utils.QL_FAIL("not an ECB month (and it should have been)"); break; } #if (QL_EXTRA_SAFETY_CHECKS) QL_ENSURE(isECBcode(ECBcode.str()), "the result " << ECBcode.str() << " is an invalid ECB code"); #endif return(ECBcode); }
/// <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); }