Пример #1
0
        //! returns the spreaded zero yield rate
        protected override double zeroYieldImpl(double t)
        {
            // to be fixed: user-defined daycounter should be used
            InterestRate zeroRate =
                originalCurve_.link.zeroRate(t, comp_, freq_, true);
            InterestRate spreadedRate = new InterestRate(zeroRate.value() + spread_.link.value(),
                                                         zeroRate.dayCounter(),
                                                         zeroRate.compounding(),
                                                         zeroRate.frequency());

            return(spreadedRate.equivalentRate(Compounding.Continuous, Frequency.NoFrequency, t).value());
        }
Пример #2
0
        public void testConversions()
        {
            InterestRateData[] cases =
            {
                // data from "Option Pricing Formulas", Haug, pag.181-182
                // Rate,Compounding,        Frequency,   Time, Compounding2,      Frequency2,  Rate2, precision
                new InterestRateData(0.0800, Compounding.Compounded,           Frequency.Quarterly,            1.00, Compounding.Continuous,           Frequency.Annual,           0.0792, 4),
                new InterestRateData(0.1200, Compounding.Continuous,           Frequency.Annual,               1.00, Compounding.Compounded,           Frequency.Annual,           0.1275, 4),
                new InterestRateData(0.0800, Compounding.Compounded,           Frequency.Quarterly,            1.00, Compounding.Compounded,           Frequency.Annual,           0.0824, 4),
                new InterestRateData(0.0700, Compounding.Compounded,           Frequency.Quarterly,            1.00, Compounding.Compounded,           Frequency.Semiannual,       0.0706, 4),
                // undocumented, but reasonable :)
                new InterestRateData(0.0100, Compounding.Compounded,           Frequency.Annual,               1.00, Compounding.Simple,               Frequency.Annual,           0.0100, 4),
                new InterestRateData(0.0200, Compounding.Simple,               Frequency.Annual,               1.00, Compounding.Compounded,           Frequency.Annual,           0.0200, 4),
                new InterestRateData(0.0300, Compounding.Compounded,           Frequency.Semiannual,           0.50, Compounding.Simple,               Frequency.Annual,           0.0300, 4),
                new InterestRateData(0.0400, Compounding.Simple,               Frequency.Annual,               0.50, Compounding.Compounded,           Frequency.Semiannual,       0.0400, 4),
                new InterestRateData(0.0500, Compounding.Compounded,           Frequency.EveryFourthMonth,  1.0 / 3, Compounding.Simple,               Frequency.Annual,           0.0500, 4),
                new InterestRateData(0.0600, Compounding.Simple,               Frequency.Annual,            1.0 / 3, Compounding.Compounded,           Frequency.EveryFourthMonth, 0.0600, 4),
                new InterestRateData(0.0500, Compounding.Compounded,           Frequency.Quarterly,            0.25, Compounding.Simple,               Frequency.Annual,           0.0500, 4),
                new InterestRateData(0.0600, Compounding.Simple,               Frequency.Annual,               0.25, Compounding.Compounded,           Frequency.Quarterly,        0.0600, 4),
                new InterestRateData(0.0700, Compounding.Compounded,           Frequency.Bimonthly,         1.0 / 6, Compounding.Simple,               Frequency.Annual,           0.0700, 4),
                new InterestRateData(0.0800, Compounding.Simple,               Frequency.Annual,            1.0 / 6, Compounding.Compounded,           Frequency.Bimonthly,        0.0800, 4),
                new InterestRateData(0.0900, Compounding.Compounded,           Frequency.Monthly,          1.0 / 12, Compounding.Simple,               Frequency.Annual,           0.0900, 4),
                new InterestRateData(0.1000, Compounding.Simple,               Frequency.Annual,           1.0 / 12, Compounding.Compounded,           Frequency.Monthly,          0.1000, 4),

                new InterestRateData(0.0300, Compounding.SimpleThenCompounded, Frequency.Semiannual,           0.25, Compounding.Simple,               Frequency.Annual,           0.0300, 4),
                new InterestRateData(0.0300, Compounding.SimpleThenCompounded, Frequency.Semiannual,           0.25, Compounding.Simple,               Frequency.Semiannual,       0.0300, 4),
                new InterestRateData(0.0300, Compounding.SimpleThenCompounded, Frequency.Semiannual,           0.25, Compounding.Simple,               Frequency.Quarterly,        0.0300, 4),
                new InterestRateData(0.0300, Compounding.SimpleThenCompounded, Frequency.Semiannual,           0.50, Compounding.Simple,               Frequency.Annual,           0.0300, 4),
                new InterestRateData(0.0300, Compounding.SimpleThenCompounded, Frequency.Semiannual,           0.50, Compounding.Simple,               Frequency.Semiannual,       0.0300, 4),
                new InterestRateData(0.0300, Compounding.SimpleThenCompounded, Frequency.Semiannual,           0.75, Compounding.Compounded,           Frequency.Semiannual,       0.0300, 4),

                new InterestRateData(0.0400, Compounding.Simple,               Frequency.Semiannual,           0.25, Compounding.SimpleThenCompounded, Frequency.Quarterly,        0.0400, 4),
                new InterestRateData(0.0400, Compounding.Simple,               Frequency.Semiannual,           0.25, Compounding.SimpleThenCompounded, Frequency.Semiannual,       0.0400, 4),
                new InterestRateData(0.0400, Compounding.Simple,               Frequency.Semiannual,           0.25, Compounding.SimpleThenCompounded, Frequency.Annual,           0.0400, 4),

                new InterestRateData(0.0400, Compounding.Compounded,           Frequency.Quarterly,            0.50, Compounding.SimpleThenCompounded, Frequency.Quarterly,        0.0400, 4),
                new InterestRateData(0.0400, Compounding.Simple,               Frequency.Semiannual,           0.50, Compounding.SimpleThenCompounded, Frequency.Semiannual,       0.0400, 4),
                new InterestRateData(0.0400, Compounding.Simple,               Frequency.Semiannual,           0.50, Compounding.SimpleThenCompounded, Frequency.Annual,           0.0400, 4),

                new InterestRateData(0.0400, Compounding.Compounded,           Frequency.Quarterly,            0.75, Compounding.SimpleThenCompounded, Frequency.Quarterly,        0.0400, 4),
                new InterestRateData(0.0400, Compounding.Compounded,           Frequency.Semiannual,           0.75, Compounding.SimpleThenCompounded, Frequency.Semiannual,       0.0400, 4),
                new InterestRateData(0.0400, Compounding.Simple,               Frequency.Semiannual,           0.75, Compounding.SimpleThenCompounded, Frequency.Annual,           0.0400, 4)
            };

            Rounding     roundingPrecision;
            double       r3;
            double       r2;
            Date         d1 = Date.Today;
            Date         d2;
            InterestRate ir;
            InterestRate ir2;
            InterestRate ir3;
            InterestRate expectedIR;
            double       compoundf;
            double       error;
            double       disc;

            for (int i = 0; i < cases.Length - 1; i++)
            {
                ir = new InterestRate(cases[i].r, new Actual360(), cases[i].comp, cases[i].freq);
                d2 = d1 + new Period((int)(360 * cases[i].t + 0.5), TimeUnit.Days);
                roundingPrecision = new Rounding(cases[i].precision);

                // check that the compound factor is the inverse of the discount factor
                compoundf = ir.compoundFactor(d1, d2);
                disc      = ir.discountFactor(d1, d2);
                error     = Math.Abs(disc - 1.0 / compoundf);
                if (error > 1e-15)
                {
                    QAssert.Fail(ir + "  1.0/compound_factor: " + 1.0 / compoundf);
                }

                // check that the equivalent InterestRate with *same* daycounter,
                // compounding, and frequency is the *same* InterestRate
                //ir2 = ir.equivalentRate(d1, d2, ir.dayCounter(), ir.compounding(), ir.frequency());
                ir2   = ir.equivalentRate(ir.dayCounter(), ir.compounding(), ir.frequency(), d1, d2);
                error = Math.Abs(ir.rate() - ir2.rate());
                if (error > 1e-15)
                {
                    QAssert.Fail("original interest rate: " + ir + " equivalent interest rate: " + ir2 + " rate error: " + error);
                }
                if (ir.dayCounter() != ir2.dayCounter())
                {
                    QAssert.Fail("day counter error original interest rate: " + ir + " equivalent interest rate: " + ir2);
                }
                if (ir.compounding() != ir2.compounding())
                {
                    QAssert.Fail("compounding error original interest rate: " + ir + " equivalent interest rate: " + ir2);
                }
                if (ir.frequency() != ir2.frequency())
                {
                    QAssert.Fail("frequency error original interest rate: " + ir + " equivalent interest rate: " + ir2);
                }

                // check that the equivalent rate with *same* daycounter,
                // compounding, and frequency is the *same* rate
                //r2 = ir.equivalentRate(d1, d2, ir.dayCounter(), ir.compounding(), ir.frequency()).rate();
                r2    = ir.equivalentRate(ir.dayCounter(), ir.compounding(), ir.frequency(), d1, d2).value();
                error = Math.Abs(ir.rate() - r2);
                if (error > 1e-15)
                {
                    QAssert.Fail("original rate: " + ir + " equivalent rate: " + r2 + " error: " + error);
                }

                // check that the equivalent InterestRate with *different*
                // compounding, and frequency is the *expected* InterestRate
                //ir3 = ir.equivalentRate(d1, d2, ir.dayCounter(), cases[i].comp2, cases[i].freq2);
                ir3        = ir.equivalentRate(ir.dayCounter(), cases[i].comp2, cases[i].freq2, d1, d2);
                expectedIR = new InterestRate(cases[i].expected, ir.dayCounter(), cases[i].comp2, cases[i].freq2);
                r3         = roundingPrecision.Round(ir3.rate());
                error      = Math.Abs(r3 - expectedIR.rate());
                if (error > 1.0e-17)
                {
                    QAssert.Fail("original interest rate: " + ir + " calculated equivalent interest rate: " + ir3 + " truncated equivalent rate: " + r3 + " expected equivalent interest rate: " + expectedIR + " rate error: " + error);
                }
                if (ir3.dayCounter() != expectedIR.dayCounter())
                {
                    QAssert.Fail("day counter error original interest rate: " + ir3 + " equivalent interest rate: " + expectedIR);
                }
                if (ir3.compounding() != expectedIR.compounding())
                {
                    QAssert.Fail("compounding error original interest rate: " + ir3 + " equivalent interest rate: " + expectedIR);
                }
                if (ir3.frequency() != expectedIR.frequency())
                {
                    QAssert.Fail("frequency error original interest rate: " + ir3 + " equivalent interest rate: " + expectedIR);
                }

                // check that the equivalent rate with *different*
                // compounding, and frequency is the *expected* rate
                //r3 = ir.equivalentRate(d1, d2, ir.dayCounter(), cases[i].comp2, cases[i].freq2).rate();
                r3    = ir.equivalentRate(ir.dayCounter(), cases[i].comp2, cases[i].freq2, d1, d2).value();
                r3    = roundingPrecision.Round(r3);
                error = Math.Abs(r3 - cases[i].expected);
                if (error > 1.0e-17)
                {
                    QAssert.Fail("calculated equivalent rate: " + r3 + " expected equivalent rate: " + cases[i].expected + " error: " + error);
                }
            }
        }
Пример #3
0
        private void BuildDiscountCurve()
        {
            Utils.QL_REQUIRE(_curveSegments.Count <= 1, () => "More than one zero curve segment not supported yet.");
            Utils.QL_REQUIRE(_curveSegments[0].CurveSegmentType() == YieldCurveSegment.Type.Zero, () => "The curve segment is not of type Zero.");

            // Fill a vector of zero quotes.
            List <ZeroQuote>        zeroQuotes       = new List <ZeroQuote>();
            DirectYieldCurveSegment zeroCurveSegment = _curveSegments[0] as DirectYieldCurveSegment;

            List <string> zeroQuoteIDs = zeroCurveSegment.Quotes();

            for (int i = 0; i < zeroQuoteIDs.Count; ++i)
            {
                MarketDatum marketQuote = _loader.Get(zeroQuoteIDs[i], _asofDate);
                if (marketQuote != null)
                {
                    Utils.QL_REQUIRE(marketQuote.GetInstrumentType() == MarketDatum.InstrumentType.ZERO, () => "Market quote not of type zero.");
                    ZeroQuote zeroQuote = marketQuote as ZeroQuote;
                    zeroQuotes.Add(zeroQuote);
                }
                else
                {
                    Utils.QL_FAIL("Could not find quote for ID " + zeroQuoteIDs[i] + " with as of date " + _asofDate + ".");
                }
            }

            // Create the (date, zero) pairs.
            Dictionary <Date, double> data = new Dictionary <Date, double>();
            Convention convention          = _conventions.Get(_curveSegments[0].ConventionsID());

            Utils.QL_REQUIRE(convention != null, () => "No conventions found with ID: " + _curveSegments[0].ConventionsID());
            Utils.QL_REQUIRE(convention.ConventionType() == Convention.Type.Zero, () => "Conventions ID does not give zero rate conventions.");
            ZeroRateConvention zeroConvention  = convention as ZeroRateConvention;
            DayCounter         quoteDayCounter = zeroConvention.DayCounter();

            for (int i = 0; i < zeroQuotes.Count; ++i)
            {
                Utils.QL_REQUIRE(quoteDayCounter == zeroQuotes[i].DayCounter(), () => "The day counter should be the same between the conventions and the quote.");

                if (!zeroQuotes[i].TenorBased())
                {
                    data[zeroQuotes[i].Date()] = zeroQuotes[i].Quote().link.value();
                }
                else
                {
                    Utils.QL_REQUIRE(zeroConvention.TenorBased(), () => "Using tenor based zero rates without tenor based zero rate conventions.");


                    Date zeroDate = _asofDate;
                    if (zeroConvention.SpotLag() > 0)
                    {
                    }

                    zeroDate       = zeroConvention.SpotCalendar().advance(zeroDate, new Period(zeroConvention.SpotLag(), TimeUnit.Days));
                    zeroDate       = zeroConvention.TenorCalendar().advance(zeroDate, zeroQuotes[i].Tenor(), zeroConvention.RollConvention(), zeroConvention.Eom());
                    data[zeroDate] = zeroQuotes[i].Quote().link.value();
                }
            }

            Utils.QL_REQUIRE(data.Count > 0, () => "No market data found for curve spec " + _curveSpec.Name() + " with as of date " + _asofDate);


            // \todo review - more flexible (flat vs. linear extrap)?
            if (data.Keys.First() > _asofDate)
            {
                double rate = data.Values.First();
                data[_asofDate] = rate;
                //LOG("Insert zero curve point at time zero for " + curveSpec_.name() + ": "+ "date " + _asofDate + ", "+"zero " + data[_asofDate]);
            }

            Utils.QL_REQUIRE(data.Count > 1, () => "The single zero rate quote provided should be associated with a date greater than as of date.");

            // First build temporary curves
            List <Date>   dates     = new List <Date>();
            List <double> zeroes    = new List <double>();
            List <double> discounts = new List <double>();

            dates.Add(data.Keys.First());
            zeroes.Add(data.Values.First());
            discounts.Add(1.0);

            Compounding zeroCompounding     = zeroConvention.Compounding();
            Frequency   zeroCompoundingFreq = zeroConvention.CompoundingFrequency();
            Dictionary <Date, double> it;

            foreach (KeyValuePair <Date, double> kvp in data)
            {
                Date   d = kvp.Key;
                double r = kvp.Value;

                dates.Add(d);
                InterestRate tempRate = new InterestRate(r, quoteDayCounter, zeroCompounding, zeroCompoundingFreq);
                double       t        = quoteDayCounter.yearFraction(_asofDate, d);
                /* Convert zero rate to continuously compounded if necessary */
                if (zeroCompounding == Compounding.Continuous)
                {
                    zeroes.Add(r);
                }
                else
                {
                    zeroes.Add(tempRate.equivalentRate(Compounding.Continuous, Frequency.Annual, t).value());
                }
                discounts.Add(tempRate.discountFactor(t));
                //LOG("Add zero curve point for " + curveSpec_.name() + ": " + dates.Last() + " " + zeroes.Last() + " / " + discounts.Last());
            }

            Utils.QL_REQUIRE(dates.Count == zeroes.Count, () => "Date and zero vectors differ in size.");
            Utils.QL_REQUIRE(dates.Count == discounts.Count, () => "Date and discount vectors differ in size.");

            // Now build curve with requested conventions
            if (_interpolationVariable == YieldCurve.InterpolationVariable.Zero)
            {
                YieldTermStructure tempCurve = Zerocurve(dates, zeroes, quoteDayCounter);
                zeroes.Clear();
                for (int i = 0; i < dates.Count; ++i)
                {
                    double zero = tempCurve.zeroRate(dates[i], _zeroDayCounter, Compounding.Continuous).value();
                    zeroes.Add(zero);
                }

                _p = Zerocurve(dates, zeroes, _zeroDayCounter);
            }
            else if (_interpolationVariable == YieldCurve.InterpolationVariable.Discount)
            {
                YieldTermStructure tempCurve = Discountcurve(dates, discounts, quoteDayCounter);
                discounts.Clear();
                for (int i = 0; i < dates.Count; ++i)
                {
                    double discount = tempCurve.discount(dates[i]);
                    discounts.Add(discount);
                }
                _p = Discountcurve(dates, discounts, _zeroDayCounter);
            }
            else
            {
                Utils.QL_FAIL("Unknown yield curve interpolation variable.");
            }
        }