Beispiel #1
0
        void addEffectiveInterestRateAmortizing()
        {
            // Amortizing Schedule
            Schedule schedule = new Schedule(_tradeDate, _maturityDate, new Period(_payFrequency),
                                             _calendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
                                             DateGeneration.Rule.Backward, false);
            double currentNominal = _marketValue;
            Date   prevDate       = _tradeDate;
            Date   actualDate     = _tradeDate;

            for (int i = 1; i < schedule.Count; ++i)
            {
                actualDate = schedule[i];
                InterestRate    rate = new InterestRate(_yield, _dCounter, Compounding.Simple, Frequency.Annual);
                InterestRate    rate2 = new InterestRate(_couponRate, _dCounter, Compounding.Simple, Frequency.Annual);
                FixedRateCoupon r, r2;
                if (i > 1)
                {
                    r  = new FixedRateCoupon(actualDate, currentNominal, rate, prevDate, actualDate, prevDate, actualDate);
                    r2 = new FixedRateCoupon(actualDate, currentNominal, rate2, prevDate, actualDate, prevDate, actualDate, null, _originalPayment);
                }

                else
                {
                    Calendar nullCalendar = new NullCalendar();
                    Period   p1           = new Period(_payFrequency);
                    Date     testDate     = nullCalendar.advance(actualDate, -1 * p1);

                    r  = new FixedRateCoupon(actualDate, currentNominal, rate, testDate, actualDate, prevDate, actualDate);
                    r2 = new FixedRateCoupon(actualDate, currentNominal, rate2, testDate, actualDate, prevDate, actualDate, null, _originalPayment);
                }

                double amort = Math.Round(Math.Abs(_originalPayment - r.amount()), 2);

                AmortizingPayment p = new AmortizingPayment(amort, actualDate);
                if (_isPremium)
                {
                    currentNominal -= Math.Abs(amort);
                }
                else
                {
                    currentNominal += Math.Abs(amort);
                }


                cashflows_.Add(r2);
                cashflows_.Add(p);
                prevDate = actualDate;
            }

            // Add single redemption for yield calculation
            setSingleRedemption(_faceValue, 100, _maturityDate);
        }
Beispiel #2
0
        public Schedule value()
        {
            // check for mandatory arguments
            Utils.QL_REQUIRE(effectiveDate_ != null, () => "effective date not provided");
            Utils.QL_REQUIRE(terminationDate_ != null, () => "termination date not provided");
            Utils.QL_REQUIRE((object)tenor_ != null, () => "tenor/frequency not provided");

            // if no calendar was set...
            if (calendar_ == null)
            {
                // ...we use a null one.
                calendar_ = new NullCalendar();
            }

            // set dynamic defaults:
            BusinessDayConvention convention;

            // if a convention was set, we use it.
            if (convention_ != null)
            {
                convention = convention_.Value;
            }
            else
            {
                if (!calendar_.empty())
                {
                    // ...if we set a calendar, we probably want it to be used;
                    convention = BusinessDayConvention.Following;
                }
                else
                {
                    // if not, we don't care.
                    convention = BusinessDayConvention.Unadjusted;
                }
            }

            BusinessDayConvention terminationDateConvention;

            // if set explicitly, we use it;
            if (terminationDateConvention_ != null)
            {
                terminationDateConvention = terminationDateConvention_.Value;
            }
            else
            {
                // Unadjusted as per ISDA specification
                terminationDateConvention = convention;
            }

            return(new Schedule(effectiveDate_, terminationDate_, tenor_, calendar_,
                                convention, terminationDateConvention,
                                rule_, endOfMonth_, firstDate_, nextToLastDate_));
        }
Beispiel #3
0
        public double fixing(Date fixingDate, bool forecastTodaysFixing)
        {
            Date today                     = Settings.evaluationDate();
            Date todayMinusLag             = today - availabilityLag_;
            KeyValuePair <Date, Date> limm = Utils.inflationPeriod(todayMinusLag, frequency_);
            Date lastFix                   = limm.Key - 1;

            Date flatMustForecastOn   = lastFix + 1;
            Date interpMustForecastOn = lastFix + 1 - new Period(frequency_);


            if (interpolated() && fixingDate >= interpMustForecastOn)
            {
                return(forecastFixing(fixingDate));
            }

            if (!interpolated() && fixingDate >= flatMustForecastOn)
            {
                return(forecastFixing(fixingDate));
            }

            // four cases with ratio() and interpolated()
            if (ratio())
            {
                if (interpolated())
                {
                    // IS ratio, IS interpolated
                    KeyValuePair <Date, Date> lim = Utils.inflationPeriod(fixingDate, frequency_);
                    Date fixMinus1Y = new NullCalendar().advance(fixingDate, new Period(-1, TimeUnit.Years), BusinessDayConvention.ModifiedFollowing);
                    KeyValuePair <Date, Date> limBef = Utils.inflationPeriod(fixMinus1Y, frequency_);
                    double dp    = lim.Value + 1 - lim.Key;
                    double dpBef = limBef.Value + 1 - limBef.Key;
                    double dl    = fixingDate - lim.Key;
                    // potentially does not work on 29th Feb
                    double dlBef = fixMinus1Y - limBef.Key;
                    // get the four relevant fixings
                    // recall that they are stored flat for every day
                    double limFirstFix =
                        IndexManager.instance().getHistory(name()).value()[lim.Key];
                    if (limFirstFix == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + lim.Key);
                    }
                    double limSecondFix =
                        IndexManager.instance().getHistory(name()).value()[lim.Value + 1];
                    if (limSecondFix == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + lim.Value + 1);
                    }
                    double limBefFirstFix =
                        IndexManager.instance().getHistory(name()).value()[limBef.Key];
                    if (limBefFirstFix == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + limBef.Key);
                    }
                    double limBefSecondFix =
                        IndexManager.instance().getHistory(name()).value()[limBef.Value + 1];
                    if (limBefSecondFix == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + limBef.Value + 1);
                    }

                    double linearNow = limFirstFix + (limSecondFix - limFirstFix) * dl / dp;
                    double linearBef = limBefFirstFix + (limBefSecondFix - limBefFirstFix) * dlBef / dpBef;
                    double wasYES    = linearNow / linearBef - 1.0;

                    return(wasYES);
                }
                else
                {
                    // IS ratio, NOT interpolated
                    double pastFixing =
                        IndexManager.instance().getHistory(name()).value()[fixingDate];
                    if (pastFixing == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + fixingDate);
                    }
                    Date   previousDate   = fixingDate - new Period(1, TimeUnit.Years);
                    double previousFixing =
                        IndexManager.instance().getHistory(name()).value()[previousDate];
                    if (previousFixing == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + previousDate);
                    }

                    return(pastFixing / previousFixing - 1.0);
                }
            }
            else
            {
                // NOT ratio
                if (interpolated())
                {
                    // NOT ratio, IS interpolated
                    KeyValuePair <Date, Date> lim = Utils.inflationPeriod(fixingDate, frequency_);
                    double dp          = lim.Value + 1 - lim.Key;
                    double dl          = fixingDate - lim.Key;
                    double limFirstFix =
                        IndexManager.instance().getHistory(name()).value()[lim.Key];
                    if (limFirstFix == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + lim.Key);
                    }
                    double limSecondFix =
                        IndexManager.instance().getHistory(name()).value()[lim.Value + 1];
                    if (limSecondFix == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + lim.Value + 1);
                    }
                    double linearNow = limFirstFix + (limSecondFix - limFirstFix) * dl / dp;

                    return(linearNow);
                }
                else
                {
                    // NOT ratio, NOT interpolated
                    // so just flat
                    double pastFixing =
                        IndexManager.instance().getHistory(name()).value()[fixingDate];
                    if (pastFixing == null)
                    {
                        throw new ApplicationException("Missing " + name() + " fixing for "
                                                       + fixingDate);
                    }
                    return(pastFixing);
                }
            }

            // QL_FAIL("YoYInflationIndex::fixing, should never get here");
        }
Beispiel #4
0
        public void testCached()
        {
            // ("Testing bond price/yield calculation against cached values...");

             CommonVars vars = new CommonVars();

             // with implicit settlement calculation:
             Date today = new Date(22, Month.November, 2004);
             Settings.setEvaluationDate(today);

             Calendar bondCalendar = new NullCalendar();
             DayCounter bondDayCount = new ActualActual(ActualActual.Convention.ISMA);
             int settlementDays = 1;

             var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, new SimpleQuote(0.03), new Actual360()));

             // actual market values from the evaluation date
             Frequency freq = Frequency.Semiannual;
             Schedule sch1 = new Schedule(new Date(31, Month.October, 2004), new Date(31, Month.October, 2006), new Period(freq),
                                      bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
                                      DateGeneration.Rule.Backward, false);

             FixedRateBond bond1 = new FixedRateBond(settlementDays, vars.faceAmount, sch1, new List<double>() { 0.025 },
                                 bondDayCount, BusinessDayConvention.ModifiedFollowing, 100.0, new Date(1, Month.November, 2004));

             IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve);
             bond1.setPricingEngine(bondEngine);

             double marketPrice1 = 99.203125;
             double marketYield1 = 0.02925;

             Schedule sch2 = new Schedule(new Date(15, Month.November, 2004), new Date(15, Month.November, 2009), new Period(freq),
                                      bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
                                      DateGeneration.Rule.Backward, false);

             FixedRateBond bond2 = new FixedRateBond(settlementDays, vars.faceAmount, sch2, new List<double>() { 0.035 },
                                      bondDayCount, BusinessDayConvention.ModifiedFollowing,
                                      100.0, new Date(15, Month.November, 2004));

             bond2.setPricingEngine(bondEngine);

             double marketPrice2 = 99.6875;
             double marketYield2 = 0.03569;

             // calculated values
             double cachedPrice1a = 99.204505, cachedPrice2a = 99.687192;
             double cachedPrice1b = 98.943393, cachedPrice2b = 101.986794;
             double cachedYield1a = 0.029257, cachedYield2a = 0.035689;
             double cachedYield1b = 0.029045, cachedYield2b = 0.035375;
             double cachedYield1c = 0.030423, cachedYield2c = 0.030432;

             // check
             double tolerance = 1.0e-6;
             double price, yield;

             price = bond1.cleanPrice(marketYield1, bondDayCount, Compounding.Compounded, freq);
             if (Math.Abs(price - cachedPrice1a) > tolerance)
             {
            Assert.Fail("failed to reproduce cached price:"
                       + "\n    calculated: " + price
                       + "\n    expected:   " + cachedPrice1a
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (price - cachedPrice1a));
             }

             price = bond1.cleanPrice();
             if (Math.Abs(price - cachedPrice1b) > tolerance)
             {
            Assert.Fail("failed to reproduce cached price:"
                       + "\n    calculated: " + price
                       + "\n    expected:   " + cachedPrice1b
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (price - cachedPrice1b));
             }

             yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Compounded, freq);
             if (Math.Abs(yield - cachedYield1a) > tolerance)
             {
            Assert.Fail("failed to reproduce cached compounded yield:"
                       + "\n    calculated: " + yield
                       + "\n    expected:   " + cachedYield1a
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (yield - cachedYield1a));
             }

             yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Continuous, freq);
             if (Math.Abs(yield - cachedYield1b) > tolerance)
             {
            Assert.Fail("failed to reproduce cached continuous yield:"
                       + "\n    calculated: " + yield
                       + "\n    expected:   " + cachedYield1b
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (yield - cachedYield1b));
             }

             yield = bond1.yield(bondDayCount, Compounding.Continuous, freq);
             if (Math.Abs(yield - cachedYield1c) > tolerance)
             {
            Assert.Fail("failed to reproduce cached continuous yield:"
                       + "\n    calculated: " + yield
                       + "\n    expected:   " + cachedYield1c
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (yield - cachedYield1c));
             }

             price = bond2.cleanPrice(marketYield2, bondDayCount, Compounding.Compounded, freq);
             if (Math.Abs(price - cachedPrice2a) > tolerance)
             {
            Assert.Fail("failed to reproduce cached price:"
                       + "\n    calculated: " + price
                       + "\n    expected:   " + cachedPrice2a
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (price - cachedPrice2a));
             }

             price = bond2.cleanPrice();
             if (Math.Abs(price - cachedPrice2b) > tolerance)
             {
            Assert.Fail("failed to reproduce cached price:"
                       + "\n    calculated: " + price
                       + "\n    expected:   " + cachedPrice2b
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (price - cachedPrice2b));
             }

             yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Compounded, freq);
             if (Math.Abs(yield - cachedYield2a) > tolerance)
             {
            Assert.Fail("failed to reproduce cached compounded yield:"
                       + "\n    calculated: " + yield
                       + "\n    expected:   " + cachedYield2a
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (yield - cachedYield2a));
             }

             yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Continuous, freq);
             if (Math.Abs(yield - cachedYield2b) > tolerance)
             {
            Assert.Fail("failed to reproduce cached continuous yield:"
                       + "\n    calculated: " + yield
                       + "\n    expected:   " + cachedYield2b
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (yield - cachedYield2b));
             }

             yield = bond2.yield(bondDayCount, Compounding.Continuous, freq);
             if (Math.Abs(yield - cachedYield2c) > tolerance)
             {
            Assert.Fail("failed to reproduce cached continuous yield:"
                       + "\n    calculated: " + yield
                       + "\n    expected:   " + cachedYield2c
                       + "\n    tolerance:  " + tolerance
                       + "\n    error:      " + (yield - cachedYield2c));
             }

             // with explicit settlement date:
             Schedule sch3 = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.November, 2006), new Period(freq),
                                      new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted,
                                      BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false);

             FixedRateBond bond3 = new FixedRateBond(settlementDays, vars.faceAmount, sch3, new List<double>() { 0.02875 },
                             new ActualActual(ActualActual.Convention.ISMA),
                             BusinessDayConvention.ModifiedFollowing, 100.0, new Date(30, Month.November, 2004));

             bond3.setPricingEngine(bondEngine);

             double marketYield3 = 0.02997;

             Date settlementDate = new Date(30, Month.November, 2004);
             double cachedPrice3 = 99.764759;

             price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq, settlementDate);
             if (Math.Abs(price - cachedPrice3) > tolerance)
             {
            Assert.Fail("failed to reproduce cached price:"
                       + "\n    calculated: " + price + ""
                       + "\n    expected:   " + cachedPrice3 + ""
                       + "\n    error:      " + (price - cachedPrice3));
             }

             // this should give the same result since the issue date is the
             // earliest possible settlement date
             Settings.setEvaluationDate(new Date(22, Month.November, 2004));

             price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq);
             if (Math.Abs(price - cachedPrice3) > tolerance)
             {
            Assert.Fail("failed to reproduce cached price:"
                       + "\n    calculated: " + price + ""
                       + "\n    expected:   " + cachedPrice3 + ""
                       + "\n    error:      " + (price - cachedPrice3));
             }
        }
Beispiel #5
0
        public void testBondFromScheduleWithDateVector()
        {
            // Testing South African R2048 bond price using Schedule constructor with Date vector
             SavedSettings backup = new SavedSettings();

             //When pricing bond from Yield To Maturity, use NullCalendar()
             Calendar calendar = new NullCalendar();

             int settlementDays = 3;

             Date issueDate = new Date(29, Month.June, 2012);
             Date today = new Date(7, Month.September, 2015);
             Date evaluationDate = calendar.adjust(today);
             Date settlementDate = calendar.advance(evaluationDate, new Period(settlementDays, TimeUnit.Days));
             Settings.setEvaluationDate(evaluationDate);

             // For the schedule to generate correctly for Feb-28's, make maturity date on Feb 29
             Date maturityDate = new Date(29, Month.February, 2048);

             double coupon = 0.0875;
             Compounding comp = Compounding.Compounded;
             Frequency freq = Frequency.Semiannual;
             DayCounter dc = new ActualActual(ActualActual.Convention.Bond);

             // Yield as quoted in market
             InterestRate yield = new InterestRate(0.09185, dc, comp, freq);

             Period tenor = new Period(6, TimeUnit.Months);
             Period exCouponPeriod = new Period(10, TimeUnit.Days);

             // Generate coupon dates for 31 Aug and end of Feb each year
             // For leap years, this will generate 29 Feb, but the bond
             // actually pays coupons on 28 Feb, regardsless of whether
             // it is a leap year or not.
             Schedule schedule = new Schedule(issueDate, maturityDate, tenor,
            new NullCalendar(), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
            DateGeneration.Rule.Backward, true);

             // Adjust the 29 Feb's to 28 Feb
             List<Date> dates = new List<Date>();
             for (int i = 0; i < schedule.Count; ++i)
             {
            Date d = schedule.date(i);
            if (d.Month == 2 && d.Day == 29)
               dates.Add(new Date(28, Month.February, d.Year));
            else
               dates.Add(d);
             }

             schedule = new Schedule(dates,
                                 schedule.calendar(),
                                 schedule.businessDayConvention(),
                                 schedule.terminationDateBusinessDayConvention(),
                                 schedule.tenor(),
                                 schedule.rule(),
                                 schedule.endOfMonth(),
                                 schedule.isRegular());

             FixedRateBond bond = new FixedRateBond(
             0,
             100.0,
             schedule,
             new List<double>() { coupon },
             dc, BusinessDayConvention.Following, 100.0,
             issueDate, calendar,
             exCouponPeriod, calendar, BusinessDayConvention.Unadjusted, false);

             double calculatedPrice = BondFunctions.dirtyPrice(bond, yield, settlementDate);
             double expectedPrice = 95.75706;
             double tolerance = 1e-5;
             if (Math.Abs(calculatedPrice - expectedPrice) > tolerance)
             {
            Assert.Fail(string.Format("failed to reproduce R2048 dirty price\nexpected: {0}\ncalculated: {1}", expectedPrice, calculatedPrice));
             }
        }
Beispiel #6
0
        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);
             }
        }
Beispiel #7
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);
        }
Beispiel #8
0
        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_);
                }
            }
        }
Beispiel #9
0
        public void testYYIndex()
        {
            // Testing year-on-year inflation indices

            SavedSettings backup = new SavedSettings();
            //IndexHistoryCleaner cleaner = new IndexHistoryCleaner();

            YYEUHICP yyeuhicp = new YYEUHICP( true );
            if ( yyeuhicp.name() != "EU YY_HICP"
                || yyeuhicp.frequency() != Frequency.Monthly
                || yyeuhicp.revised()
                || !yyeuhicp.interpolated()
                || yyeuhicp.ratio()
                || yyeuhicp.availabilityLag() != new Period( 1, TimeUnit.Months ) )
            {
                Assert.Fail( "wrong year-on-year EU HICP data ("
                            + yyeuhicp.name() + ", "
                            + yyeuhicp.frequency() + ", "
                            + yyeuhicp.revised() + ", "
                            + yyeuhicp.interpolated() + ", "
                            + yyeuhicp.ratio() + ", "
                            + yyeuhicp.availabilityLag() + ")" );
            }

            YYEUHICPr yyeuhicpr = new YYEUHICPr( true );
            if ( yyeuhicpr.name() != "EU YYR_HICP"
                || yyeuhicpr.frequency() != Frequency.Monthly
                || yyeuhicpr.revised()
                || !yyeuhicpr.interpolated()
                || !yyeuhicpr.ratio()
                || yyeuhicpr.availabilityLag() != new Period( 1, TimeUnit.Months ) )
            {
                Assert.Fail( "wrong year-on-year EU HICPr data ("
                                + yyeuhicpr.name() + ", "
                                + yyeuhicpr.frequency() + ", "
                                + yyeuhicpr.revised() + ", "
                                + yyeuhicpr.interpolated() + ", "
                                + yyeuhicpr.ratio() + ", "
                                + yyeuhicpr.availabilityLag() + ")" );
            }

            YYUKRPI yyukrpi = new YYUKRPI( false );
            if ( yyukrpi.name() != "UK YY_RPI"
                || yyukrpi.frequency() != Frequency.Monthly
                || yyukrpi.revised()
                || yyukrpi.interpolated()
                || yyukrpi.ratio()
                || yyukrpi.availabilityLag() != new Period( 1, TimeUnit.Months ) )
            {
                Assert.Fail( "wrong year-on-year UK RPI data ("
                                + yyukrpi.name() + ", "
                                + yyukrpi.frequency() + ", "
                                + yyukrpi.revised() + ", "
                                + yyukrpi.interpolated() + ", "
                                + yyukrpi.ratio() + ", "
                                + yyukrpi.availabilityLag() + ")" );
            }

            YYUKRPIr yyukrpir = new YYUKRPIr( false );
            if ( yyukrpir.name() != "UK YYR_RPI"
                || yyukrpir.frequency() != Frequency.Monthly
                || yyukrpir.revised()
                || yyukrpir.interpolated()
                || !yyukrpir.ratio()
                || yyukrpir.availabilityLag() != new Period( 1, TimeUnit.Months ) )
            {
                Assert.Fail( "wrong year-on-year UK RPIr data ("
                                + yyukrpir.name() + ", "
                                + yyukrpir.frequency() + ", "
                                + yyukrpir.revised() + ", "
                                + yyukrpir.interpolated() + ", "
                                + yyukrpir.ratio() + ", "
                                + yyukrpir.availabilityLag() + ")" );
            }

            // Retrieval test.
            //----------------
            // make sure of the evaluation date
            Date evaluationDate = new Date( 13, Month.August, 2007 );
            evaluationDate = new UnitedKingdom().adjust( evaluationDate );
            Settings.setEvaluationDate( evaluationDate );

            // fixing data
            Date from = new Date( 1, Month.January, 2005 );
            Date to = new Date( 13, Month.August, 2007 );
            Schedule rpiSchedule = new MakeSchedule().from( from ).to( to )
            .withTenor( new Period( 1, TimeUnit.Months ) )
            .withCalendar( new UnitedKingdom() )
            .withConvention( BusinessDayConvention.ModifiedFollowing ).value();

            double[] fixData = { 189.9, 189.9, 189.6, 190.5, 191.6, 192.0,
            192.2, 192.2, 192.6, 193.1, 193.3, 193.6,
            194.1, 193.4, 194.2, 195.0, 196.5, 197.7,
            198.5, 198.5, 199.2, 200.1, 200.4, 201.1,
            202.7, 201.6, 203.1, 204.4, 205.4, 206.2,
            207.3 };

            bool interp = false;
            YYUKRPIr iir = new YYUKRPIr( interp );
            YYUKRPIr iirYES = new YYUKRPIr( true );
            for ( int i = 0; i < fixData.Length; i++ )
            {
                iir.addFixing( rpiSchedule[i], fixData[i] );
                iirYES.addFixing( rpiSchedule[i], fixData[i] );
            }

            Date todayMinusLag = evaluationDate - iir.availabilityLag();
            KeyValuePair<Date, Date> lim0 = Utils.inflationPeriod( todayMinusLag, iir.frequency() );
            todayMinusLag = lim0.Value + 1 - 2 * new Period( iir.frequency() );

            double eps = 1.0e-8;

            // Interpolation tests
            //--------------------
            // (no TS so can't forecast).
            for ( int i = 13; i < rpiSchedule.Count; i++ )
            {
                KeyValuePair<Date, Date> lim = Utils.inflationPeriod( rpiSchedule[i], iir.frequency() );
                KeyValuePair<Date, Date> limBef = Utils.inflationPeriod( rpiSchedule[i - 12], iir.frequency() );
                for ( Date d = lim.Key; d <= lim.Value; d++ )
                {
                    if ( d < todayMinusLag )
                    {
                        double expected = fixData[i] / fixData[i - 12] - 1.0;
                        double calculated = iir.fixing( d );
                        Assert.IsTrue( Math.Abs( calculated - expected ) < eps,
                                                "Non-interpolated fixings not constant within a period: "
                                                + calculated
                                                + ", should be "
                                                + expected );

                        double dp = lim.Value + 1 - lim.Key;
                        double dpBef = limBef.Value + 1 - limBef.Key;
                        double dl = d - lim.Key;
                        // potentially does not work on 29th Feb
                        double dlBef = new NullCalendar().advance( d, -new Period( 1, TimeUnit.Years ),
                            BusinessDayConvention.ModifiedFollowing ) - limBef.Key;

                        double linearNow = fixData[i] + ( fixData[i + 1] - fixData[i] ) * dl / dp;
                        double linearBef = fixData[i - 12] + ( fixData[i + 1 - 12] - fixData[i - 12] ) * dlBef / dpBef;
                        double expectedYES = linearNow / linearBef - 1.0;
                        double calculatedYES = iirYES.fixing( d );
                        Assert.IsTrue( Math.Abs( expectedYES - calculatedYES ) < eps,
                                                "Error in interpolated fixings: expect " + expectedYES
                                                + " see " + calculatedYES
                                                + " flat " + calculated
                                                + ", data: " + fixData[i - 12] + ", " + fixData[i + 1 - 12]
                                                + ", " + fixData[i] + ", " + fixData[i + 1]
                                                + ", fac: " + dp + ", " + dl
                                                + ", " + dpBef + ", " + dlBef
                                                + ", to: " + linearNow + ", " + linearBef
                                                );
                    }
                }
            }
        }
Beispiel #10
0
        static void Main(string[] args)
        {
            // boost::timer timer;

             Date today = new Date(16,Month.October,2007);
             Settings.setEvaluationDate(today);

             Console.WriteLine();
             Console.WriteLine("Pricing a callable fixed rate bond using");
             Console.WriteLine("Hull White model w/ reversion parameter = 0.03");
             Console.WriteLine("BAC4.65 09/15/12  ISIN: US06060WBJ36");
             Console.WriteLine("roughly five year tenor, ");
             Console.WriteLine("quarterly coupon and call dates");
             Console.WriteLine("reference date is : " + today );

             /* Bloomberg OAS1: "N" model (Hull White)
               varying volatility parameter

               The curve entered into Bloomberg OAS1 is a flat curve,
               at constant yield = 5.5%, semiannual compounding.
               Assume here OAS1 curve uses an ACT/ACT day counter,
               as documented in PFC1 as a "default" in the latter case.
             */

             // set up a flat curve corresponding to Bloomberg flat curve

             double bbCurveRate = 0.055;
             DayCounter bbDayCounter = new ActualActual(ActualActual.Convention.Bond);
             InterestRate bbIR = new InterestRate(bbCurveRate,bbDayCounter,Compounding.Compounded ,Frequency.Semiannual);

             Handle<YieldTermStructure> termStructure = new Handle<YieldTermStructure>(flatRate( today,
                                                              bbIR.rate(),
                                                              bbIR.dayCounter(),
                                                              bbIR.compounding(),
                                                              bbIR.frequency()));
             // set up the call schedule

             CallabilitySchedule callSchedule = new CallabilitySchedule();
             double callPrice = 100.0;
             int numberOfCallDates = 24;
             Date callDate = new Date(15,Month.September,2006);

             for (int i=0; i< numberOfCallDates; i++)
             {
            Calendar nullCalendar = new NullCalendar();

            Callability.Price myPrice = new Callability.Price(callPrice, Callability.Price.Type.Clean);
            callSchedule.Add( new Callability(myPrice,Callability.Type.Call, callDate ));
            callDate = nullCalendar.advance(callDate, 3, TimeUnit.Months);
             }

             // set up the callable bond

             Date dated = new Date(16,Month.September,2004);
             Date issue = dated;
             Date maturity = new Date(15,Month.September,2012);
             int settlementDays = 3;  // Bloomberg OAS1 settle is Oct 19, 2007
             Calendar bondCalendar = new UnitedStates(UnitedStates.Market.GovernmentBond);
             double coupon = .0465;
             Frequency frequency = Frequency.Quarterly;
             double redemption = 100.0;
             double faceAmount = 100.0;

             /* The 30/360 day counter Bloomberg uses for this bond cannot
            reproduce the US Bond/ISMA (constant) cashflows used in PFC1.
            Therefore use ActAct(Bond)
             */
             DayCounter bondDayCounter = new ActualActual(ActualActual.Convention.Bond);

             // PFC1 shows no indication dates are being adjusted
             // for weekends/holidays for vanilla bonds
             BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted;
             BusinessDayConvention paymentConvention = BusinessDayConvention.Unadjusted;

             Schedule sch = new Schedule( dated, maturity, new Period(frequency), bondCalendar,
                                      accrualConvention, accrualConvention,
                                      DateGeneration.Rule.Backward, false);

             int maxIterations = 1000;
             double accuracy = 1e-8;
             int gridIntervals = 40;
             double reversionParameter = .03;

             // output price/yield results for varying volatility parameter

             double sigma = Const.QL_Epsilon; // core dumps if zero on Cygwin

             ShortRateModel hw0 = new HullWhite(termStructure,reversionParameter,sigma);

             IPricingEngine engine0 = new TreeCallableFixedRateBondEngine(hw0, gridIntervals, termStructure);

             CallableFixedRateBond callableBond = new CallableFixedRateBond( settlementDays, faceAmount, sch,
                                                                         new InitializedList<double>(1, coupon),
                                                                         bondDayCounter, paymentConvention,
                                                                         redemption, issue, callSchedule);
             callableBond.setPricingEngine(engine0);

             Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma));

             Console.WriteLine("QuantLib price/yld (%)  ");
             Console.WriteLine(  "{0:0.00} / {1:0.00} ", callableBond.cleanPrice() ,
                                                     100.0 * callableBond.yield(bondDayCounter,
                                                                                Compounding.Compounded,
                                                                                frequency,
                                                                                accuracy,
                                                                                maxIterations));
             Console.WriteLine("Bloomberg price/yld (%) ");
             Console.WriteLine("96.50 / 5.47");

             //

             sigma = .01;

             Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma));

             ShortRateModel hw1 = new HullWhite(termStructure,reversionParameter,sigma);

             IPricingEngine engine1 = new TreeCallableFixedRateBondEngine(hw1,gridIntervals,termStructure);

             callableBond.setPricingEngine(engine1);

             Console.WriteLine("QuantLib price/yld (%)  ");
             Console.WriteLine(  "{0:0.00} / {1:0.00} ", callableBond.cleanPrice() ,
                                                     100.0 * callableBond.yield(bondDayCounter,
                                                                                Compounding.Compounded,
                                                                                frequency,
                                                                                accuracy,
                                                                                maxIterations));

             Console.WriteLine("Bloomberg price/yld (%) ");
             Console.WriteLine("95.68 / 5.66");

             //

             sigma = .03;

             Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma));

             ShortRateModel hw2 = new HullWhite(termStructure, reversionParameter, sigma);

             IPricingEngine engine2 = new TreeCallableFixedRateBondEngine(hw2, gridIntervals, termStructure);

             callableBond.setPricingEngine(engine2);

             Console.WriteLine("QuantLib price/yld (%)  ");
             Console.WriteLine("{0:0.00} / {1:0.00} ", callableBond.cleanPrice(),
                                                     100.0 * callableBond.yield(bondDayCounter,
                                                                                Compounding.Compounded,
                                                                                frequency,
                                                                                accuracy,
                                                                                maxIterations));

             Console.WriteLine("Bloomberg price/yld (%) ");
             Console.WriteLine("92.34 / 6.49");

             //

             sigma = .06;

             Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma));

             ShortRateModel hw3 = new HullWhite(termStructure, reversionParameter, sigma);

             IPricingEngine engine3 = new TreeCallableFixedRateBondEngine(hw3, gridIntervals, termStructure);

             callableBond.setPricingEngine(engine3);

             Console.WriteLine("QuantLib price/yld (%)  ");
             Console.WriteLine("{0:0.00} / {1:0.00} ", callableBond.cleanPrice(),
                                                     100.0 * callableBond.yield(bondDayCounter,
                                                                                Compounding.Compounded,
                                                                                frequency,
                                                                                accuracy,
                                                                                maxIterations));

             Console.WriteLine("Bloomberg price/yld (%) ");
             Console.WriteLine("87.16 / 7.83");

             //

             sigma = .12;

             Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma));

             ShortRateModel hw4 = new HullWhite(termStructure, reversionParameter, sigma);

             IPricingEngine engine4 = new TreeCallableFixedRateBondEngine(hw4, gridIntervals, termStructure);

             callableBond.setPricingEngine(engine4);

             Console.WriteLine("QuantLib price/yld (%)  ");
             Console.WriteLine("{0:0.00} / {1:0.00} ", callableBond.cleanPrice(),
                                                     100.0 * callableBond.yield(bondDayCounter,
                                                                                Compounding.Compounded,
                                                                                frequency,
                                                                                accuracy,
                                                                                maxIterations));

             Console.WriteLine("Bloomberg price/yld (%) ");
             Console.WriteLine("77.31 / 10.65");
        }
Beispiel #11
0
        public void testInArrears()
        {
            //("Testing in-arrears swap calculation...");

             CommonVars vars = new CommonVars();

             /* See Hull, 4th ed., page 550
            Note: the calculation in the book is wrong (work out the adjustment and you'll get 0.05 + 0.000115 T1) */
             Date maturity = vars.today + new Period(5, TimeUnit.Years);
             Calendar calendar = new NullCalendar();
             Schedule schedule = new Schedule(vars.today, maturity, new Period(Frequency.Annual), calendar,
                                          BusinessDayConvention.Following, BusinessDayConvention.Following,
                                          DateGeneration.Rule.Forward, false);
             DayCounter dayCounter = new SimpleDayCounter();

             List<double> nominals = new List<double>() { 100000000.0 };

             IborIndex index = new IborIndex("dummy", new Period(1, TimeUnit.Years), 0, new EURCurrency(), calendar,
                                         BusinessDayConvention.Following, false, dayCounter, vars.termStructure);
             double oneYear = 0.05;
             double r = Math.Log(1.0 + oneYear);
             vars.termStructure.linkTo(Utilities.flatRate(vars.today, r, dayCounter));

             List<double> coupons = new List<double>() { oneYear };
             List<CashFlow> fixedLeg = new FixedRateLeg(schedule)
                                 .withCouponRates(coupons, dayCounter)
                                 .withNotionals(nominals);

             List<double> gearings = new List<double>();
             List<double> spreads = new List<double>();
             int fixingDays = 0;

             double capletVolatility = 0.22;
             var vol = new Handle<OptionletVolatilityStructure>(
                        new ConstantOptionletVolatility(vars.today, new NullCalendar(),
                                                        BusinessDayConvention.Following, capletVolatility, dayCounter));
             IborCouponPricer pricer = new BlackIborCouponPricer(vol);

             List<CashFlow> floatingLeg = new IborLeg(schedule, index)
                                     .withPaymentDayCounter(dayCounter)
                                     .withFixingDays(fixingDays)
                                     .withGearings(gearings)
                                     .withSpreads(spreads)
                                     .inArrears()
                                     .withNotionals(nominals);
             Utils.setCouponPricer(floatingLeg, pricer);

             Swap swap = new Swap(floatingLeg, fixedLeg);
             swap.setPricingEngine(new DiscountingSwapEngine(vars.termStructure));

             double storedValue = -144813.0;
             double tolerance = 1.0;

             if (Math.Abs(swap.NPV() - storedValue) > tolerance)
            Assert.Fail("Wrong NPV calculation:\n"
                        + "    expected:   " + storedValue + "\n"
                        + "    calculated: " + swap.NPV());
        }
Beispiel #12
0
      void addEffectiveInterestRateAmortizing()
      {

         // Amortizing Schedule
         Schedule schedule = new Schedule(_tradeDate, _maturityDate, new Period(_payFrequency),
                                           _calendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
                                           DateGeneration.Rule.Backward, false);
         double currentNominal = _marketValue;
         Date prevDate = _tradeDate;
         Date actualDate = _tradeDate;

         for (int i = 1; i < schedule.Count; ++i)
         {

            actualDate = schedule[i];
            InterestRate rate = new InterestRate(_yield, _dCounter, Compounding.Simple, Frequency.Annual);
            InterestRate rate2 = new InterestRate(_couponRate, _dCounter, Compounding.Simple, Frequency.Annual);
            FixedRateCoupon r,r2;
            if (i > 1)
            {
               r = new FixedRateCoupon(currentNominal, actualDate, rate, prevDate, actualDate, prevDate, actualDate);
               r2 = new FixedRateCoupon(currentNominal, actualDate, rate2, prevDate, actualDate, prevDate, actualDate, null,_originalPayment);
            }

            else
            {
               Calendar nullCalendar = new NullCalendar();
               Period p1 = new Period(_payFrequency);
               Date testDate = nullCalendar.advance(actualDate, -1 * p1);

               r = new FixedRateCoupon(currentNominal, actualDate, rate, testDate, actualDate, prevDate, actualDate);
               r2 = new FixedRateCoupon(currentNominal, actualDate, rate2, testDate, actualDate, prevDate, actualDate, null,_originalPayment);
            }

            double amort = Math.Round(Math.Abs(_originalPayment - r.amount()),2);
          
            AmortizingPayment p = new AmortizingPayment(amort, actualDate);
            if (_isPremium)
               currentNominal -= Math.Abs(amort);
            else
               currentNominal += Math.Abs(amort);


            cashflows_.Add(r2);
            cashflows_.Add(p);
            prevDate = actualDate;
         }

         // Add single redemption for yield calculation
         setSingleRedemption(_faceValue, 100, _maturityDate);

      }
        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);
            }
        }
        //public MakeSchedule(Date effectiveDate, Date terminationDate, Period tenor, Calendar calendar,
        //                    BusinessDayConvention convention) {
        //    calendar_ = calendar;
        //    effectiveDate_ = effectiveDate;
        //    terminationDate_ = terminationDate;
        //    tenor_ = tenor;
        //    convention_ = convention;
        //    terminationDateConvention_ = convention;
        //    rule_ = DateGeneration.Rule.Backward;
        //    endOfMonth_ = false;
        //    firstDate_ = nextToLastDate_ = null;
        //}

        public Schedule value() 
        {

           // check for mandatory arguments
           if (effectiveDate_ == null)
              throw new ApplicationException("effective date not provided");
           if (terminationDate_ == null)
              throw new ApplicationException("termination date not provided");
           if ((object)tenor_ == null)
              throw new ApplicationException("tenor/frequency not provided");

           // set dynamic defaults:
           BusinessDayConvention convention;
           // if a convention was set, we use it.
           if (convention_ != null )
           {
              convention = convention_;
           }
           else
           {
              if (!calendar_.empty())
              {
                 // ...if we set a calendar, we probably want it to be used;
                 convention = BusinessDayConvention.Following;
              }
              else
              {
                 // if not, we don't care.
                 convention = BusinessDayConvention.Unadjusted;
              }
           }

           BusinessDayConvention terminationDateConvention;
           // if set explicitly, we use it;
           if (terminationDateConvention_ != null )
           {
              terminationDateConvention = terminationDateConvention_;
           }
           else
           {
              // Unadjusted as per ISDA specification
              terminationDateConvention = convention;
           }

           Calendar calendar = calendar_;
           // if no calendar was set...
           if (calendar.empty())
           {
              // ...we use a null one.
              calendar = new NullCalendar();
           }

            return new Schedule(effectiveDate_, terminationDate_, tenor_, calendar_,
                                convention_, terminationDateConvention_,
                                rule_, endOfMonth_, firstDate_, nextToLastDate_);
        }
Beispiel #15
0
        public override void calculate(DateTime calcDate, FP_Parameter fp_parameter)
        {
            // master data load

            this.indexOptionDAO_.SelectOwn();

            // market data load
            
            // index data
            clsHDAT_MARKETDATA_TB clstb = new clsHDAT_MARKETDATA_TB();

            string calcDateStr = calcDate.ToString("yyyyMMdd");
            QLNet.Settings.setEvaluationDate(calcDate);

            clstb.REF_DT = calcDateStr;
            clstb.INDEX_CD = this.indexOptionDAO_.UNDERLYING_INDEX_CD;

            int checkNum = clstb.SelectOwn();

            if (checkNum == 0) { throw new Exception("market data does not exist : " + calcDateStr + " " + clstb.INDEX_CD); }

            double indexData = clstb.LAST;

            // curveData --------------------------------------------------

            string curve_cd = "IRSKRW";
            
            YieldCurve curveManager = new YieldCurve();

            curveManager.loadCurveData(calcDate,curve_cd,clsHDAT_CURVEDATA_TB.RATE_TYP_Type.YTM);
            QLNet.YieldTermStructure yield_ts = curveManager.yieldCurve();

            // calculate

            string maturityDateStr = this.indexOptionDAO_.MATURITY_DT;

            System.Globalization.CultureInfo us
                = new System.Globalization.CultureInfo("en-US");

            DateTime maturityDate = DateTime.ParseExact(maturityDateStr, "yyyyMMdd", us);

            DayCounter dc = new Actual365Fixed();
            Calendar cal = new NullCalendar();

            double vol = 0.3;

            double strike = this.indexOptionDAO_.STRIKE;
            PlainVanillaPayoff strikePayoff = new PlainVanillaPayoff(Option.Type.
                Call, strike);

            Exercise exercise = new EuropeanExercise(maturityDate);

            VanillaOption q_option = new VanillaOption(strikePayoff,exercise);

            Handle<Quote> x0 = new Handle<Quote>(new SimpleQuote(indexData));
            FlatForward flatForward = new FlatForward(calcDate,0.01,dc);
            Handle<YieldTermStructure> dividendTS = new Handle<YieldTermStructure>(flatForward);
            Handle<YieldTermStructure> riskFreeTS = new Handle<YieldTermStructure>(yield_ts);
            BlackConstantVol blackConstVol = new BlackConstantVol(calcDate,cal,vol,dc);
            Handle<BlackVolTermStructure> blackVolTS = new Handle<BlackVolTermStructure>(blackConstVol);

            GeneralizedBlackScholesProcess process =new GeneralizedBlackScholesProcess(x0 ,dividendTS,riskFreeTS,blackVolTS);
            
            AnalyticEuropeanEngine europeanEngine = new AnalyticEuropeanEngine(process);

            q_option.setPricingEngine(europeanEngine);

            double value = q_option.NPV(); 
            double indexMultiplier = this.indexOptionDAO_.INDEX_MULTIPLIER;
            int quantity = this.indexOptionDAO_.QUANTITY;

            clsHITM_FP_GREEKRESULT_TB result_tb = new clsHITM_FP_GREEKRESULT_TB();

            result_tb.FP_GREEKRESULT_ID = IDGenerator.getNewGreekResultID(this.indexOptionDAO_.INSTRUMENT_ID,calcDateStr);
            result_tb.CALC_DT = calcDateStr;
            result_tb.INSTRUMENT_ID = this.indexOptionDAO_.INSTRUMENT_ID;
            result_tb.INSTRUMENT_TYP = this.indexOptionDAO_.INSTRUMENT_TYP;
            result_tb.UNDERLYING_ID = "KOSPI200";
            result_tb.UNDERLYING_VALUE = indexData;
            //result_tb.SEQ = 1;
            result_tb.DELTA = (q_option.delta() * indexData / 100) * indexMultiplier * quantity; // 1% Delta
            result_tb.GAMMA = 0.5 * (q_option.gamma() * indexData / 100) * indexMultiplier * quantity; // 1% Gamma
            result_tb.VEGA = q_option.vega() / 100 * indexMultiplier * quantity; // 1% point Vega
            result_tb.CALC_PRICE = value * indexMultiplier * quantity;
            result_tb.CALCULATED_FLAG = (int)clsHITM_FP_GREEKRESULT_TB.CALCULATED_FLAG_Type.CALCULATED;
            result_tb.CALCULATED_TIME = DateTime.Now.ToString("HHmmss"); ;
            result_tb.CALCULATE_TYP = (int)clsHITM_FP_GREEKRESULT_TB.CALCULATE_TYP_Type.ANALYTICS;

            // price

            if (result_tb.UpdateDateResult() == 0)
            { throw new Exception("update result fail. no exist , calcDate : " + calcDate.ToString("yyyyMMdd") + " , inst_id : " + result_tb.INSTRUMENT_ID); }

            // delta

            // gamma and others : no exist ?


        }
      public double fixing(Date fixingDate, bool forecastTodaysFixing)
      {
         Date today = Settings.evaluationDate();
         Date todayMinusLag = today - availabilityLag_;
         KeyValuePair<Date,Date> limm = Utils.inflationPeriod(todayMinusLag, frequency_);
         Date lastFix = limm.Key-1;

         Date flatMustForecastOn = lastFix+1;
         Date interpMustForecastOn = lastFix+1 - new Period(frequency_);


         if (interpolated() && fixingDate >= interpMustForecastOn) {
            return forecastFixing(fixingDate);
         }

         if (!interpolated() && fixingDate >= flatMustForecastOn) {
            return forecastFixing(fixingDate);
         }

         // four cases with ratio() and interpolated()
         if (ratio()) 
         {
            if(interpolated())
            {
               // IS ratio, IS interpolated
               KeyValuePair<Date,Date> lim = Utils.inflationPeriod(fixingDate, frequency_);
               Date fixMinus1Y= new NullCalendar().advance(fixingDate, new Period(-1,TimeUnit.Years),BusinessDayConvention.ModifiedFollowing);
               KeyValuePair<Date,Date> limBef = Utils.inflationPeriod(fixMinus1Y, frequency_);
               double dp= lim.Value + 1 - lim.Key;
               double dpBef=limBef.Value + 1 - limBef.Key;
               double dl = fixingDate-lim.Key;
                // potentially does not work on 29th Feb
                double dlBef = fixMinus1Y - limBef.Key;
                // get the four relevant fixings
                // recall that they are stored flat for every day
                double limFirstFix =
                IndexManager.instance().getHistory(name()).value()[lim.Key];
                if( limFirstFix == null)
                   throw new ApplicationException("Missing " + name() + " fixing for "
                                                  + lim.Key );
                double limSecondFix =
                IndexManager.instance().getHistory(name()).value()[lim.Value+1];
                if ( limSecondFix == null )
                   throw new ApplicationException("Missing " + name() + " fixing for "
                                                  + lim.Value+1 );
                double limBefFirstFix =
                IndexManager.instance().getHistory(name()).value()[limBef.Key];
                if ( limBefFirstFix == null )
                   throw new ApplicationException("Missing " + name() + " fixing for "
                                                  + limBef.Key );
                double limBefSecondFix =
                IndexManager.instance().getHistory(name()).value()[limBef.Value+1];
                if ( limBefSecondFix == null )
                   throw new ApplicationException("Missing " + name() + " fixing for "
                                                  + limBef.Value+1 );

                double linearNow = limFirstFix + (limSecondFix-limFirstFix)*dl/dp;
                double linearBef = limBefFirstFix + (limBefSecondFix-limBefFirstFix)*dlBef/dpBef;
                double wasYES = linearNow / linearBef - 1.0;

                return wasYES;

            } 
            else 
            {    
               // IS ratio, NOT interpolated
               double pastFixing =
                    IndexManager.instance().getHistory(name()).value()[fixingDate];
               if ( pastFixing == null )
                  throw new ApplicationException("Missing " + name() + " fixing for "
                                                 + fixingDate);
                Date previousDate = fixingDate - new Period(1,TimeUnit.Years);
                double previousFixing =
                IndexManager.instance().getHistory(name()).value()[previousDate];
                if( previousFixing == null )
                   throw new ApplicationException("Missing " + name() + " fixing for "
                                                  + previousDate );

                return pastFixing/previousFixing - 1.0;
            }
         } 
         else 
         {  
            // NOT ratio
            if (interpolated()) 
            { 
               // NOT ratio, IS interpolated
                KeyValuePair<Date,Date> lim = Utils.inflationPeriod(fixingDate, frequency_);
                double dp= lim.Value + 1 - lim.Key;
                double dl = fixingDate-lim.Key;
                double limFirstFix =
                IndexManager.instance().getHistory(name()).value()[lim.Key];
                if ( limFirstFix == null )
                   throw new ApplicationException("Missing " + name() + " fixing for "
                                                  + lim.Key );
                double limSecondFix =
                IndexManager.instance().getHistory(name()).value()[lim.Value+1];
                if ( limSecondFix == null )
                   throw new ApplicationException("Missing " + name() + " fixing for "
                                                  + lim.Value+1 );
                double linearNow = limFirstFix + (limSecondFix-limFirstFix)*dl/dp;

                return linearNow;

            } 
            else 
            { 
               // NOT ratio, NOT interpolated
               // so just flat
                double pastFixing =
                    IndexManager.instance().getHistory(name()).value()[fixingDate];
                if ( pastFixing == null ) 
                   throw new ApplicationException("Missing " + name() + " fixing for "
                                                  + fixingDate);
                return pastFixing;

            }
         }

         // QL_FAIL("YoYInflationIndex::fixing, should never get here");

        }
Beispiel #17
0
        static void Main(string[] args)
        {
            DateTime timer = DateTime.Now;

            Date repoSettlementDate = new Date(14,Month.February,2000);;
            Date repoDeliveryDate = new Date(15,Month.August,2000);
            double repoRate = 0.05;
            DayCounter repoDayCountConvention = new Actual360();
            int repoSettlementDays = 0;
            Compounding repoCompounding = Compounding.Simple;
            Frequency repoCompoundFreq = Frequency.Annual;

            // assume a ten year bond- this is irrelevant
            Date bondIssueDate = new Date(15,Month.September,1995);
            Date bondDatedDate = new Date(15,Month.September,1995);
            Date bondMaturityDate = new Date(15,Month.September,2005);
            double bondCoupon = 0.08;
            Frequency bondCouponFrequency = Frequency.Semiannual;
            // unknown what calendar fincad is using
            Calendar bondCalendar = new NullCalendar();
            DayCounter bondDayCountConvention = new Thirty360(Thirty360.Thirty360Convention.BondBasis);
            // unknown what fincad is using. this may affect accrued calculation
            int bondSettlementDays = 0;
            BusinessDayConvention bondBusinessDayConvention = BusinessDayConvention.Unadjusted;
            double bondCleanPrice = 89.97693786;
            double bondRedemption = 100.0;
            double faceAmount = 100.0;

            Settings.setEvaluationDate(repoSettlementDate);

            RelinkableHandle<YieldTermStructure> bondCurve = new RelinkableHandle<YieldTermStructure>();
            bondCurve.linkTo(new FlatForward(repoSettlementDate,
                                               .01, // dummy rate
                                               bondDayCountConvention,
                                               Compounding.Compounded,
                                               bondCouponFrequency));

            /*
            boost::shared_ptr<FixedRateBond> bond(
                           new FixedRateBond(faceAmount,
                                             bondIssueDate,
                                             bondDatedDate,
                                             bondMaturityDate,
                                             bondSettlementDays,
                                             std::vector<Rate>(1,bondCoupon),
                                             bondCouponFrequency,
                                             bondCalendar,
                                             bondDayCountConvention,
                                             bondBusinessDayConvention,
                                             bondBusinessDayConvention,
                                             bondRedemption,
                                             bondCurve));
            */

            Schedule bondSchedule = new Schedule(bondDatedDate, bondMaturityDate,
                                  new Period(bondCouponFrequency),
                                  bondCalendar,bondBusinessDayConvention,
                                  bondBusinessDayConvention,
                                  DateGeneration.Rule.Backward,false);
            FixedRateBond bond = new FixedRateBond(bondSettlementDays,
                                             faceAmount,
                                             bondSchedule,
                                             new List<double>() { bondCoupon },
                                             bondDayCountConvention,
                                             bondBusinessDayConvention,
                                             bondRedemption,
                                             bondIssueDate);
            bond.setPricingEngine(new DiscountingBondEngine(bondCurve));

            bondCurve.linkTo(new FlatForward(repoSettlementDate,
                                       bond.yield(bondCleanPrice,
                                                   bondDayCountConvention,
                                                   Compounding.Compounded,
                                                   bondCouponFrequency),
                                       bondDayCountConvention,
                                       Compounding.Compounded,
                                       bondCouponFrequency));

            Position.Type fwdType = Position.Type.Long;
            double dummyStrike = 91.5745;

            RelinkableHandle<YieldTermStructure> repoCurve = new RelinkableHandle<YieldTermStructure>();
            repoCurve.linkTo(new FlatForward(repoSettlementDate,
                                               repoRate,
                                               repoDayCountConvention,
                                               repoCompounding,
                                               repoCompoundFreq));

            FixedRateBondForward bondFwd = new FixedRateBondForward(repoSettlementDate,
                                         repoDeliveryDate,
                                         fwdType,
                                         dummyStrike,
                                         repoSettlementDays,
                                         repoDayCountConvention,
                                         bondCalendar,
                                         bondBusinessDayConvention,
                                         bond,
                                         repoCurve,
                                         repoCurve);

            Console.WriteLine("Underlying bond clean price: " + bond.cleanPrice());
            Console.WriteLine("Underlying bond dirty price: " + bond.dirtyPrice());
            Console.WriteLine("Underlying bond accrued at settlement: "
                 + bond.accruedAmount(repoSettlementDate));
            Console.WriteLine("Underlying bond accrued at delivery:   "
                 + bond.accruedAmount(repoDeliveryDate));
            Console.WriteLine("Underlying bond spot income: "
                 + bondFwd.spotIncome(repoCurve));
            Console.WriteLine("Underlying bond fwd income:  "
                 + bondFwd.spotIncome(repoCurve)/
                    repoCurve.link.discount(repoDeliveryDate));
            Console.WriteLine("Repo strike: " + dummyStrike);
            Console.WriteLine("Repo NPV:    " + bondFwd.NPV());
            Console.WriteLine("Repo clean forward price: "
                 + bondFwd.cleanForwardPrice());
            Console.WriteLine("Repo dirty forward price: "
                 + bondFwd.forwardPrice());
            Console.WriteLine("Repo implied yield: "
                 + bondFwd.impliedYield(bond.dirtyPrice(),
                                         dummyStrike,
                                         repoSettlementDate,
                                         repoCompounding,
                                         repoDayCountConvention));
            Console.WriteLine("Market repo rate:   "
                 + repoCurve.link.zeroRate(repoDeliveryDate,
                                        repoDayCountConvention,
                                        repoCompounding,
                                        repoCompoundFreq));

            Console.WriteLine("\nCompare with example given at \n"
                 + "http://www.fincad.com/support/developerFunc/mathref/BFWD.htm");
            Console.WriteLine("Clean forward price = 88.2408");
            Console.WriteLine("\nIn that example, it is unknown what bond calendar they are\n"
                 + "using, as well as settlement Days. For that reason, I have\n"
                 + "made the simplest possible assumptions here: NullCalendar\n"
                 + "and 0 settlement days.\n");

            Console.WriteLine("nRun completed in {0}", DateTime.Now - timer);

              Console.Write("Press any key to continue ...");
              Console.ReadKey();
        }
Beispiel #18
0
        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_);
            }
        }