示例#1
0
文件: ASX.cs 项目: scchess/QLNet
        //! 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);
        }
示例#2
0
文件: ECB.cs 项目: akasolace/qlnet
        /*! 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;
        }
示例#3
0
            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);
            }
示例#4
0
            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;
            }
示例#5
0
        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.
            }
        }
示例#6
0
文件: Schedule.cs 项目: mikaboz/QLNet
        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);
        }
示例#7
0
文件: Schedule.cs 项目: Yenyenx/qlnet
 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;
 }
示例#8
0
文件: ASX.cs 项目: scchess/QLNet
        /*! 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);
        }
示例#9
0
文件: ECB.cs 项目: sandboxorg/QLNet
        /*! 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);
        }
示例#10
0
        /// <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);
        }