public void testInstrumentEquality()
        {
            // Testing inflation capped/floored coupon against inflation capfloor instrument...

            CommonVars vars = new CommonVars();

            int[] lengths = { 1, 2, 3, 5, 7, 10, 15, 20 };
            // vol is low ...
            double[] strikes = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 };
            // yoy inflation vol is generally very low
            double[] vols = { 0.001, 0.005, 0.010, 0.015, 0.020 };

            // this is model independent
            // capped coupon = fwd - cap, and fwd = swap(0)
            // floored coupon = fwd + floor
            for (int whichPricer = 0; whichPricer < 3; whichPricer++)
            {
                for (int i = 0; i < lengths.Length; i++)
                {
                    for (int j = 0; j < strikes.Length; j++)
                    {
                        for (int k = 0; k < vols.Length; k++)
                        {
                            List <CashFlow> leg = vars.makeYoYLeg(vars.evaluationDate, lengths[i]);

                            Instrument cap = vars.makeYoYCapFloor(CapFloorType.Cap,
                                                                  leg, strikes[j], vols[k], whichPricer);

                            Instrument floor = vars.makeYoYCapFloor(CapFloorType.Floor,
                                                                    leg, strikes[j], vols[k], whichPricer);

                            Date     from        = vars.nominalTS.link.referenceDate();
                            Date     to          = from + new Period(lengths[i], TimeUnit.Years);
                            Schedule yoySchedule = new MakeSchedule().from(from).to(to)
                                                   .withTenor(new Period(1, TimeUnit.Years))
                                                   .withCalendar(new UnitedKingdom())
                                                   .withConvention(BusinessDayConvention.Unadjusted)
                                                   .backwards().value();

                            YearOnYearInflationSwap swap = new YearOnYearInflationSwap(YearOnYearInflationSwap.Type.Payer,
                                                                                       1000000.0,
                                                                                       yoySchedule, //fixed schedule, but same as yoy
                                                                                       0.0,         //strikes[j],
                                                                                       vars.dc,
                                                                                       yoySchedule,
                                                                                       vars.iir,
                                                                                       vars.observationLag,
                                                                                       0.0, //spread on index
                                                                                       vars.dc,
                                                                                       new UnitedKingdom());

                            Handle <YieldTermStructure> hTS = new Handle <YieldTermStructure>(vars.nominalTS);
                            IPricingEngine sppe             = new DiscountingSwapEngine(hTS);
                            swap.setPricingEngine(sppe);

                            List <CashFlow> leg2 = vars.makeYoYCapFlooredLeg(whichPricer, from,
                                                                             lengths[i],
                                                                             new InitializedList <double?>(lengths[i], strikes[j]), //cap
                                                                             new List <double?>(),                                  //floor
                                                                             vols[k],
                                                                             1.0,                                                   // gearing
                                                                             0.0);                                                  // spread

                            List <CashFlow> leg3 = vars.makeYoYCapFlooredLeg(whichPricer, from,
                                                                             lengths[i],
                                                                             new List <double?>(),                                  // cap
                                                                             new InitializedList <double?>(lengths[i], strikes[j]), //floor
                                                                             vols[k],
                                                                             1.0,                                                   // gearing
                                                                             0.0);                                                  // spread

                            // N.B. nominals are 10e6
                            double capped = CashFlows.npv(leg2, vars.nominalTS, false);
                            if (Math.Abs(capped - (swap.NPV() - cap.NPV())) > 1.0e-6)
                            {
                                QAssert.Fail(
                                    "capped coupon != swap(0) - cap:\n"
                                    + "    length:      " + lengths[i] + " years\n"
                                    + "    volatility:  " + vols[k] + "\n"
                                    + "    strike:      " + strikes[j] + "\n"
                                    + "    cap value:   " + cap.NPV() + "\n"
                                    + "    swap value:  " + swap.NPV() + "\n"
                                    + "   capped coupon " + capped);
                            }


                            // N.B. nominals are 10e6
                            double floored = CashFlows.npv(leg3, vars.nominalTS, false);
                            if (Math.Abs(floored - (swap.NPV() + floor.NPV())) > 1.0e-6)
                            {
                                QAssert.Fail(
                                    "floored coupon != swap(0) + floor :\n"
                                    + "    length:      " + lengths[i] + " years\n"
                                    + "    volatility:  " + vols[k] + "\n"
                                    + "    strike:      " + strikes[j] + "\n"
                                    + "    floor value: " + floor.NPV() + "\n"
                                    + "    swap value:  " + swap.NPV() + "\n"
                                    + "  floored coupon " + floored);
                            }
                        }
                    }
                }
            }
            // remove circular refernce
            vars.hy.linkTo(null);
        }
        public void testMonteCarloCapletPricing()
        {
            // Testing caplet LMM Monte-Carlo caplet pricing

            /* factor loadings are taken from Hull & White article
             * plus extra normalisation to get orthogonal eigenvectors
             * http://www.rotman.utoronto.ca/~amackay/fin/libormktmodel2.pdf */
            double[] compValues = { 0.85549771,  0.46707264,  0.22353259,
                                    0.91915359,  0.37716089,  0.11360610,
                                    0.96438280,  0.26413316, -0.01412414,
                                    0.97939148,  0.13492952, -0.15028753,
                                    0.95970595, -0.00000000, -0.28100621,
                                    0.97939148, -0.13492952, -0.15028753,
                                    0.96438280, -0.26413316, -0.01412414,
                                    0.91915359, -0.37716089,  0.11360610,
                                    0.85549771, -0.46707264, 0.22353259 };

            Matrix        volaComp    = new Matrix(9, 3);
            List <double> lcompValues = new InitializedList <double>(27, 0);
            List <double> ltemp       = new InitializedList <double>(3, 0);

            lcompValues = compValues.ToList();
            //std::copy(compValues, compValues+9*3, volaComp.begin());
            for (int i = 0; i < 9; i++)
            {
                ltemp = lcompValues.GetRange(3 * i, 3);
                for (int j = 0; j < 3; j++)
                {
                    volaComp[i, j] = ltemp[j];
                }
            }
            LiborForwardModelProcess process1 = makeProcess();
            LiborForwardModelProcess process2 = makeProcess(volaComp);

            List <double> tmp  = process1.fixingTimes();
            TimeGrid      grid = new TimeGrid(tmp, tmp.Count, 12);

            List <int> location = new List <int>();

            for (int i = 0; i < tmp.Count; ++i)
            {
                location.Add(grid.index(tmp[i]));
            }

            // set-up a small Monte-Carlo simulation to price caplets
            // and ratchet caps using a one- and a three factor libor market model

            ulong seed = 42;

            LowDiscrepancy.icInstance = new InverseCumulativeNormal();
            IRNG rsg1 = (IRNG) new LowDiscrepancy().make_sequence_generator(
                process1.factors() * (grid.size() - 1), seed);
            IRNG rsg2 = (IRNG) new LowDiscrepancy().make_sequence_generator(
                process2.factors() * (grid.size() - 1), seed);

            MultiPathGenerator <IRNG> generator1 = new MultiPathGenerator <IRNG> (process1, grid, rsg1, false);
            MultiPathGenerator <IRNG> generator2 = new MultiPathGenerator <IRNG> (process2, grid, rsg2, false);

            const int nrTrails             = 250000;
            List <GeneralStatistics> stat1 = new InitializedList <GeneralStatistics>(process1.size());
            List <GeneralStatistics> stat2 = new InitializedList <GeneralStatistics>(process2.size());
            List <GeneralStatistics> stat3 = new InitializedList <GeneralStatistics>(process2.size() - 1);

            for (int i = 0; i < nrTrails; ++i)
            {
                Sample <IPath> path1  = generator1.next();
                Sample <IPath> path2  = generator2.next();
                MultiPath      value1 = path1.value as MultiPath;
                Utils.QL_REQUIRE(value1 != null, () => "Invalid Path");
                MultiPath value2 = path2.value as MultiPath;
                Utils.QL_REQUIRE(value2 != null, () => "Invalid Path");

                List <double> rates1 = new InitializedList <double>(len);
                List <double> rates2 = new InitializedList <double>(len);
                for (int j = 0; j < process1.size(); ++j)
                {
                    rates1[j] = value1[j][location[j]];
                    rates2[j] = value2[j][location[j]];
                }

                List <double> dis1 = process1.discountBond(rates1);
                List <double> dis2 = process2.discountBond(rates2);

                for (int k = 0; k < process1.size(); ++k)
                {
                    double accrualPeriod = process1.accrualEndTimes()[k]
                                           - process1.accrualStartTimes()[k];
                    // caplet payoff function, cap rate at 4%
                    double payoff1 = Math.Max(rates1[k] - 0.04, 0.0) * accrualPeriod;

                    double payoff2 = Math.Max(rates2[k] - 0.04, 0.0) * accrualPeriod;
                    stat1[k].add(dis1[k] * payoff1);
                    stat2[k].add(dis2[k] * payoff2);

                    if (k != 0)
                    {
                        // ratchet cap payoff function
                        double payoff3 = Math.Max(rates2[k] - (rates2[k - 1] + 0.0025), 0.0)
                                         * accrualPeriod;
                        stat3[k - 1].add(dis2[k] * payoff3);
                    }
                }
            }

            double[] capletNpv = { 0.000000000000, 0.000002841629, 0.002533279333,
                                   0.009577143571, 0.017746502618, 0.025216116835,
                                   0.031608230268, 0.036645683881, 0.039792254012,
                                   0.041829864365 };

            double[] ratchetNpv = { 0.0082644895, 0.0082754754, 0.0082159966,
                                    0.0082982822, 0.0083803357, 0.0084366961,
                                    0.0084173270, 0.0081803406, 0.0079533814 };

            for (int k = 0; k < process1.size(); ++k)
            {
                double calculated1 = stat1[k].mean();
                double tolerance1  = stat1[k].errorEstimate();
                double expected    = capletNpv[k];

                if (Math.Abs(calculated1 - expected) > tolerance1)
                {
                    QAssert.Fail("Failed to reproduce expected caplet NPV"
                                 + "\n    calculated: " + calculated1
                                 + "\n    error int:  " + tolerance1
                                 + "\n    expected:   " + expected);
                }

                double calculated2 = stat2[k].mean();
                double tolerance2  = stat2[k].errorEstimate();

                if (Math.Abs(calculated2 - expected) > tolerance2)
                {
                    QAssert.Fail("Failed to reproduce expected caplet NPV"
                                 + "\n    calculated: " + calculated2
                                 + "\n    error int:  " + tolerance2
                                 + "\n    expected:   " + expected);
                }

                if (k != 0)
                {
                    double calculated3 = stat3[k - 1].mean();
                    double tolerance3  = stat3[k - 1].errorEstimate();
                    expected = ratchetNpv[k - 1];

                    double refError = 1e-5; // 1e-5. error bars of the reference values

                    if (Math.Abs(calculated3 - expected) > tolerance3 + refError)
                    {
                        QAssert.Fail("Failed to reproduce expected caplet NPV"
                                     + "\n    calculated: " + calculated3
                                     + "\n    error int:  " + tolerance3 + refError
                                     + "\n    expected:   " + expected);
                    }
                }
            }
        }
Пример #3
0
        public void testHalton()
        {
            //("Testing Halton sequences...");

            List <double> point;
            double        tolerance = 1.0e-15;

            // testing "high" dimensionality
            int       dimensionality = (int)SobolRsg.PPMT_MAX_DIM;
            HaltonRsg rsg = new HaltonRsg(dimensionality, 0, false, false);
            int       points = 100, i, k;

            for (i = 0; i < points; i++)
            {
                point = rsg.nextSequence().value;
                if (point.Count != dimensionality)
                {
                    QAssert.Fail("Halton sequence generator returns " +
                                 " a sequence of wrong dimensionality: " + point.Count
                                 + " instead of  " + dimensionality)
                    ;
                }
            }

            // testing first and second dimension (van der Corput sequence)
            double[] vanderCorputSequenceModuloTwo   =
            {
                // first cycle (zero excluded)
                0.50000,
                // second cycle
                0.25000, 0.75000,
                // third cycle
                0.12500, 0.62500, 0.37500, 0.87500,
                // fourth cycle
                0.06250, 0.56250, 0.31250, 0.81250, 0.18750, 0.68750, 0.43750,
                0.93750,
                // fifth cycle
                0.03125, 0.53125, 0.28125, 0.78125, 0.15625, 0.65625, 0.40625,
                0.90625,
                0.09375, 0.59375, 0.34375, 0.84375, 0.21875, 0.71875, 0.46875,
                0.96875,
            };

            dimensionality = 1;
            rsg            = new HaltonRsg(dimensionality, 0, false, false);
            points         = (int)(Math.Pow(2.0, 5)) - 1; // five cycles
            for (i = 0; i < points; i++)
            {
                point = rsg.nextSequence().value;
                double error = Math.Abs(point[0] - vanderCorputSequenceModuloTwo[i]);
                if (error > tolerance)
                {
                    QAssert.Fail(i + 1 + " draw ("
                                 + /*QL_FIXED*/ +point[0]
                                 + ") in 1-D Halton sequence is not in the "
                                 + "van der Corput sequence modulo two: "
                                 + "it should have been "
                                 + vanderCorputSequenceModuloTwo[i]
                                 //+ QL_SCIENTIFIC
                                 + " (error = " + error + ")");
                }
            }

            double[] vanderCorputSequenceModuloThree =
            {
                // first cycle (zero excluded)
                1.0 / 3,    2.0 / 3,
                // second cycle
                1.0 / 9,    4.0 / 9,   7.0 / 9,  2.0 / 9,   5.0 / 9,   8.0 / 9,
                // third cycle
                1.0 / 27, 10.0 / 27, 19.0 / 27, 4.0 / 27, 13.0 / 27, 22.0 / 27,
                7.0 / 27, 16.0 / 27, 25.0 / 27, 2.0 / 27, 11.0 / 27, 20.0 / 27,
                5.0 / 27, 14.0 / 27, 23.0 / 27, 8.0 / 27, 17.0 / 27, 26.0 / 27
            };

            dimensionality = 2;
            rsg            = new HaltonRsg(dimensionality, 0, false, false);
            points         = (int)(Math.Pow(3.0, 3)) - 1; // three cycles of the higher dimension
            for (i = 0; i < points; i++)
            {
                point = rsg.nextSequence().value;
                double error = Math.Abs(point[0] - vanderCorputSequenceModuloTwo[i]);
                if (error > tolerance)
                {
                    QAssert.Fail("First component of " + i + 1
                                 + " draw (" + /*QL_FIXED*/ +point[0]
                                 + ") in 2-D Halton sequence is not in the "
                                 + "van der Corput sequence modulo two: "
                                 + "it should have been "
                                 + vanderCorputSequenceModuloTwo[i]
                                 //+ QL_SCIENTIFIC
                                 + " (error = " + error + ")");
                }
                error = Math.Abs(point[1] - vanderCorputSequenceModuloThree[i]);
                if (error > tolerance)
                {
                    QAssert.Fail("Second component of " + i + 1
                                 + " draw (" + /*QL_FIXED*/ +point[1]
                                 + ") in 2-D Halton sequence is not in the "
                                 + "van der Corput sequence modulo three: "
                                 + "it should have been "
                                 + vanderCorputSequenceModuloThree[i]
                                 //+ QL_SCIENTIFIC
                                 + " (error = " + error + ")");
                }
            }

            // testing homogeneity properties
            dimensionality = 33;
            rsg            = new HaltonRsg(dimensionality, 0, false, false);
            SequenceStatistics stat = new SequenceStatistics(dimensionality);
            List <double>      mean; //, stdev, variance, skewness, kurtosis;

            k = 0;
            int j;

            for (j = 1; j < 5; j++)
            {
                // five cycle
                points = (int)(Math.Pow(2.0, j)) - 1; // base 2
                for (; k < points; k++)
                {
                    point = rsg.nextSequence().value;
                    stat.add(point);
                }
                mean = stat.mean();
                double error = Math.Abs(mean[0] - 0.5);
                if (error > tolerance)
                {
                    QAssert.Fail("First dimension mean (" + /*QL_FIXED*/ +mean[0]
                                 + ") at the end of the " + j + 1
                                 + " cycle in Halton sequence is not " + 0.5
                                 //+ QL_SCIENTIFIC
                                 + " (error = " + error + ")");
                }
            }

            // reset generator and gaussianstatistics
            rsg = new HaltonRsg(dimensionality, 0, false, false);
            stat.reset(dimensionality);
            k = 0;
            for (j = 1; j < 3; j++)
            {
                // three cycle
                points = (int)(Math.Pow(3.0, j)) - 1; // base 3
                for (; k < points; k++)
                {
                    point = rsg.nextSequence().value;
                    stat.add(point);
                }
                mean = stat.mean();
                double error = Math.Abs(mean[1] - 0.5);
                if (error > tolerance)
                {
                    QAssert.Fail("Second dimension mean (" + /*QL_FIXED*/ +mean[1]
                                 + ") at the end of the " + j + 1
                                 + " cycle in Halton sequence is not " + 0.5
                                 //+ QL_SCIENTIFIC
                                 + " (error = " + error + ")");
                }
            }
        }
Пример #4
0
        public void testConventions()
        {
            // Testing business day conventions...

            SingleCase[] testCases =
            {
                // Following
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Following,                  new Date(3,  Month.February, 2015), new Period(1,  TimeUnit.Months), false, new Date(3,  Month.March,    2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Following,                  new Date(3,  Month.February, 2015), new Period(4,  TimeUnit.Days),   false, new Date(9,  Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Following,                  new Date(31, Month.January,  2015), new Period(1,  TimeUnit.Months), true,  new Date(27, Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Following,                  new Date(31, Month.January,  2015), new Period(1,  TimeUnit.Months), false, new Date(2,  Month.March,    2015)),

                //ModifiedFollowing
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing,          new Date(3,  Month.February, 2015), new Period(1,  TimeUnit.Months), false, new Date(3,  Month.March,    2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing,          new Date(3,  Month.February, 2015), new Period(4,  TimeUnit.Days),   false, new Date(9,  Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing,          new Date(31, Month.January,  2015), new Period(1,  TimeUnit.Months), true,  new Date(27, Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing,          new Date(31, Month.January,  2015), new Period(1,  TimeUnit.Months), false, new Date(27, Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing,          new Date(25, Month.March,    2015), new Period(1,  TimeUnit.Months), false, new Date(28, Month.April,    2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing,          new Date(7,  Month.February, 2015), new Period(1,  TimeUnit.Months), false, new Date(9,  Month.March,    2015)),

                //Preceding
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Preceding,                  new Date(3,  Month.March,    2015), new Period(-1, TimeUnit.Months), false, new Date(3,  Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Preceding,                  new Date(3,  Month.February, 2015), new Period(-2, TimeUnit.Days),   false, new Date(30, Month.January,  2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Preceding,                  new Date(1,  Month.March,    2015), new Period(-1, TimeUnit.Months), true,  new Date(30, Month.January,  2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Preceding,                  new Date(1,  Month.March,    2015), new Period(-1, TimeUnit.Months), false, new Date(30, Month.January,  2015)),

                //ModifiedPreceding
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedPreceding,          new Date(3,  Month.March,    2015), new Period(-1, TimeUnit.Months), false, new Date(3,  Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedPreceding,          new Date(3,  Month.February, 2015), new Period(-2, TimeUnit.Days),   false, new Date(30, Month.January,  2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedPreceding,          new Date(1,  Month.March,    2015), new Period(-1, TimeUnit.Months), true,  new Date(2,  Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedPreceding,          new Date(1,  Month.March,    2015), new Period(-1, TimeUnit.Months), false, new Date(2,  Month.February, 2015)),

                //Unadjusted
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Unadjusted,                 new Date(3,  Month.February, 2015), new Period(1,  TimeUnit.Months), false, new Date(3,  Month.March,    2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Unadjusted,                 new Date(3,  Month.February, 2015), new Period(4,  TimeUnit.Days),   false, new Date(9,  Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Unadjusted,                 new Date(31, Month.January,  2015), new Period(1,  TimeUnit.Months), true,  new Date(27, Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Unadjusted,                 new Date(31, Month.January,  2015), new Period(1,  TimeUnit.Months), false, new Date(28, Month.February, 2015)),

                //HalfMonthModifiedFollowing
                new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(3,  Month.February, 2015), new Period(1,  TimeUnit.Months), false, new Date(3,  Month.March,    2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(3,  Month.February, 2015), new Period(4,  TimeUnit.Days),   false, new Date(9,  Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(31, Month.January,  2015), new Period(1,  TimeUnit.Months), true,  new Date(27, Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(31, Month.January,  2015), new Period(1,  TimeUnit.Months), false, new Date(27, Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(3,  Month.January,  2015), new Period(1,  TimeUnit.Weeks),  false, new Date(12, Month.January,  2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(21, Month.March,    2015), new Period(1,  TimeUnit.Weeks),  false, new Date(30, Month.March,    2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(7,  Month.February, 2015), new Period(1,  TimeUnit.Months), false, new Date(9,  Month.March,    2015)),

                //Nearest
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest,                    new Date(3,  Month.February, 2015), new Period(1,  TimeUnit.Months), false, new Date(3,  Month.March,    2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest,                    new Date(3,  Month.February, 2015), new Period(4,  TimeUnit.Days),   false, new Date(9,  Month.February, 2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest,                    new Date(16, Month.April,    2015), new Period(1,  TimeUnit.Months), false, new Date(15, Month.May,      2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest,                    new Date(17, Month.April,    2015), new Period(1,  TimeUnit.Months), false, new Date(18, Month.May,      2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest,                    new Date(4,  Month.March,    2015), new Period(1,  TimeUnit.Months), false, new Date(2,  Month.April,    2015)),
                new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest,                    new Date(2,  Month.April,    2015), new Period(1,  TimeUnit.Months), false, new Date(4,  Month.May, 2015))
            };

            int n = testCases.Length;

            for (int i = 0; i < n; i++)
            {
                Calendar calendar = new Calendar(testCases[i].calendar);
                Date     result   = calendar.advance(testCases[i].start, testCases[i].period, testCases[i].convention, testCases[i].endOfMonth);

                QAssert.IsTrue(result == testCases[i].result,
                               "\ncase " + i + ":\n" //<< j << " ("<< desc << "): "
                               + "start date: " + testCases[i].start + "\n"
                               + "calendar: " + calendar + "\n"
                               + "period: " + testCases[i].period + ", end of month: " + testCases[i].endOfMonth + "\n"
                               + "convention: " + testCases[i].convention + "\n"
                               + "expected: " + testCases[i].result + " vs. actual: " + result);
            }
        }
Пример #5
0
        public void testSingle(StochasticProcess1D process,
                               string tag,
                               bool brownianBridge,
                               double expected,
                               double antithetic)
        {
            ulong  seed      = 42;
            double length    = 10;
            int    timeSteps = 12;

            var rsg = (InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng>
                                             , InverseCumulativeNormal>)
                      new PseudoRandom().make_sequence_generator(timeSteps, seed);



            PathGenerator <IRNG> generator = new PathGenerator <IRNG>(process,
                                                                      length,
                                                                      timeSteps,
                                                                      rsg,
                                                                      brownianBridge);
            int i;

            for (i = 0; i < 100; i++)
            {
                generator.next();
            }

            Sample <IPath> sample = generator.next();
            Path           value  = sample.value as Path;

            Utils.QL_REQUIRE(value != null, () => "Invalid Path");
            double calculated = value.back();
            double error      = Math.Abs(calculated - expected);
            double tolerance  = 2.0e-8;

            if (error > tolerance)
            {
                QAssert.Fail("using " + tag + " process "
                             + (brownianBridge ? "with " : "without ")
                             + "brownian bridge:\n"
                             //+ std::setprecision(13)
                             + "    calculated: " + calculated + "\n"
                             + "    expected:   " + expected + "\n"
                             + "    error:      " + error + "\n"
                             + "    tolerance:  " + tolerance);
            }

            sample = generator.antithetic();
            value  = sample.value as Path;
            Utils.QL_REQUIRE(value != null, () => "Invalid Path");
            calculated = value.back();
            error      = Math.Abs(calculated - antithetic);
            tolerance  = 2.0e-7;
            if (error > tolerance)
            {
                QAssert.Fail("using " + tag + " process "
                             + (brownianBridge ? "with " : "without ")
                             + "brownian bridge:\n"
                             + "antithetic sample:\n"
                             //+ setprecision(13)
                             + "    calculated: " + calculated + "\n"
                             + "    expected:   " + antithetic + "\n"
                             + "    error:      " + error + "\n"
                             + "    tolerance:  " + tolerance);
            }
        }
Пример #6
0
        public void testSmartLookup()
        {
            Currency EUR = new EURCurrency(), USD = new USDCurrency(), GBP = new GBPCurrency(),
                     CHF = new CHFCurrency(), SEK = new SEKCurrency(), JPY = new JPYCurrency();

            ExchangeRateManager rateManager = ExchangeRateManager.Instance;

            rateManager.clear();

            ExchangeRate eur_usd1           = new ExchangeRate(EUR, USD, 1.1983);
            ExchangeRate eur_usd2           = new ExchangeRate(USD, EUR, 1.0 / 1.2042);

            rateManager.add(eur_usd1, new Date(4, Month.August, 2004));
            rateManager.add(eur_usd2, new Date(5, Month.August, 2004));

            ExchangeRate eur_gbp1 = new ExchangeRate(GBP, EUR, 1.0 / 0.6596);
            ExchangeRate eur_gbp2 = new ExchangeRate(EUR, GBP, 0.6612);

            rateManager.add(eur_gbp1, new Date(4, Month.August, 2004));
            rateManager.add(eur_gbp2, new Date(5, Month.August, 2004));

            ExchangeRate usd_chf1 = new ExchangeRate(USD, CHF, 1.2847);
            ExchangeRate usd_chf2 = new ExchangeRate(CHF, USD, 1.0 / 1.2774);

            rateManager.add(usd_chf1, new Date(4, Month.August, 2004));
            rateManager.add(usd_chf2, new Date(5, Month.August, 2004));

            ExchangeRate chf_sek1 = new ExchangeRate(SEK, CHF, 0.1674);
            ExchangeRate chf_sek2 = new ExchangeRate(CHF, SEK, 1.0 / 0.1677);

            rateManager.add(chf_sek1, new Date(4, Month.August, 2004));
            rateManager.add(chf_sek2, new Date(5, Month.August, 2004));

            ExchangeRate jpy_sek1 = new ExchangeRate(SEK, JPY, 14.5450);
            ExchangeRate jpy_sek2 = new ExchangeRate(JPY, SEK, 1.0 / 14.6110);

            rateManager.add(jpy_sek1, new Date(4, Month.August, 2004));
            rateManager.add(jpy_sek2, new Date(5, Month.August, 2004));

            Money m1 = 100000.0 * USD;
            Money m2 = 100000.0 * EUR;
            Money m3 = 100000.0 * GBP;
            Money m4 = 100000.0 * CHF;
            Money m5 = 100000.0 * SEK;
            Money m6 = 100000.0 * JPY;

            Money.conversionType = Money.ConversionType.NoConversion;

            // two-rate chain

            ExchangeRate usd_sek    = rateManager.lookup(USD, SEK, new Date(4, Month.August, 2004));
            Money        calculated = usd_sek.exchange(m1);
            Money        expected   = new Money(m1.value * usd_chf1.rate / chf_sek1.rate, SEK);

            if (!Utils.close(calculated, expected))
            {
                QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated);
            }

            usd_sek    = rateManager.lookup(SEK, USD, new Date(5, Month.August, 2004));
            calculated = usd_sek.exchange(m5);
            expected   = new Money(m5.value * usd_chf2.rate / chf_sek2.rate, USD);

            if (!Utils.close(calculated, expected))
            {
                QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated);
            }

            // three-rate chain

            ExchangeRate eur_sek = rateManager.lookup(EUR, SEK, new Date(4, Month.August, 2004));

            calculated = eur_sek.exchange(m2);
            expected   = new Money(m2.value * eur_usd1.rate * usd_chf1.rate / chf_sek1.rate, SEK);

            if (!Utils.close(calculated, expected))
            {
                QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated);
            }

            eur_sek    = rateManager.lookup(SEK, EUR, new Date(5, Month.August, 2004));
            calculated = eur_sek.exchange(m5);
            expected   = new Money(m5.value * eur_usd2.rate * usd_chf2.rate / chf_sek2.rate, EUR);

            if (!Utils.close(calculated, expected))
            {
                QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated);
            }

            // four-rate chain

            ExchangeRate eur_jpy = rateManager.lookup(EUR, JPY, new Date(4, Month.August, 2004));

            calculated = eur_jpy.exchange(m2);
            expected   = new Money(m2.value * eur_usd1.rate * usd_chf1.rate * jpy_sek1.rate / chf_sek1.rate, JPY);

            if (!Utils.close(calculated, expected))
            {
                QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated);
            }

            eur_jpy    = rateManager.lookup(JPY, EUR, new Date(5, Month.August, 2004));
            calculated = eur_jpy.exchange(m6);
            expected   = new Money(m6.value * jpy_sek2.rate * eur_usd2.rate * usd_chf2.rate / chf_sek2.rate, EUR);

            if (!Utils.close(calculated, expected))
            {
                QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated);
            }

            // five-rate chain

            ExchangeRate gbp_jpy = rateManager.lookup(GBP, JPY, new Date(4, Month.August, 2004));

            calculated = gbp_jpy.exchange(m3);
            expected   = new Money(m3.value * eur_gbp1.rate * eur_usd1.rate * usd_chf1.rate * jpy_sek1.rate / chf_sek1.rate, JPY);

            if (!Utils.close(calculated, expected))
            {
                QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated);
            }

            gbp_jpy    = rateManager.lookup(JPY, GBP, new Date(5, Month.August, 2004));
            calculated = gbp_jpy.exchange(m6);
            expected   = new Money(m6.value * jpy_sek2.rate * eur_usd2.rate * usd_chf2.rate * eur_gbp2.rate / chf_sek2.rate, GBP);

            if (!Utils.close(calculated, expected))
            {
                QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated);
            }
        }
Пример #7
0
        public void testSwaps()
        {
            //BOOST_MESSAGE("Testing Hull-White swap pricing against known values...");

            Date today; //=Settings::instance().evaluationDate();;

            Calendar calendar = new TARGET();

            today = calendar.adjust(Date.Today);
            Settings.setEvaluationDate(today);

            Date settlement = calendar.advance(today, 2, TimeUnit.Days);

            Date[] dates =
            {
                settlement,
                calendar.advance(settlement,  1, TimeUnit.Weeks),
                calendar.advance(settlement,  1, TimeUnit.Months),
                calendar.advance(settlement,  3, TimeUnit.Months),
                calendar.advance(settlement,  6, TimeUnit.Months),
                calendar.advance(settlement,  9, TimeUnit.Months),
                calendar.advance(settlement,  1, TimeUnit.Years),
                calendar.advance(settlement,  2, TimeUnit.Years),
                calendar.advance(settlement,  3, TimeUnit.Years),
                calendar.advance(settlement,  5, TimeUnit.Years),
                calendar.advance(settlement, 10, TimeUnit.Years),
                calendar.advance(settlement, 15, TimeUnit.Years)
            };
            double[] discounts =
            {
                1.0,
                0.999258,
                0.996704,
                0.990809,
                0.981798,
                0.972570,
                0.963430,
                0.929532,
                0.889267,
                0.803693,
                0.596903,
                0.433022
            };

            //for (int i = 0; i < dates.Length; i++)
            //    dates[i] + dates.Length;

            LogLinear Interpolator = new LogLinear();

            Handle <YieldTermStructure> termStructure =
                new Handle <YieldTermStructure>(
                    new InterpolatedDiscountCurve <LogLinear>(
                        dates.ToList <Date>(),
                        discounts.ToList <double>(),
                        new Actual365Fixed(), new Calendar(), null, null, Interpolator)
                    );

            HullWhite model = new HullWhite(termStructure);

            int[]     start   = { -3, 0, 3 };
            int[]     length  = { 2, 5, 10 };
            double[]  rates   = { 0.02, 0.04, 0.06 };
            IborIndex euribor = new Euribor6M(termStructure);

            IPricingEngine engine = new TreeVanillaSwapEngine(model, 120, termStructure);

#if QL_USE_INDEXED_COUPON
            double tolerance = 4.0e-3;
#else
            double tolerance = 1.0e-8;
#endif

            for (int i = 0; i < start.Length; i++)
            {
                Date startDate = calendar.advance(settlement, start[i], TimeUnit.Months);
                if (startDate < today)
                {
                    Date fixingDate = calendar.advance(startDate, -2, TimeUnit.Days);
                    TimeSeries <double?> pastFixings = new TimeSeries <double?>();
                    pastFixings[fixingDate] = 0.03;
                    IndexManager.instance().setHistory(euribor.name(), pastFixings);
                }

                for (int j = 0; j < length.Length; j++)
                {
                    Date     maturity      = calendar.advance(startDate, length[i], TimeUnit.Years);
                    Schedule fixedSchedule = new Schedule(startDate, maturity, new Period(Frequency.Annual),
                                                          calendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
                                                          DateGeneration.Rule.Forward, false);
                    Schedule floatSchedule = new Schedule(startDate, maturity, new Period(Frequency.Semiannual),
                                                          calendar, BusinessDayConvention.Following, BusinessDayConvention.Following,
                                                          DateGeneration.Rule.Forward, false);
                    for (int k = 0; k < rates.Length; k++)
                    {
                        VanillaSwap swap = new VanillaSwap(VanillaSwap.Type.Payer, 1000000.0,
                                                           fixedSchedule, rates[k], new Thirty360(),
                                                           floatSchedule, euribor, 0.0, new Actual360());
                        swap.setPricingEngine(new DiscountingSwapEngine(termStructure));
                        double expected = swap.NPV();
                        swap.setPricingEngine(engine);
                        double calculated = swap.NPV();

                        double error = Math.Abs((expected - calculated) / expected);
                        if (error > tolerance)
                        {
                            QAssert.Fail("Failed to reproduce swap NPV:"
                                         //+ QL_FIXED << std::setprecision(9)
                                         + "\n    calculated: " + calculated
                                         + "\n    expected:   " + expected
                                         //+ QL_SCIENTIFIC
                                         + "\n    rel. error: " + error);
                        }
                    }
                }
            }
        }
Пример #8
0
        public void testActualActual()
        {
            SingleCase[] testCases =
            {
                // first example
                new SingleCase(ActualActual.Convention.ISDA,
                               new Date(1,                  Month.November,  2003), new Date(1,  Month.May,     2004),
                               0.497724380567),
                new SingleCase(ActualActual.Convention.ISMA,
                               new Date(1,                  Month.November,  2003), new Date(1,  Month.May,     2004),
                               new Date(1,                  Month.November,  2003), new Date(1,  Month.May,     2004),
                               0.500000000000),
                new SingleCase(ActualActual.Convention.AFB,
                               new Date(1,                  Month.November,  2003), new Date(1,  Month.May,     2004),
                               0.497267759563),
                // short first calculation period (first period)
                new SingleCase(ActualActual.Convention.ISDA,
                               new Date(1,                  Month.February,  1999), new Date(1,  Month.July,    1999),
                               0.410958904110),
                new SingleCase(ActualActual.Convention.ISMA,
                               new Date(1,                  Month.February,  1999), new Date(1,  Month.July,    1999),
                               new Date(1,                  Month.July,      1998), new Date(1,  Month.July,    1999),
                               0.410958904110),
                new SingleCase(ActualActual.Convention.AFB,
                               new Date(1,                  Month.February,  1999), new Date(1,  Month.July,    1999),
                               0.410958904110),
                // short first calculation period (second period)
                new SingleCase(ActualActual.Convention.ISDA,
                               new Date(1,                  Month.July,      1999), new Date(1,  Month.July,    2000),
                               1.001377348600),
                new SingleCase(ActualActual.Convention.ISMA,
                               new Date(1,                  Month.July,      1999), new Date(1,  Month.July,    2000),
                               new Date(1,                  Month.July,      1999), new Date(1,  Month.July,    2000),
                               1.000000000000),
                new SingleCase(ActualActual.Convention.AFB,
                               new Date(1,                  Month.July,      1999), new Date(1,  Month.July,    2000),
                               1.000000000000),
                // long first calculation period (first period)
                new SingleCase(ActualActual.Convention.ISDA,
                               new Date(15,                 Month.August,    2002), new Date(15, Month.July,    2003),
                               0.915068493151),
                new SingleCase(ActualActual.Convention.ISMA,
                               new Date(15,                 Month.August,    2002), new Date(15, Month.July,    2003),
                               new Date(15,                 Month.January,   2003), new Date(15, Month.July,    2003),
                               0.915760869565),
                new SingleCase(ActualActual.Convention.AFB,
                               new Date(15,                 Month.August,    2002), new Date(15, Month.July,    2003),
                               0.915068493151),
                // long first calculation period (second period)
                /* Warning: the ISDA case is in disagreement with mktc1198.pdf */
                new SingleCase(ActualActual.Convention.ISDA,
                               new Date(15,                 Month.July,      2003), new Date(15, Month.January, 2004),
                               0.504004790778),
                new SingleCase(ActualActual.Convention.ISMA,
                               new Date(15,                 Month.July,      2003), new Date(15, Month.January, 2004),
                               new Date(15,                 Month.July,      2003), new Date(15, Month.January, 2004),
                               0.500000000000),
                new SingleCase(ActualActual.Convention.AFB,
                               new Date(15,                 Month.July,      2003), new Date(15, Month.January, 2004),
                               0.504109589041),
                // short final calculation period (penultimate period)
                new SingleCase(ActualActual.Convention.ISDA,
                               new Date(30,                 Month.July,      1999), new Date(30, Month.January, 2000),
                               0.503892506924),
                new SingleCase(ActualActual.Convention.ISMA,
                               new Date(30,                 Month.July,      1999), new Date(30, Month.January, 2000),
                               new Date(30,                 Month.July,      1999), new Date(30, Month.January, 2000),
                               0.500000000000),
                new SingleCase(ActualActual.Convention.AFB,
                               new Date(30,                 Month.July,      1999), new Date(30, Month.January, 2000),
                               0.504109589041),
                // short final calculation period (final period)
                new SingleCase(ActualActual.Convention.ISDA,
                               new Date(30,                 Month.January,   2000), new Date(30, Month.June,    2000),
                               0.415300546448),
                new SingleCase(ActualActual.Convention.ISMA,
                               new Date(30,                 Month.January,   2000), new Date(30, Month.June,    2000),
                               new Date(30,                 Month.January,   2000), new Date(30, Month.July,    2000),
                               0.417582417582),
                new SingleCase(ActualActual.Convention.AFB,
                               new Date(30,                 Month.January,   2000), new Date(30, Month.June,    2000),
                               0.41530054644)
            };

            int n = testCases.Length; /// sizeof(SingleCase);

            for (int i = 0; i < n; i++)
            {
                ActualActual dayCounter = new ActualActual(testCases[i]._convention);
                Date         d1         = testCases[i]._start;
                Date         d2         = testCases[i]._end;
                Date         rd1        = testCases[i]._refStart;
                Date         rd2        = testCases[i]._refEnd;
                double       calculated = dayCounter.yearFraction(d1, d2, rd1, rd2);

                if (Math.Abs(calculated - testCases[i]._result) > 1.0e-10)
                {
                    QAssert.Fail(dayCounter.name() + "period: " + d1 + " to " + d2 +
                                 "    calculated: " + calculated + "    expected:   " + testCases[i]._result);
                }
            }
        }
Пример #9
0
        public void testChambersImpliedVol()
        {
            // Testing Chambers-Nawalkha implied vol approximation

            Option.Type[] types         = { Option.Type.Call, Option.Type.Put };
            double[]      displacements = { 0.0000, 0.0010, 0.0050, 0.0100, 0.0200 };
            double[]      forwards      = { -0.0010, 0.0000, 0.0050, 0.0100, 0.0200, 0.0500 };
            double[]      strikes       = { -0.0100, -0.0050, -0.0010, 0.0000, 0.0010, 0.0050, 0.0100, 0.0200, 0.0500, 0.1000 };
            double[]      stdDevs       = { 0.10, 0.15, 0.20, 0.30, 0.50, 0.60, 0.70, 0.80, 1.00, 1.50, 2.00 };
            double[]      discounts     = { 1.00, 0.95, 0.80, 1.10 };

            double tol = 5.0E-4;

            for (int i1 = 0; i1 < types.Length; ++i1)
            {
                for (int i2 = 0; i2 < displacements.Length; ++i2)
                {
                    for (int i3 = 0; i3 < forwards.Length; ++i3)
                    {
                        for (int i4 = 0; i4 < strikes.Length; ++i4)
                        {
                            for (int i5 = 0; i5 < stdDevs.Length; ++i5)
                            {
                                for (int i6 = 0; i6 < discounts.Length; ++i6)
                                {
                                    if (forwards[i3] + displacements[i2] > 0.0 &&
                                        strikes[i4] + displacements[i2] > 0.0)
                                    {
                                        double premium = Utils.blackFormula(
                                            types[i1], strikes[i4], forwards[i3],
                                            stdDevs[i5], discounts[i6],
                                            displacements[i2]);
                                        double atmPremium = Utils.blackFormula(
                                            types[i1], forwards[i3], forwards[i3],
                                            stdDevs[i5], discounts[i6],
                                            displacements[i2]);
                                        double iStdDev = Utils.blackFormulaImpliedStdDevChambers(
                                            types[i1], strikes[i4], forwards[i3],
                                            premium, atmPremium, discounts[i6],
                                            displacements[i2]);
                                        double moneyness = (strikes[i4] + displacements[i2]) /
                                                           (forwards[i3] + displacements[i2]);
                                        if (moneyness > 1.0)
                                        {
                                            moneyness = 1.0 / moneyness;
                                        }
                                        double error = (iStdDev - stdDevs[i5]) / stdDevs[i5] * moneyness;
                                        if (error > tol)
                                        {
                                            QAssert.Fail("Failed to verify Chambers-Nawalkha approximation for "
                                                         + types[i1]
                                                         + " displacement=" + displacements[i2]
                                                         + " forward=" + forwards[i3]
                                                         + " strike=" + strikes[i4]
                                                         + " discount=" + discounts[i6]
                                                         + " stddev=" + stdDevs[i5]
                                                         + " result=" + iStdDev
                                                         + " exceeds maximum error tolerance");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #10
0
        public void testThirty360_BondBasis()
        {
            // Testing thirty/360 day counter (Bond Basis)
            // http://www.isda.org/c_and_a/docs/30-360-2006ISDADefs.xls
            // Source: 2006 ISDA Definitions, Sec. 4.16 (f)
            // 30/360 (or Bond Basis)

            DayCounter  dayCounter     = new Thirty360(Thirty360.Thirty360Convention.BondBasis);
            List <Date> testStartDates = new List <Date>();
            List <Date> testEndDates   = new List <Date>();
            int         calculated;

            // ISDA - Example 1: End dates do not involve the last day of February
            testStartDates.Add(new Date(20, Month.August, 2006));   testEndDates.Add(new Date(20, Month.February, 2007));
            testStartDates.Add(new Date(20, Month.February, 2007)); testEndDates.Add(new Date(20, Month.August, 2007));
            testStartDates.Add(new Date(20, Month.August, 2007));   testEndDates.Add(new Date(20, Month.February, 2008));
            testStartDates.Add(new Date(20, Month.February, 2008)); testEndDates.Add(new Date(20, Month.August, 2008));
            testStartDates.Add(new Date(20, Month.August, 2008));   testEndDates.Add(new Date(20, Month.February, 2009));
            testStartDates.Add(new Date(20, Month.February, 2009)); testEndDates.Add(new Date(20, Month.August, 2009));

            // ISDA - Example 2: End dates include some end-February dates
            testStartDates.Add(new Date(31, Month.August, 2006));   testEndDates.Add(new Date(28, Month.February, 2007));
            testStartDates.Add(new Date(28, Month.February, 2007)); testEndDates.Add(new Date(31, Month.August, 2007));
            testStartDates.Add(new Date(31, Month.August, 2007));   testEndDates.Add(new Date(29, Month.February, 2008));
            testStartDates.Add(new Date(29, Month.February, 2008)); testEndDates.Add(new Date(31, Month.August, 2008));
            testStartDates.Add(new Date(31, Month.August, 2008));   testEndDates.Add(new Date(28, Month.February, 2009));
            testStartDates.Add(new Date(28, Month.February, 2009)); testEndDates.Add(new Date(31, Month.August, 2009));

            //// ISDA - Example 3: Miscellaneous calculations
            testStartDates.Add(new Date(31, Month.January, 2006));   testEndDates.Add(new Date(28, Month.February, 2006));
            testStartDates.Add(new Date(30, Month.January, 2006));   testEndDates.Add(new Date(28, Month.February, 2006));
            testStartDates.Add(new Date(28, Month.February, 2006));  testEndDates.Add(new Date(3, Month.March, 2006));
            testStartDates.Add(new Date(14, Month.February, 2006));  testEndDates.Add(new Date(28, Month.February, 2006));
            testStartDates.Add(new Date(30, Month.September, 2006)); testEndDates.Add(new Date(31, Month.October, 2006));
            testStartDates.Add(new Date(31, Month.October, 2006));   testEndDates.Add(new Date(28, Month.November, 2006));
            testStartDates.Add(new Date(31, Month.August, 2007));    testEndDates.Add(new Date(28, Month.February, 2008));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(28, Month.August, 2008));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(30, Month.August, 2008));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(31, Month.August, 2008));
            testStartDates.Add(new Date(26, Month.February, 2007));  testEndDates.Add(new Date(28, Month.February, 2008));
            testStartDates.Add(new Date(26, Month.February, 2007));  testEndDates.Add(new Date(29, Month.February, 2008));
            testStartDates.Add(new Date(29, Month.February, 2008));  testEndDates.Add(new Date(28, Month.February, 2009));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(30, Month.March, 2008));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(31, Month.March, 2008));

            int[] expected = { 180, 180, 180, 180, 180, 180,
                               178, 183, 179, 182, 178, 183,
                               28,   28,   5,  14,  30,  28,
                               178, 180, 182, 183, 362, 363,
                               359,  32, 33 };

            for (int i = 0; i < testStartDates.Count; i++)
            {
                calculated = dayCounter.dayCount(testStartDates[i], testEndDates[i]);
                if (calculated != expected[i])
                {
                    QAssert.Fail("from " + testStartDates[i]
                                 + " to " + testEndDates[i] + ":\n"
                                 + "    calculated: " + calculated + "\n"
                                 + "    expected:   " + expected[i]);
                }
            }
        }
Пример #11
0
        public void testThirty360_EurobondBasis()
        {
            // Testing thirty/360 day counter (Eurobond Basis)
            // Source: ISDA 2006 Definitions 4.16 (g)
            // 30E/360 (or Eurobond Basis)
            // Based on ICMA (Rule 251) and FBF; this is the version of 30E/360 used by Excel

            DayCounter  dayCounter     = new Thirty360(Thirty360.Thirty360Convention.EurobondBasis);
            List <Date> testStartDates = new List <Date>();
            List <Date> testEndDates   = new List <Date>();
            int         calculated;

            // ISDA - Example 1: End dates do not involve the last day of February
            testStartDates.Add(new Date(20, Month.August, 2006));   testEndDates.Add(new Date(20, Month.February, 2007));
            testStartDates.Add(new Date(20, Month.February, 2007)); testEndDates.Add(new Date(20, Month.August, 2007));
            testStartDates.Add(new Date(20, Month.August, 2007));   testEndDates.Add(new Date(20, Month.February, 2008));
            testStartDates.Add(new Date(20, Month.February, 2008)); testEndDates.Add(new Date(20, Month.August, 2008));
            testStartDates.Add(new Date(20, Month.August, 2008));   testEndDates.Add(new Date(20, Month.February, 2009));
            testStartDates.Add(new Date(20, Month.February, 2009)); testEndDates.Add(new Date(20, Month.August, 2009));

            //// ISDA - Example 2: End dates include some end-February dates
            testStartDates.Add(new Date(28, Month.February, 2006)); testEndDates.Add(new Date(31, Month.August, 2006));
            testStartDates.Add(new Date(31, Month.August, 2006));   testEndDates.Add(new Date(28, Month.February, 2007));
            testStartDates.Add(new Date(28, Month.February, 2007)); testEndDates.Add(new Date(31, Month.August, 2007));
            testStartDates.Add(new Date(31, Month.August, 2007));   testEndDates.Add(new Date(29, Month.February, 2008));
            testStartDates.Add(new Date(29, Month.February, 2008)); testEndDates.Add(new Date(31, Month.August, 2008));
            testStartDates.Add(new Date(31, Month.August, 2008));   testEndDates.Add(new Date(28, Month.Feb, 2009));
            testStartDates.Add(new Date(28, Month.February, 2009)); testEndDates.Add(new Date(31, Month.August, 2009));
            testStartDates.Add(new Date(31, Month.August, 2009));   testEndDates.Add(new Date(28, Month.Feb, 2010));
            testStartDates.Add(new Date(28, Month.February, 2010)); testEndDates.Add(new Date(31, Month.August, 2010));
            testStartDates.Add(new Date(31, Month.August, 2010));   testEndDates.Add(new Date(28, Month.Feb, 2011));
            testStartDates.Add(new Date(28, Month.February, 2011)); testEndDates.Add(new Date(31, Month.August, 2011));
            testStartDates.Add(new Date(31, Month.August, 2011));   testEndDates.Add(new Date(29, Month.Feb, 2012));

            //// ISDA - Example 3: Miscellaneous calculations
            testStartDates.Add(new Date(31, Month.January, 2006));   testEndDates.Add(new Date(28, Month.February, 2006));
            testStartDates.Add(new Date(30, Month.January, 2006));   testEndDates.Add(new Date(28, Month.February, 2006));
            testStartDates.Add(new Date(28, Month.February, 2006));  testEndDates.Add(new Date(3, Month.March, 2006));
            testStartDates.Add(new Date(14, Month.February, 2006));  testEndDates.Add(new Date(28, Month.February, 2006));
            testStartDates.Add(new Date(30, Month.September, 2006)); testEndDates.Add(new Date(31, Month.October, 2006));
            testStartDates.Add(new Date(31, Month.October, 2006));   testEndDates.Add(new Date(28, Month.November, 2006));
            testStartDates.Add(new Date(31, Month.August, 2007));    testEndDates.Add(new Date(28, Month.February, 2008));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(28, Month.August, 2008));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(30, Month.August, 2008));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(31, Month.August, 2008));
            testStartDates.Add(new Date(26, Month.February, 2007));  testEndDates.Add(new Date(28, Month.February, 2008));
            testStartDates.Add(new Date(26, Month.February, 2007));  testEndDates.Add(new Date(29, Month.February, 2008));
            testStartDates.Add(new Date(29, Month.February, 2008));  testEndDates.Add(new Date(28, Month.February, 2009));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(30, Month.March, 2008));
            testStartDates.Add(new Date(28, Month.February, 2008));  testEndDates.Add(new Date(31, Month.March, 2008));

            int[] expected = { 180, 180, 180, 180, 180, 180,
                               182, 178, 182, 179, 181, 178,
                               182, 178, 182, 178, 182, 179,
                               28,   28,   5,  14,  30,  28,
                               178, 180, 182, 182, 362, 363,
                               359,  32, 32 };

            for (int i = 0; i < testStartDates.Count; i++)
            {
                calculated = dayCounter.dayCount(testStartDates[i], testEndDates[i]);
                if (calculated != expected[i])
                {
                    QAssert.Fail("from " + testStartDates[i]
                                 + " to " + testEndDates[i] + ":\n"
                                 + "    calculated: " + calculated + "\n"
                                 + "    expected:   " + expected[i]);
                }
            }
        }
Пример #12
0
        public void testBusiness252()
        {
            // Testing business/252 day counter

            List <Date> testDates = new List <Date>();

            testDates.Add(new Date(1, Month.February, 2002));
            testDates.Add(new Date(4, Month.February, 2002));
            testDates.Add(new Date(16, Month.May, 2003));
            testDates.Add(new Date(17, Month.December, 2003));
            testDates.Add(new Date(17, Month.December, 2004));
            testDates.Add(new Date(19, Month.December, 2005));
            testDates.Add(new Date(2, Month.January, 2006));
            testDates.Add(new Date(13, Month.March, 2006));
            testDates.Add(new Date(15, Month.May, 2006));
            testDates.Add(new Date(17, Month.March, 2006));
            testDates.Add(new Date(15, Month.May, 2006));
            testDates.Add(new Date(26, Month.July, 2006));
            testDates.Add(new Date(28, Month.June, 2007));
            testDates.Add(new Date(16, Month.September, 2009));
            testDates.Add(new Date(26, Month.July, 2016));

            double[] expected =
            {
                0.0039682539683,
                1.2738095238095,
                0.6031746031746,
                0.9960317460317,
                1.0000000000000,
                0.0396825396825,
                0.1904761904762,
                0.1666666666667,
                -0.1507936507937,
                0.1507936507937,
                0.2023809523810,
                0.912698412698,
                2.214285714286,
                6.84126984127
            };

            DayCounter dayCounter1 = new Business252(new Brazil());

            double calculated;

            for (int i = 1; i < testDates.Count; i++)
            {
                calculated = dayCounter1.yearFraction(testDates[i - 1], testDates[i]);
                if (Math.Abs(calculated - expected[i - 1]) > 1.0e-12)
                {
                    QAssert.Fail("from " + testDates[i - 1]
                                 + " to " + testDates[i] + ":\n"
                                 + "    calculated: " + calculated + "\n"
                                 + "    expected:   " + expected[i - 1]);
                }
            }

            DayCounter dayCounter2 = new Business252();

            for (int i = 1; i < testDates.Count; i++)
            {
                calculated = dayCounter2.yearFraction(testDates[i - 1], testDates[i]);
                if (Math.Abs(calculated - expected[i - 1]) > 1.0e-12)
                {
                    QAssert.Fail("from " + testDates[i - 1]
                                 + " to " + testDates[i] + ":\n"
                                 + "    calculated: " + calculated + "\n"
                                 + "    expected:   " + expected[i - 1]);
                }
            }
        }
Пример #13
0
        public void testActualActualWithSchedule()
        {
            // Testing actual/actual day counter with schedule

            // long first coupon
            Date issueDateExpected       = new Date(17, Month.January, 2017);
            Date firstCouponDateExpected = new Date(31, Month.August, 2017);

            Schedule schedule =
                new MakeSchedule()
                .from(issueDateExpected)
                .withFirstDate(firstCouponDateExpected)
                .to(new Date(28, Month.February, 2026))
                .withFrequency(Frequency.Semiannual)
                .withCalendar(new Canada())
                .withConvention(BusinessDayConvention.Unadjusted)
                .backwards()
                .endOfMonth().value();

            Date issueDate = schedule.date(0);

            Utils.QL_REQUIRE(issueDate == issueDateExpected, () =>
                             "This is not the expected issue date " + issueDate
                             + " expected " + issueDateExpected);
            Date firstCouponDate = schedule.date(1);

            Utils.QL_REQUIRE(firstCouponDate == firstCouponDateExpected, () =>
                             "This is not the expected first coupon date " + firstCouponDate
                             + " expected: " + firstCouponDateExpected);

            //Make thw quasi coupon dates:
            Date quasiCouponDate2 = schedule.calendar().advance(firstCouponDate,
                                                                -schedule.tenor(),
                                                                schedule.businessDayConvention(),
                                                                schedule.endOfMonth());
            Date quasiCouponDate1 = schedule.calendar().advance(quasiCouponDate2,
                                                                -schedule.tenor(),
                                                                schedule.businessDayConvention(),
                                                                schedule.endOfMonth());

            Date quasiCouponDate1Expected = new Date(31, Month.August, 2016);
            Date quasiCouponDate2Expected = new Date(28, Month.February, 2017);

            Utils.QL_REQUIRE(quasiCouponDate2 == quasiCouponDate2Expected, () =>
                             "Expected " + quasiCouponDate2Expected
                             + " as the later quasi coupon date but received "
                             + quasiCouponDate2);
            Utils.QL_REQUIRE(quasiCouponDate1 == quasiCouponDate1Expected, () =>
                             "Expected " + quasiCouponDate1Expected
                             + " as the earlier quasi coupon date but received "
                             + quasiCouponDate1);

            DayCounter dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule);

            // full coupon
            double t_with_reference = dayCounter.yearFraction(
                issueDate, firstCouponDate,
                quasiCouponDate2, firstCouponDate
                );
            double t_no_reference = dayCounter.yearFraction(
                issueDate,
                firstCouponDate
                );
            double t_total =
                ISMAYearFractionWithReferenceDates(dayCounter,
                                                   issueDate, quasiCouponDate2,
                                                   quasiCouponDate1, quasiCouponDate2)
                + 0.5;
            double expected = 0.6160220994;


            if (Math.Abs(t_total - expected) > 1.0e-10)
            {
                QAssert.Fail("Failed to reproduce expected time:\n"
                             + "    calculated: " + t_total + "\n"
                             + "    expected:   " + expected);
            }
            if (Math.Abs(t_with_reference - expected) > 1.0e-10)
            {
                QAssert.Fail("Failed to reproduce expected time:\n"
                             + "    calculated: " + t_with_reference + "\n"
                             + "    expected:   " + expected);
            }
            if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10)
            {
                QAssert.Fail("Should produce the same time whether or not references are present");
            }

            // settlement date in the first quasi-period
            Date settlementDate = new Date(29, Month.January, 2017);

            t_with_reference = ISMAYearFractionWithReferenceDates(
                dayCounter,
                issueDate, settlementDate,
                quasiCouponDate1, quasiCouponDate2
                );
            t_no_reference = dayCounter.yearFraction(issueDate, settlementDate);
            double t_expected_first_qp = 0.03314917127071823; //12.0/362

            if (Math.Abs(t_with_reference - t_expected_first_qp) > 1.0e-10)
            {
                QAssert.Fail("Failed to reproduce expected time:\n"
                             + "    calculated: " + t_no_reference + "\n"
                             + "    expected:   " + t_expected_first_qp);
            }
            if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10)
            {
                QAssert.Fail("Should produce the same time whether or not references are present");
            }
            double t2 = dayCounter.yearFraction(settlementDate, firstCouponDate);

            if (Math.Abs(t_expected_first_qp + t2 - expected) > 1.0e-10)
            {
                QAssert.Fail("Sum of quasiperiod2 split is not consistent");
            }

            // settlement date in the second quasi-period
            settlementDate   = new Date(29, Month.July, 2017);
            t_no_reference   = dayCounter.yearFraction(issueDate, settlementDate);
            t_with_reference = ISMAYearFractionWithReferenceDates(
                dayCounter,
                issueDate, quasiCouponDate2,
                quasiCouponDate1, quasiCouponDate2
                ) + ISMAYearFractionWithReferenceDates(
                dayCounter,
                quasiCouponDate2, settlementDate,
                quasiCouponDate2, firstCouponDate
                );
            if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10)
            {
                QAssert.Fail("These two cases should be identical");
            }
            t2 = dayCounter.yearFraction(settlementDate, firstCouponDate);
            if (Math.Abs(t_total - (t_no_reference + t2)) > 1.0e-10)
            {
                QAssert.Fail("Failed to reproduce expected time:\n"
                             + "    calculated: " + t_total + "\n"
                             + "    expected:   " + t_no_reference + t2);
            }
        }
Пример #14
0
        public void testActualActualWithSemiannualSchedule()
        {
            // Testing actual/actual with schedule for undefined semiannual reference periods

            Calendar calendar     = new UnitedStates();
            Date     fromDate     = new Date(10, Month.January, 2017);
            Date     firstCoupon  = new Date(31, Month.August, 2017);
            Date     quasiCoupon  = new Date(28, Month.February, 2017);
            Date     quasiCoupon2 = new Date(31, Month.August, 2016);

            Schedule schedule = new MakeSchedule()
                                .from(fromDate)
                                .withFirstDate(firstCoupon)
                                .to(new Date(28, Month.February, 2026))
                                .withFrequency(Frequency.Semiannual)
                                .withCalendar(calendar)
                                .withConvention(BusinessDayConvention.Unadjusted)
                                .backwards().endOfMonth(true).value();

            Date       testDate             = schedule.date(1);
            DayCounter dayCounter           = new ActualActual(ActualActual.Convention.ISMA, schedule);
            DayCounter dayCounterNoSchedule = new ActualActual(ActualActual.Convention.ISMA);

            Date referencePeriodStart = schedule.date(1);
            Date referencePeriodEnd   = schedule.date(2);

            // Test
            QAssert.IsTrue(dayCounter.yearFraction(referencePeriodStart,
                                                   referencePeriodStart).IsEqual(0.0), "This should be zero.");

            QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart,
                                                             referencePeriodStart).IsEqual(0.0), "This should be zero");

            QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart,
                                                             referencePeriodStart, referencePeriodStart, referencePeriodStart).IsEqual(0.0),
                           "This should be zero");

            QAssert.IsTrue(dayCounter.yearFraction(referencePeriodStart,
                                                   referencePeriodEnd).IsEqual(0.5),
                           "This should be exact using schedule; "
                           + referencePeriodStart + " to " + referencePeriodEnd
                           + "Should be 0.5");

            QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart,
                                                             referencePeriodEnd, referencePeriodStart, referencePeriodEnd).IsEqual(0.5),
                           "This should be exact for explicit reference periods with no schedule");

            while (testDate < referencePeriodEnd)
            {
                double difference =
                    dayCounter.yearFraction(testDate, referencePeriodEnd,
                                            referencePeriodStart, referencePeriodEnd) -
                    dayCounter.yearFraction(testDate, referencePeriodEnd);
                if (Math.Abs(difference) > 1.0e-10)
                {
                    QAssert.Fail("Failed to correctly use the schedule to find the reference period for Act/Act");
                }
                testDate = calendar.advance(testDate, 1, TimeUnit.Days);
            }

            //Test long first coupon
            double calculatedYearFraction =
                dayCounter.yearFraction(fromDate, firstCoupon);
            double expectedYearFraction =
                0.5 + ((double)dayCounter.dayCount(fromDate, quasiCoupon))
                / (2 * dayCounter.dayCount(quasiCoupon2, quasiCoupon));

            QAssert.IsTrue(Math.Abs(calculatedYearFraction - expectedYearFraction) < 1.0e-10,
                           "Failed to compute the expected year fraction " +
                           "\n expected:   " + expectedYearFraction +
                           "\n calculated: " + calculatedYearFraction);

            // test multiple periods

            schedule = new MakeSchedule()
                       .from(new Date(10, Month.January, 2017))
                       .withFirstDate(new Date(31, Month.August, 2017))
                       .to(new Date(28, Month.February, 2026))
                       .withFrequency(Frequency.Semiannual)
                       .withCalendar(calendar)
                       .withConvention(BusinessDayConvention.Unadjusted)
                       .backwards().endOfMonth(false).value();

            Date periodStartDate = schedule.date(1);
            Date periodEndDate   = schedule.date(2);

            dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule);

            while (periodEndDate < schedule.date(schedule.size() - 2))
            {
                double expected =
                    actualActualDaycountComputation(schedule,
                                                    periodStartDate,
                                                    periodEndDate);
                double calculated = dayCounter.yearFraction(periodStartDate,
                                                            periodEndDate);

                if (Math.Abs(expected - calculated) > 1e-8)
                {
                    QAssert.Fail("Failed to compute the correct year fraction " +
                                 "given a schedule: " + periodStartDate +
                                 " to " + periodEndDate +
                                 "\n expected: " + expected +
                                 " calculated: " + calculated);
                }
                periodEndDate = calendar.advance(periodEndDate, 1, TimeUnit.Days);
            }
        }
Пример #15
0
        public void testCalibration()
        {
            // Testing calibration of a Libor forward model
            const int    size      = 14;
            const double tolerance = 8e-3;

            double[] capVols = { 0.145708, 0.158465, 0.166248, 0.168672,
                                 0.169007, 0.167956, 0.166261, 0.164239,
                                 0.162082, 0.159923, 0.157781, 0.155745,
                                 0.153776, 0.151950, 0.150189, 0.148582,
                                 0.147034, 0.145598, 0.144248 };

            double[] swaptionVols = { 0.170595, 0.166844, 0.158306, 0.147444,
                                      0.136930, 0.126833, 0.118135, 0.175963,
                                      0.166359, 0.155203, 0.143712, 0.132769,
                                      0.122947, 0.114310, 0.174455, 0.162265,
                                      0.150539, 0.138734, 0.128215, 0.118470,
                                      0.110540, 0.169780, 0.156860, 0.144821,
                                      0.133537, 0.123167, 0.114363, 0.106500,
                                      0.164521, 0.151223, 0.139670, 0.128632,
                                      0.119123, 0.110330, 0.103114, 0.158956,
                                      0.146036, 0.134555, 0.124393, 0.115038,
                                      0.106996, 0.100064 };

            IborIndex index = makeIndex();
            LiborForwardModelProcess    process       = new LiborForwardModelProcess(size, index);
            Handle <YieldTermStructure> termStructure = index.forwardingTermStructure();

            // set-up the model
            LmVolatilityModel volaModel = new LmExtLinearExponentialVolModel(process.fixingTimes(),
                                                                             0.5, 0.6, 0.1, 0.1);

            LmCorrelationModel corrModel = new LmLinearExponentialCorrelationModel(size, 0.5, 0.8);

            LiborForwardModel model = new LiborForwardModel(process, volaModel, corrModel);

            int        swapVolIndex = 0;
            DayCounter dayCounter   = index.forwardingTermStructure().link.dayCounter();

            // set-up calibration helper
            List <CalibrationHelper> calibrationHelper = new List <CalibrationHelper>();

            int i;

            for (i = 2; i < size; ++i)
            {
                Period         maturity = i * index.tenor();
                Handle <Quote> capVol   = new Handle <Quote>(new SimpleQuote(capVols[i - 2]));

                CalibrationHelper caphelper = new CapHelper(maturity, capVol, index, Frequency.Annual,
                                                            index.dayCounter(), true, termStructure, CalibrationHelper.CalibrationErrorType.ImpliedVolError);

                caphelper.setPricingEngine(new AnalyticCapFloorEngine(model, termStructure));

                calibrationHelper.Add(caphelper);

                if (i <= size / 2)
                {
                    // add a few swaptions to test swaption calibration as well
                    for (int j = 1; j <= size / 2; ++j)
                    {
                        Period         len         = j * index.tenor();
                        Handle <Quote> swaptionVol = new Handle <Quote>(
                            new SimpleQuote(swaptionVols[swapVolIndex++]));

                        CalibrationHelper swaptionHelper =
                            new SwaptionHelper(maturity, len, swaptionVol, index,
                                               index.tenor(), dayCounter,
                                               index.dayCounter(),
                                               termStructure, CalibrationHelper.CalibrationErrorType.ImpliedVolError);

                        swaptionHelper.setPricingEngine(new LfmSwaptionEngine(model, termStructure));

                        calibrationHelper.Add(swaptionHelper);
                    }
                }
            }

            LevenbergMarquardt om = new LevenbergMarquardt(1e-6, 1e-6, 1e-6);

            //ConjugateGradient gc = new ConjugateGradient();

            model.calibrate(calibrationHelper,
                            om,
                            new EndCriteria(2000, 100, 1e-6, 1e-6, 1e-6),
                            new Constraint(),
                            new List <double>());

            // measure the calibration error
            double calculated = 0.0;

            for (i = 0; i < calibrationHelper.Count; ++i)
            {
                double diff = calibrationHelper[i].calibrationError();
                calculated += diff * diff;
            }

            if (Math.Sqrt(calculated) > tolerance)
            {
                QAssert.Fail("Failed to calibrate libor forward model"
                             + "\n    calculated diff: " + Math.Sqrt(calculated)
                             + "\n    expected : smaller than  " + tolerance);
            }
        }
Пример #16
0
        public void testCachedMarketValue()
        {
            // Testing credit-default swap against cached market values...

            using (SavedSettings backup = new SavedSettings())
            {
                Settings.setEvaluationDate(new Date(9, Month.June, 2006));
                Date     evalDate = Settings.evaluationDate();
                Calendar calendar = new UnitedStates();

                List <Date> discountDates = new List <Date>();
                discountDates.Add(evalDate);
                discountDates.Add(calendar.advance(evalDate, 1, TimeUnit.Weeks, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 1, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 2, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 3, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 6, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 12, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 2, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 3, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 4, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 5, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 6, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 7, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 8, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 9, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 10, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                discountDates.Add(calendar.advance(evalDate, 15, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));

                List <double> dfs = new List <double>();
                dfs.Add(1.0);
                dfs.Add(0.9990151375768731);
                dfs.Add(0.99570502636871183);
                dfs.Add(0.99118260474528685);
                dfs.Add(0.98661167950906203);
                dfs.Add(0.9732592953359388);
                dfs.Add(0.94724424481038083);
                dfs.Add(0.89844996737120875);
                dfs.Add(0.85216647839921411);
                dfs.Add(0.80775477692556874);
                dfs.Add(0.76517289234200347);
                dfs.Add(0.72401019553182933);
                dfs.Add(0.68503909569219212);
                dfs.Add(0.64797499814013748);
                dfs.Add(0.61263171936255534);
                dfs.Add(0.5791942350748791);
                dfs.Add(0.43518868769953606);

                DayCounter curveDayCounter = new Actual360();

                RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>();
                discountCurve.linkTo(new InterpolatedDiscountCurve <LogLinear>(discountDates, dfs, curveDayCounter, null, null, null, new LogLinear()));

                DayCounter  dayCounter = new Thirty360();
                List <Date> dates      = new List <Date>();
                dates.Add(evalDate);
                dates.Add(calendar.advance(evalDate, 6, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing));
                dates.Add(calendar.advance(evalDate, 1, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                dates.Add(calendar.advance(evalDate, 2, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                dates.Add(calendar.advance(evalDate, 3, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                dates.Add(calendar.advance(evalDate, 4, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                dates.Add(calendar.advance(evalDate, 5, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                dates.Add(calendar.advance(evalDate, 7, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));
                dates.Add(calendar.advance(evalDate, 10, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing));

                List <double> defaultProbabilities = new List <double>();
                defaultProbabilities.Add(0.0000);
                defaultProbabilities.Add(0.0047);
                defaultProbabilities.Add(0.0093);
                defaultProbabilities.Add(0.0286);
                defaultProbabilities.Add(0.0619);
                defaultProbabilities.Add(0.0953);
                defaultProbabilities.Add(0.1508);
                defaultProbabilities.Add(0.2288);
                defaultProbabilities.Add(0.3666);

                List <double> hazardRates = new List <double>();
                hazardRates.Add(0.0);
                for (int i = 1; i < dates.Count; ++i)
                {
                    double t1 = dayCounter.yearFraction(dates[0], dates[i - 1]);
                    double t2 = dayCounter.yearFraction(dates[0], dates[i]);
                    double S1 = 1.0 - defaultProbabilities[i - 1];
                    double S2 = 1.0 - defaultProbabilities[i];
                    hazardRates.Add(Math.Log(S1 / S2) / (t2 - t1));
                }

                RelinkableHandle <DefaultProbabilityTermStructure> piecewiseFlatHazardRate = new RelinkableHandle <DefaultProbabilityTermStructure>();
                piecewiseFlatHazardRate.linkTo(new InterpolatedHazardRateCurve <BackwardFlat>(dates, hazardRates, new Thirty360()));

                // Testing credit default swap

                // Build the schedule
                Date                  issueDate     = new Date(20, Month.March, 2006);
                Date                  maturity      = new Date(20, Month.June, 2013);
                Frequency             cdsFrequency  = Frequency.Semiannual;
                BusinessDayConvention cdsConvention = BusinessDayConvention.ModifiedFollowing;

                Schedule schedule = new Schedule(issueDate, maturity, new Period(cdsFrequency), calendar,
                                                 cdsConvention, cdsConvention,
                                                 DateGeneration.Rule.Forward, false);

                // Build the CDS
                double     recoveryRate = 0.25;
                double     fixedRate    = 0.0224;
                DayCounter dayCount     = new Actual360();
                double     cdsNotional  = 100.0;

                CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, cdsNotional, fixedRate,
                                                              schedule, cdsConvention, dayCount, true, true);
                cds.setPricingEngine(new MidPointCdsEngine(piecewiseFlatHazardRate, recoveryRate, discountCurve));

                double calculatedNpv      = cds.NPV();
                double calculatedFairRate = cds.fairSpread();

                double npv      = -1.364048777; // from Bloomberg we have 98.15598868 - 100.00;
                double fairRate = 0.0248429452; // from Bloomberg we have 0.0258378;

                double tolerance = 1e-9;

                if (Math.Abs(npv - calculatedNpv) > tolerance)
                {
                    QAssert.Fail(
                        "Failed to reproduce the npv for the given credit-default swap\n"
                        + "    computed NPV:  " + calculatedNpv + "\n"
                        + "    Given NPV:     " + npv);
                }

                if (Math.Abs(fairRate - calculatedFairRate) > tolerance)
                {
                    QAssert.Fail("Failed to reproduce the fair rate for the given credit-default swap\n"
                                 + "    computed fair rate:  " + calculatedFairRate + "\n"
                                 + "    Given fair rate:     " + fairRate);
                }
            }
        }
Пример #17
0
        public void testSwaptionPricing()
        {
            // Testing forward swap and swaption pricing
            const int size  = 10;
            const int steps = 8 * size;

#if QL_USE_INDEXED_COUPON
            const double tolerance = 1e-6;
#else
            const double tolerance = 1e-12;
#endif

            List <Date>   dates = new List <Date>();
            List <double> rates = new List <double>();
            dates.Add(new Date(4, 9, 2005));
            dates.Add(new Date(4, 9, 2011));
            rates.Add(0.04);
            rates.Add(0.08);

            IborIndex index = makeIndex(dates, rates);

            LiborForwardModelProcess process = new LiborForwardModelProcess(size, index);

            LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.5);

            LmVolatilityModel volaModel = new LmLinearExponentialVolatilityModel(process.fixingTimes(),
                                                                                 0.291, 1.483, 0.116, 0.00001);

            // set-up pricing engine
            process.setCovarParam((LfmCovarianceParameterization)
                                  new LfmCovarianceProxy(volaModel, corrModel));

            // set-up a small Monte-Carlo simulation to price swations
            List <double> tmp = process.fixingTimes();

            TimeGrid grid = new TimeGrid(tmp, tmp.Count, steps);

            List <int> location = new List <int>();
            for (int i = 0; i < tmp.Count; ++i)
            {
                location.Add(grid.index(tmp[i]));
            }

            ulong     seed     = 42;
            const int nrTrails = 5000;
            LowDiscrepancy.icInstance = new InverseCumulativeNormal();

            IRNG rsg = (InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng>
                                              , InverseCumulativeNormal>)
                       new PseudoRandom().make_sequence_generator(process.factors() * (grid.size() - 1), seed);



            MultiPathGenerator <IRNG> generator = new MultiPathGenerator <IRNG>(process,
                                                                                grid,
                                                                                rsg, false);

            LiborForwardModel liborModel = new LiborForwardModel(process, volaModel, corrModel);

            Calendar              calendar   = index.fixingCalendar();
            DayCounter            dayCounter = index.forwardingTermStructure().link.dayCounter();
            BusinessDayConvention convention = index.businessDayConvention();

            Date settlement = index.forwardingTermStructure().link.referenceDate();

            SwaptionVolatilityMatrix m = liborModel.getSwaptionVolatilityMatrix();

            for (int i = 1; i < size; ++i)
            {
                for (int j = 1; j <= size - i; ++j)
                {
                    Date fwdStart    = settlement + new Period(6 * i, TimeUnit.Months);
                    Date fwdMaturity = fwdStart + new Period(6 * j, TimeUnit.Months);

                    Schedule schedule = new Schedule(fwdStart, fwdMaturity, index.tenor(), calendar,
                                                     convention, convention, DateGeneration.Rule.Forward, false);

                    double      swapRate    = 0.0404;
                    VanillaSwap forwardSwap = new VanillaSwap(VanillaSwap.Type.Receiver, 1.0,
                                                              schedule, swapRate, dayCounter,
                                                              schedule, index, 0.0, index.dayCounter());
                    forwardSwap.setPricingEngine(new DiscountingSwapEngine(index.forwardingTermStructure()));

                    // check forward pricing first
                    double expected   = forwardSwap.fairRate();
                    double calculated = liborModel.S_0(i - 1, i + j - 1);

                    if (Math.Abs(expected - calculated) > tolerance)
                    {
                        QAssert.Fail("Failed to reproduce fair forward swap rate"
                                     + "\n    calculated: " + calculated
                                     + "\n    expected:   " + expected);
                    }

                    swapRate    = forwardSwap.fairRate();
                    forwardSwap =
                        new VanillaSwap(VanillaSwap.Type.Receiver, 1.0,
                                        schedule, swapRate, dayCounter,
                                        schedule, index, 0.0, index.dayCounter());
                    forwardSwap.setPricingEngine(new DiscountingSwapEngine(index.forwardingTermStructure()));

                    if (i == j && i <= size / 2)
                    {
                        IPricingEngine engine =
                            new LfmSwaptionEngine(liborModel, index.forwardingTermStructure());
                        Exercise exercise =
                            new EuropeanExercise(process.fixingDates()[i]);

                        Swaption swaption =
                            new Swaption(forwardSwap, exercise);
                        swaption.setPricingEngine(engine);

                        GeneralStatistics stat = new GeneralStatistics();

                        for (int n = 0; n < nrTrails; ++n)
                        {
                            Sample <IPath> path = (n % 2 != 0) ? generator.antithetic()
                                          : generator.next();
                            MultiPath value = path.value as MultiPath;
                            Utils.QL_REQUIRE(value != null, () => "Invalid Path");
                            //Sample<MultiPath> path = generator.next();
                            List <double> rates_ = new InitializedList <double>(size);
                            for (int k = 0; k < process.size(); ++k)
                            {
                                rates_[k] = value[k][location[i]];
                            }
                            List <double> dis = process.discountBond(rates_);

                            double npv = 0.0;
                            for (int k = i; k < i + j; ++k)
                            {
                                npv += (swapRate - rates_[k])
                                       * (process.accrualEndTimes()[k]
                                          - process.accrualStartTimes()[k]) * dis[k];
                            }
                            stat.add(Math.Max(npv, 0.0));
                        }

                        if (Math.Abs(swaption.NPV() - stat.mean())
                            > stat.errorEstimate() * 2.35)
                        {
                            QAssert.Fail("Failed to reproduce swaption npv"
                                         + "\n    calculated: " + stat.mean()
                                         + "\n    expected:   " + swaption.NPV());
                        }
                    }
                }
            }
        }
Пример #18
0
        public void testImpliedHazardRate()
        {
            // Testing implied hazard-rate for credit-default swaps...

            using (SavedSettings backup = new SavedSettings())
            {
                // Initialize curves
                Calendar calendar = new TARGET();
                Date     today    = calendar.adjust(Date.Today);
                Settings.setEvaluationDate(today);

                double     h1 = 0.30, h2 = 0.40;
                DayCounter dayCounter = new Actual365Fixed();

                List <Date>   dates       = new List <Date>(3);
                List <double> hazardRates = new List <double>(3);
                dates.Add(today);
                hazardRates.Add(h1);

                dates.Add(today + new Period(5, TimeUnit.Years));
                hazardRates.Add(h1);

                dates.Add(today + new Period(10, TimeUnit.Years));
                hazardRates.Add(h2);

                RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve =
                    new RelinkableHandle <DefaultProbabilityTermStructure>();
                probabilityCurve.linkTo(new InterpolatedHazardRateCurve <BackwardFlat>(dates,
                                                                                       hazardRates,
                                                                                       dayCounter));

                RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>();
                discountCurve.linkTo(new FlatForward(today, 0.03, new Actual360()));

                Frequency             frequency  = Frequency.Semiannual;
                BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing;

                Date       issueDate    = calendar.advance(today, -6, TimeUnit.Months);
                double     fixedRate    = 0.0120;
                DayCounter cdsDayCount  = new Actual360();
                double     notional     = 10000.0;
                double     recoveryRate = 0.4;

                double?latestRate = null;
                for (int n = 6; n <= 10; ++n)
                {
                    Date     maturity = calendar.advance(issueDate, n, TimeUnit.Years);
                    Schedule schedule = new Schedule(issueDate, maturity, new Period(frequency), calendar,
                                                     convention, convention,
                                                     DateGeneration.Rule.Forward, false);

                    CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate,
                                                                  schedule, convention, cdsDayCount, true, true);
                    cds.setPricingEngine(new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve));

                    double NPV      = cds.NPV();
                    double flatRate = cds.impliedHazardRate(NPV, discountCurve,
                                                            dayCounter,
                                                            recoveryRate);

                    if (flatRate < h1 || flatRate > h2)
                    {
                        QAssert.Fail("implied hazard rate outside expected range\n"
                                     + "    maturity: " + n + " years\n"
                                     + "    expected minimum: " + h1 + "\n"
                                     + "    expected maximum: " + h2 + "\n"
                                     + "    implied rate:     " + flatRate);
                    }

                    if (n > 6 && flatRate < latestRate)
                    {
                        QAssert.Fail("implied hazard rate decreasing with swap maturity\n"
                                     + "    maturity: " + n + " years\n"
                                     + "    previous rate: " + latestRate + "\n"
                                     + "    implied rate:  " + flatRate);
                    }

                    latestRate = flatRate;

                    RelinkableHandle <DefaultProbabilityTermStructure> probability = new RelinkableHandle <DefaultProbabilityTermStructure>();
                    probability.linkTo(new FlatHazardRate(today, new Handle <Quote>(new SimpleQuote(flatRate)), dayCounter));

                    CreditDefaultSwap cds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate,
                                                                   schedule, convention, cdsDayCount, true, true);
                    cds2.setPricingEngine(new MidPointCdsEngine(probability, recoveryRate, discountCurve));

                    double NPV2      = cds2.NPV();
                    double tolerance = 1.0;
                    if (Math.Abs(NPV - NPV2) > tolerance)
                    {
                        QAssert.Fail("failed to reproduce NPV with implied rate\n"
                                     + "    expected:   " + NPV + "\n"
                                     + "    calculated: " + NPV2);
                    }
                }
            }
        }
Пример #19
0
        public void testCalibration()
        {
            double forward = 0.03;
            double tau     = 1.0;

            //Real a = 0.04;
            //Real b = 0.1;
            //Real rho = -0.5;
            //Real sigma = 0.1;
            //Real m  = 0.0;
            double a     = 0.1;
            double b     = 0.06;
            double rho   = -0.9;
            double m     = 0.24;
            double sigma = 0.06;

            List <double> strikes = new List <double>();

            strikes.Add(0.01);
            strikes.Add(0.015);
            strikes.Add(0.02);
            strikes.Add(0.025);
            strikes.Add(0.03);
            strikes.Add(0.035);
            strikes.Add(0.04);
            strikes.Add(0.045);
            strikes.Add(0.05);

            List <double> vols = new InitializedList <double>(strikes.Count, 0.20); //dummy vols (we do not calibrate here)

            SviInterpolation svi = new SviInterpolation(strikes, strikes.Count, vols, tau,
                                                        forward, a, b, sigma, rho, m, true, true, true,
                                                        true, true);

            svi.enableExtrapolation();

            List <double> sviVols = new InitializedList <double>(strikes.Count, 0.0);

            for (int i = 0; i < strikes.Count; ++i)
            {
                sviVols[i] = svi.value(strikes[i]);
            }

            SviInterpolation svi2 = new SviInterpolation(strikes, strikes.Count, sviVols, tau,
                                                         forward, null, null, null,
                                                         null, null, false, false, false,
                                                         false, false, false, null,
                                                         null, 1E-8, false,
                                                         0); //don't allow for random start values

            svi2.enableExtrapolation();
            svi2.update();

            testOutputHelper.WriteLine("a=" + svi2.a());
            if (!Utils.close_enough(a, svi2.a(), 100))
            {
                QAssert.Fail("error in a coefficient estimation");
            }

            testOutputHelper.WriteLine("b=" + svi2.b());
            if (!Utils.close_enough(b, svi2.b(), 100))
            {
                QAssert.Fail("error in b coefficient estimation");
            }

            testOutputHelper.WriteLine("sigma=" + svi2.sigma());
            if (!Utils.close_enough(sigma, svi2.sigma(), 100))
            {
                QAssert.Fail("error in sigma coefficient estimation");
            }

            testOutputHelper.WriteLine("rho=" + svi2.rho());
            if (!Utils.close_enough(rho, svi2.rho(), 100))
            {
                QAssert.Fail("error in rho coefficient estimation");
            }

            testOutputHelper.WriteLine("m=" + svi2.m());
            if (!Utils.close_enough(m, svi2.m(), 100))
            {
                QAssert.Fail("error in m coefficient estimation");
            }

            testOutputHelper.WriteLine("error=" + svi2.rmsError());
        }
Пример #20
0
        public void testCachedValue()
        {
            // Testing credit-default swap against cached values...

            using (SavedSettings backup = new SavedSettings())
            {
                // Initialize curves
                Settings.setEvaluationDate(new Date(9, Month.June, 2006));
                Date     today    = Settings.evaluationDate();
                Calendar calendar = new TARGET();

                Handle <Quote> hazardRate = new Handle <Quote>(new SimpleQuote(0.01234));
                RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle <DefaultProbabilityTermStructure>();
                probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360()));

                RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>();

                discountCurve.linkTo(new FlatForward(today, 0.06, new Actual360()));

                // Build the schedule
                Date                  issueDate  = calendar.advance(today, -1, TimeUnit.Years);
                Date                  maturity   = calendar.advance(issueDate, 10, TimeUnit.Years);
                Frequency             frequency  = Frequency.Semiannual;
                BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing;

                Schedule schedule = new Schedule(issueDate, maturity, new Period(frequency), calendar,
                                                 convention, convention, DateGeneration.Rule.Forward, false);

                // Build the CDS
                double     fixedRate    = 0.0120;
                DayCounter dayCount     = new Actual360();
                double     notional     = 10000.0;
                double     recoveryRate = 0.4;

                CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate,
                                                              schedule, convention, dayCount, true, true);
                cds.setPricingEngine(new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve));

                double npv      = 295.0153398;
                double fairRate = 0.007517539081;

                double calculatedNpv      = cds.NPV();
                double calculatedFairRate = cds.fairSpread();
                double tolerance          = 1.0e-7;

                if (Math.Abs(calculatedNpv - npv) > tolerance)
                {
                    QAssert.Fail(
                        "Failed to reproduce NPV with mid-point engine\n"
                        + "    calculated NPV: " + calculatedNpv + "\n"
                        + "    expected NPV:   " + npv);
                }

                if (Math.Abs(calculatedFairRate - fairRate) > tolerance)
                {
                    QAssert.Fail(
                        "Failed to reproduce fair rate with mid-point engine\n"
                        + "    calculated fair rate: " + calculatedFairRate + "\n"
                        + "    expected fair rate:   " + fairRate);
                }

                cds.setPricingEngine(new IntegralCdsEngine(new Period(1, TimeUnit.Days), probabilityCurve,
                                                           recoveryRate, discountCurve));

                calculatedNpv      = cds.NPV();
                calculatedFairRate = cds.fairSpread();
                tolerance          = 1.0e-5;

                if (Math.Abs(calculatedNpv - npv) > notional * tolerance * 10)
                {
                    QAssert.Fail(
                        "Failed to reproduce NPV with integral engine "
                        + "(step = 1 day)\n"
                        + "    calculated NPV: " + calculatedNpv + "\n"
                        + "    expected NPV:   " + npv);
                }

                if (Math.Abs(calculatedFairRate - fairRate) > tolerance)
                {
                    QAssert.Fail(
                        "Failed to reproduce fair rate with integral engine "
                        + "(step = 1 day)\n"
                        + "    calculated fair rate: " + calculatedFairRate + "\n"
                        + "    expected fair rate:   " + fairRate);
                }

                cds.setPricingEngine(new IntegralCdsEngine(new Period(1, TimeUnit.Weeks), probabilityCurve, recoveryRate, discountCurve));

                calculatedNpv      = cds.NPV();
                calculatedFairRate = cds.fairSpread();
                tolerance          = 1.0e-5;

                if (Math.Abs(calculatedNpv - npv) > notional * tolerance * 10)
                {
                    QAssert.Fail(
                        "Failed to reproduce NPV with integral engine "
                        + "(step = 1 week)\n"
                        + "    calculated NPV: " + calculatedNpv + "\n"
                        + "    expected NPV:   " + npv);
                }

                if (Math.Abs(calculatedFairRate - fairRate) > tolerance)
                {
                    QAssert.Fail(
                        "Failed to reproduce fair rate with integral engine "
                        + "(step = 1 week)\n"
                        + "    calculated fair rate: " + calculatedFairRate + "\n"
                        + "    expected fair rate:   " + fairRate);
                }
            }
        }
Пример #21
0
        public void testCachedHullWhite()
        {
            //("Testing Hull-White calibration against cached values...");

            Date today      = new Date(15, Month.February, 2002);
            Date settlement = new Date(19, Month.February, 2002);

            Settings.setEvaluationDate(today);
            Handle <YieldTermStructure> termStructure =
                new Handle <YieldTermStructure>(Utilities.flatRate(settlement, 0.04875825, new Actual365Fixed()));
            //termStructure.link
            HullWhite model = new HullWhite(termStructure);

            CalibrationData[] data = { new CalibrationData(1, 5, 0.1148),
                                       new CalibrationData(2, 4, 0.1108),
                                       new CalibrationData(3, 3, 0.1070),
                                       new CalibrationData(4, 2, 0.1021),
                                       new CalibrationData(5, 1, 0.1000) };
            IborIndex         index = new Euribor6M(termStructure);

            IPricingEngine engine = new JamshidianSwaptionEngine(model);

            List <CalibrationHelper> swaptions = new List <CalibrationHelper>();

            for (int i = 0; i < data.Length; i++)
            {
                Quote             vol    = new SimpleQuote(data[i].volatility);
                CalibrationHelper helper =
                    new SwaptionHelper(new Period(data[i].start, TimeUnit.Years),
                                       new Period(data[i].length, TimeUnit.Years),
                                       new Handle <Quote>(vol),
                                       index,
                                       new Period(1, TimeUnit.Years),
                                       new Thirty360(),
                                       new Actual360(),
                                       termStructure);
                helper.setPricingEngine(engine);
                swaptions.Add(helper);
            }

            // Set up the optimization problem
            // Real simplexLambda = 0.1;
            // Simplex optimizationMethod(simplexLambda);
            LevenbergMarquardt optimizationMethod = new LevenbergMarquardt(1.0e-8, 1.0e-8, 1.0e-8);
            EndCriteria        endCriteria        = new EndCriteria(10000, 100, 1e-6, 1e-8, 1e-8);

            //Optimize
            model.calibrate(swaptions, optimizationMethod, endCriteria, new Constraint(), new List <double>());
            EndCriteria.Type ecType = model.endCriteria();

            // Check and print out results
#if QL_USE_INDEXED_COUPON
            double cachedA = 0.0488199, cachedSigma = 0.00593579;
#else
            double cachedA = 0.0488565, cachedSigma = 0.00593662;
#endif
            double tolerance = 1.120e-5;
            //double tolerance = 1.0e-6;
            Vector xMinCalculated = model.parameters();
            double yMinCalculated = model.value(xMinCalculated, swaptions);
            Vector xMinExpected   = new Vector(2);
            xMinExpected[0] = cachedA;
            xMinExpected[1] = cachedSigma;
            double yMinExpected = model.value(xMinExpected, swaptions);
            if (Math.Abs(xMinCalculated[0] - cachedA) > tolerance ||
                Math.Abs(xMinCalculated[1] - cachedSigma) > tolerance)
            {
                QAssert.Fail("Failed to reproduce cached calibration results:\n"
                             + "calculated: a = " + xMinCalculated[0] + ", "
                             + "sigma = " + xMinCalculated[1] + ", "
                             + "f(a) = " + yMinCalculated + ",\n"
                             + "expected:   a = " + xMinExpected[0] + ", "
                             + "sigma = " + xMinExpected[1] + ", "
                             + "f(a) = " + yMinExpected + ",\n"
                             + "difference: a = " + (xMinCalculated[0] - xMinExpected[0]) + ", "
                             + "sigma = " + (xMinCalculated[1] - xMinExpected[1]) + ", "
                             + "f(a) = " + (yMinCalculated - yMinExpected) + ",\n"
                             + "end criteria = " + ecType);
            }
        }
Пример #22
0
        public void testFairUpfront()
        {
            // Testing fair-upfront calculation for credit-default swaps...

            using (SavedSettings backup = new SavedSettings())
            {
                // Initialize curves
                Calendar calendar = new TARGET();
                Date     today    = calendar.adjust(Date.Today);
                Settings.setEvaluationDate(today);

                Handle <Quote> hazardRate = new Handle <Quote>(new SimpleQuote(0.01234));
                RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve =
                    new RelinkableHandle <DefaultProbabilityTermStructure>();
                probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360()));

                RelinkableHandle <YieldTermStructure> discountCurve =
                    new RelinkableHandle <YieldTermStructure>();
                discountCurve.linkTo(new FlatForward(today, 0.06, new Actual360()));

                // Build the schedule
                Date issueDate = today;
                Date maturity  = calendar.advance(issueDate, 10, TimeUnit.Years);
                BusinessDayConvention convention = BusinessDayConvention.Following;

                Schedule schedule =
                    new MakeSchedule().from(issueDate)
                    .to(maturity)
                    .withFrequency(Frequency.Quarterly)
                    .withCalendar(calendar)
                    .withTerminationDateConvention(convention)
                    .withRule(DateGeneration.Rule.TwentiethIMM).value();

                // Build the CDS
                double     fixedRate    = 0.05;
                double     upfront      = 0.001;
                DayCounter dayCount     = new Actual360();
                double     notional     = 10000.0;
                double     recoveryRate = 0.4;

                IPricingEngine engine = new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve, true);

                CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, upfront, fixedRate,
                                                              schedule, convention, dayCount, true, true);
                cds.setPricingEngine(engine);

                double fairUpfront = cds.fairUpfront();

                CreditDefaultSwap fairCds = new CreditDefaultSwap(Protection.Side.Seller, notional,
                                                                  fairUpfront, fixedRate, schedule, convention, dayCount, true, true);
                fairCds.setPricingEngine(engine);

                double fairNPV   = fairCds.NPV();
                double tolerance = 1e-10;

                if (Math.Abs(fairNPV) > tolerance)
                {
                    QAssert.Fail(
                        "Failed to reproduce null NPV with calculated fair upfront\n"
                        + "    calculated upfront: " + fairUpfront + "\n"
                        + "    calculated NPV:     " + fairNPV);
                }

                // same with null upfront to begin with
                upfront = 0.0;
                CreditDefaultSwap cds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, upfront, fixedRate,
                                                               schedule, convention, dayCount, true, true);
                cds2.setPricingEngine(engine);

                fairUpfront = cds2.fairUpfront();

                CreditDefaultSwap fairCds2 = new CreditDefaultSwap(Protection.Side.Seller, notional,
                                                                   fairUpfront, fixedRate, schedule, convention, dayCount, true, true);
                fairCds2.setPricingEngine(engine);

                fairNPV = fairCds2.NPV();

                if (Math.Abs(fairNPV) > tolerance)
                {
                    QAssert.Fail(
                        "Failed to reproduce null NPV with calculated fair upfront\n"
                        + "    calculated upfront: " + fairUpfront + "\n"
                        + "    calculated NPV:     " + fairNPV);
                }
            }
        }
Пример #23
0
        public void testMultiple(StochasticProcess process,
                                 string tag,
                                 double[] expected,
                                 double[] antithetic)
        {
            ulong  seed      = 42;
            double length    = 10;
            int    timeSteps = 12;
            int    assets    = process.size();

            var rsg = (InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng>
                                             , InverseCumulativeNormal>)
                      new PseudoRandom().make_sequence_generator(timeSteps * assets, seed);

            MultiPathGenerator <IRNG> generator = new MultiPathGenerator <IRNG>(process,
                                                                                new TimeGrid(length, timeSteps),
                                                                                rsg, false);
            int i;

            for (i = 0; i < 100; i++)
            {
                generator.next();
            }

            Sample <IPath> sample = generator.next();
            MultiPath      value  = sample.value as MultiPath;

            Utils.QL_REQUIRE(value != null, () => "Invalid Path");
            Vector calculated = new Vector(assets);
            double error, tolerance = 2.0e-7;

            for (int j = 0; j < assets; j++)
            {
                calculated[j] = value[j].back();
            }

            for (int j = 0; j < assets; j++)
            {
                error = Math.Abs(calculated[j] - expected[j]);
                if (error > tolerance)
                {
                    QAssert.Fail("using " + tag + " process "
                                 + "(" + j + 1 + " asset:)\n"
                                 //+ std::setprecision(13)
                                 + "    calculated: " + calculated[j] + "\n"
                                 + "    expected:   " + expected[j] + "\n"
                                 + "    error:      " + error + "\n"
                                 + "    tolerance:  " + tolerance);
                }
            }

            sample = generator.antithetic();
            value  = sample.value as MultiPath;
            Utils.QL_REQUIRE(value != null, () => "Invalid Path");
            for (int j = 0; j < assets; j++)
            {
                calculated[j] = value[j].back();
            }
            for (int j = 0; j < assets; j++)
            {
                error = Math.Abs(calculated[j] - antithetic[j]);
                if (error > tolerance)
                {
                    QAssert.Fail("using " + tag + " process "
                                 + "(" + j + 1 + " asset:)\n"
                                 + "antithetic sample:\n"
                                 //+ std::setprecision(13)
                                 + "    calculated: " + calculated[j] + "\n"
                                 + "    expected:   " + antithetic[j] + "\n"
                                 + "    error:      " + error + "\n"
                                 + "    tolerance:  " + tolerance);
                }
            }
        }
Пример #24
0
        public void testDefaultProbability()
        {
            // Testing default-probability structure...

            double         hazardRate      = 0.0100;
            Handle <Quote> hazardRateQuote = new Handle <Quote>(new SimpleQuote(hazardRate));
            DayCounter     dayCounter      = new Actual360();
            Calendar       calendar        = new TARGET();
            int            n = 20;

            double tolerance = 1.0e-10;
            Date   today     = Settings.evaluationDate();
            Date   startDate = today;
            Date   endDate   = startDate;

            FlatHazardRate flatHazardRate = new FlatHazardRate(startDate, hazardRateQuote, dayCounter);

            for (int i = 0; i < n; i++)
            {
                startDate = endDate;
                endDate   = calendar.advance(endDate, 1, TimeUnit.Years);

                double pStart = flatHazardRate.defaultProbability(startDate);
                double pEnd   = flatHazardRate.defaultProbability(endDate);

                double pBetweenComputed =
                    flatHazardRate.defaultProbability(startDate, endDate);

                double pBetween = pEnd - pStart;

                if (Math.Abs(pBetween - pBetweenComputed) > tolerance)
                {
                    QAssert.Fail("Failed to reproduce probability(d1, d2) "
                                 + "for default probability structure\n"
                                 + "    calculated probability: " + pBetweenComputed + "\n"
                                 + "    expected probability:   " + pBetween);
                }

                double t2 = dayCounter.yearFraction(today, endDate);
                double timeProbability = flatHazardRate.defaultProbability(t2);
                double dateProbability =
                    flatHazardRate.defaultProbability(endDate);

                if (Math.Abs(timeProbability - dateProbability) > tolerance)
                {
                    QAssert.Fail("single-time probability and single-date probability do not match\n"
                                 + "    time probability: " + timeProbability + "\n"
                                 + "    date probability: " + dateProbability);
                }

                double t1 = dayCounter.yearFraction(today, startDate);
                timeProbability = flatHazardRate.defaultProbability(t1, t2);
                dateProbability = flatHazardRate.defaultProbability(startDate, endDate);

                if (Math.Abs(timeProbability - dateProbability) > tolerance)
                {
                    QAssert.Fail("double-time probability and double-date probability do not match\n"
                                 + "    time probability: " + timeProbability + "\n"
                                 + "    date probability: " + dateProbability);
                }
            }
        }
Пример #25
0
        public void testCachedValues()
        {
            //("Testing Bermudan swaption against cached values...");

            CommonVars vars = new CommonVars();

            vars.today = new Date(15, Month.February, 2002);

            Settings.Instance.setEvaluationDate(vars.today);

            vars.settlement = new Date(19, Month.February, 2002);
            // flat yield term structure impling 1x5 swap at 5%
            vars.termStructure.linkTo(Utilities.flatRate(vars.settlement,
                                                         0.04875825,
                                                         new Actual365Fixed()));

            double atmRate = vars.makeSwap(0.0).fairRate();

            VanillaSwap itmSwap = vars.makeSwap(0.8 * atmRate);
            VanillaSwap atmSwap = vars.makeSwap(atmRate);
            VanillaSwap otmSwap = vars.makeSwap(1.2 * atmRate);

            double          a = 0.048696, sigma = 0.0058904;
            ShortRateModel  model         = new HullWhite(vars.termStructure, a, sigma);
            List <Date>     exerciseDates = new List <Date>();
            List <CashFlow> leg           = atmSwap.fixedLeg();

            for (int i = 0; i < leg.Count; i++)
            {
                Coupon coupon = (Coupon)(leg[i]);
                exerciseDates.Add(coupon.accrualStartDate());
            }

            Exercise       exercise   = new BermudanExercise(exerciseDates);
            IPricingEngine treeEngine = new TreeSwaptionEngine(model, 50);
            IPricingEngine fdmEngine  = new FdHullWhiteSwaptionEngine(model as HullWhite);

#if QL_USE_INDEXED_COUPON
            double itmValue = 42.2413, atmValue = 12.8789, otmValue = 2.4759;
            double itmValueFdm = 42.2111, atmValueFdm = 12.8879, otmValueFdm = 2.44443;
#else
            double itmValue = 42.2470, atmValue = 12.8826, otmValue = 2.4769;
            double itmValueFdm = 42.2091, atmValueFdm = 12.8864, otmValueFdm = 2.4437;
#endif

            double tolerance = 1.0e-4;

            Swaption swaption = new Swaption(itmSwap, exercise);
            swaption.setPricingEngine(treeEngine);
            if (Math.Abs(swaption.NPV() - itmValue) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached in-the-money swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + itmValue);
            }

            swaption.setPricingEngine(fdmEngine);
            if (Math.Abs(swaption.NPV() - itmValueFdm) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached in-the-money swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + itmValueFdm);
            }

            swaption = new Swaption(atmSwap, exercise);
            swaption.setPricingEngine(treeEngine);
            if (Math.Abs(swaption.NPV() - atmValue) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached at-the-money swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + atmValue);
            }
            swaption.setPricingEngine(fdmEngine);
            if (Math.Abs(swaption.NPV() - atmValueFdm) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached at-the-money swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + atmValueFdm);
            }

            swaption = new Swaption(otmSwap, exercise);
            swaption.setPricingEngine(treeEngine);
            if (Math.Abs(swaption.NPV() - otmValue) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached out-of-the-money "
                             + "swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + otmValue);
            }
            swaption.setPricingEngine(fdmEngine);
            if (Math.Abs(swaption.NPV() - otmValueFdm) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached out-of-the-money "
                             + "swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + otmValueFdm);
            }

            for (int j = 0; j < exerciseDates.Count; j++)
            {
                exerciseDates[j] = vars.calendar.adjust(exerciseDates[j] - 10);
            }
            exercise = new BermudanExercise(exerciseDates);

#if QL_USE_INDEXED_COUPON
            itmValue = 42.1917; atmValue = 12.7788; otmValue = 2.4388;
#else
            itmValue = 42.1974; atmValue = 12.7825; otmValue = 2.4399;
#endif

            swaption = new Swaption(itmSwap, exercise);
            swaption.setPricingEngine(treeEngine);
            if (Math.Abs(swaption.NPV() - itmValue) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached in-the-money swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + itmValue);
            }

            swaption = new Swaption(atmSwap, exercise);
            swaption.setPricingEngine(treeEngine);
            if (Math.Abs(swaption.NPV() - atmValue) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached at-the-money swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + atmValue);
            }

            swaption = new Swaption(otmSwap, exercise);
            swaption.setPricingEngine(treeEngine);
            if (Math.Abs(swaption.NPV() - otmValue) > tolerance)
            {
                QAssert.Fail("failed to reproduce cached out-of-the-money "
                             + "swaption value:\n"
                             + "calculated: " + swaption.NPV() + "\n"
                             + "expected:   " + otmValue);
            }
        }
Пример #26
0
        public void RiskStatisticsTest()
        {
            //    ("Testing risk measures...");

            IncrementalGaussianStatistics igs = new IncrementalGaussianStatistics();
            RiskStatistics s = new RiskStatistics();

            double[] averages = { -100.0, -1.0, 0.0, 1.0, 100.0 };
            double[] sigmas = { 0.1, 1.0, 100.0 };
            int      i, j, k, N;

            N = (int)Math.Pow(2, 16) - 1;
            double        dataMin, dataMax;
            List <double> data = new InitializedList <double>(N), weights = new InitializedList <double>(N);

            for (i = 0; i < averages.Length; i++)
            {
                for (j = 0; j < sigmas.Length; j++)
                {
                    NormalDistribution           normal     = new NormalDistribution(averages[i], sigmas[j]);
                    CumulativeNormalDistribution cumulative = new CumulativeNormalDistribution(averages[i], sigmas[j]);
                    InverseCumulativeNormal      inverseCum = new InverseCumulativeNormal(averages[i], sigmas[j]);

                    SobolRsg rng = new SobolRsg(1);
                    dataMin = double.MaxValue;
                    dataMax = double.MinValue;
                    for (k = 0; k < N; k++)
                    {
                        data[k]    = inverseCum.value(rng.nextSequence().value[0]);
                        dataMin    = Math.Min(dataMin, data[k]);
                        dataMax    = Math.Max(dataMax, data[k]);
                        weights[k] = 1.0;
                    }

                    igs.addSequence(data, weights);
                    s.addSequence(data, weights);

                    // checks
                    double calculated, expected;
                    double tolerance;

                    if (igs.samples() != N)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong number of samples\n"
                                     + "    calculated: " + igs.samples() + "\n"
                                     + "    expected:   " + N);
                    }
                    if (s.samples() != N)
                    {
                        QAssert.Fail("RiskStatistics: wrong number of samples\n"
                                     + "    calculated: " + s.samples() + "\n"
                                     + "    expected:   " + N);
                    }


                    // weightSum()
                    tolerance  = 1e-10;
                    expected   = weights.Sum();
                    calculated = igs.weightSum();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong sum of weights\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.weightSum();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong sum of weights\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // min
                    tolerance  = 1e-12;
                    expected   = dataMin;
                    calculated = igs.min();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong minimum value\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.min();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: "
                                     + "wrong minimum value\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // max
                    expected   = dataMax;
                    calculated = igs.max();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong maximum value\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.max();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: "
                                     + "wrong maximum value\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // mean
                    expected  = averages[i];
                    tolerance = (expected == 0.0 ? 1.0e-13 :
                                 Math.Abs(expected) * 1.0e-13);
                    calculated = igs.mean();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong mean value"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.mean();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong mean value"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // variance
                    expected   = sigmas[j] * sigmas[j];
                    tolerance  = expected * 1.0e-1;
                    calculated = igs.variance();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong variance"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.variance();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong variance"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // standardDeviation
                    expected   = sigmas[j];
                    tolerance  = expected * 1.0e-1;
                    calculated = igs.standardDeviation();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong standard deviation"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.standardDeviation();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong standard deviation"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // missing errorEstimate() test

                    // skewness
                    expected   = 0.0;
                    tolerance  = 1.0e-4;
                    calculated = igs.skewness();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong skewness"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.skewness();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong skewness"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // kurtosis
                    expected   = 0.0;
                    tolerance  = 1.0e-1;
                    calculated = igs.kurtosis();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong kurtosis"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.kurtosis();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong kurtosis"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // percentile
                    expected  = averages[i];
                    tolerance = (expected == 0.0 ? 1.0e-3 :
                                 Math.Abs(expected * 1.0e-3));
                    calculated = igs.gaussianPercentile(0.5);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong Gaussian percentile"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.gaussianPercentile(0.5);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong Gaussian percentile"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.percentile(0.5);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong percentile"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }



                    // potential upside
                    double upper_tail = averages[i] + 2.0 * sigmas[j],
                           lower_tail = averages[i] - 2.0 * sigmas[j];
                    double twoSigma   = cumulative.value(upper_tail);

                    expected  = Math.Max(upper_tail, 0.0);
                    tolerance = (expected == 0.0 ? 1.0e-3 :
                                 Math.Abs(expected * 1.0e-3));
                    calculated = igs.gaussianPotentialUpside(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong Gaussian potential upside"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.gaussianPotentialUpside(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong Gaussian potential upside"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.potentialUpside(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong potential upside"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // just to check that GaussianStatistics<StatsHolder> does work
                    StatsHolder h = new StatsHolder(s.mean(), s.standardDeviation());
                    GenericGaussianStatistics <StatsHolder> test = new GenericGaussianStatistics <StatsHolder>(h);
                    expected   = s.gaussianPotentialUpside(twoSigma);
                    calculated = test.gaussianPotentialUpside(twoSigma);
                    if (calculated != expected)
                    {
                        QAssert.Fail("GenericGaussianStatistics<StatsHolder> fails"
                                     + "\n  calculated: " + calculated
                                     + "\n  expected: " + expected);
                    }


                    // value-at-risk
                    expected  = -Math.Min(lower_tail, 0.0);
                    tolerance = (expected == 0.0 ? 1.0e-3 :
                                 Math.Abs(expected * 1.0e-3));
                    calculated = igs.gaussianValueAtRisk(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong Gaussian value-at-risk"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.gaussianValueAtRisk(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong Gaussian value-at-risk"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.valueAtRisk(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong value-at-risk"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }

                    if (averages[i] > 0.0 && sigmas[j] < averages[i])
                    {
                        // no data will miss the targets:
                        // skip the rest of this iteration
                        igs.reset();
                        s.reset();
                        continue;
                    }


                    // expected shortfall
                    expected = -Math.Min(averages[i]
                                         - sigmas[j] * sigmas[j]
                                         * normal.value(lower_tail) / (1.0 - twoSigma),
                                         0.0);
                    tolerance = (expected == 0.0 ? 1.0e-4
                            : Math.Abs(expected) * 1.0e-2);
                    calculated = igs.gaussianExpectedShortfall(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong Gaussian expected shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.gaussianExpectedShortfall(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong Gaussian expected shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.expectedShortfall(twoSigma);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong expected shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // shortfall
                    expected  = 0.5;
                    tolerance = (expected == 0.0 ? 1.0e-3 :
                                 Math.Abs(expected * 1.0e-3));
                    calculated = igs.gaussianShortfall(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong Gaussian shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.gaussianShortfall(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong Gaussian shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.shortfall(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // average shortfall
                    expected   = sigmas[j] / Math.Sqrt(2.0 * Const.M_PI) * 2.0;
                    tolerance  = expected * 1.0e-3;
                    calculated = igs.gaussianAverageShortfall(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong Gaussian average shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.gaussianAverageShortfall(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong Gaussian average shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.averageShortfall(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: wrong average shortfall"
                                     + " for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // regret
                    expected   = sigmas[j] * sigmas[j];
                    tolerance  = expected * 1.0e-1;
                    calculated = igs.gaussianRegret(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong Gaussian regret(" + averages[i] + ") "
                                     + "for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.gaussianRegret(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: "
                                     + "wrong Gaussian regret(" + averages[i] + ") "
                                     + "for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = s.regret(averages[i]);
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("RiskStatistics: "
                                     + "wrong regret(" + averages[i] + ") "
                                     + "for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }


                    // downsideVariance
                    expected  = s.downsideVariance();
                    tolerance = (expected == 0.0 ? 1.0e-3 :
                                 Math.Abs(expected * 1.0e-3));
                    calculated = igs.downsideVariance();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong downside variance"
                                     + "for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }
                    calculated = igs.gaussianDownsideVariance();
                    if (Math.Abs(calculated - expected) > tolerance)
                    {
                        QAssert.Fail("IncrementalGaussianStatistics: "
                                     + "wrong Gaussian downside variance"
                                     + "for N(" + averages[i] + ", "
                                     + sigmas[j] + ")\n"
                                     + "    calculated: " + calculated + "\n"
                                     + "    expected:   " + expected + "\n"
                                     + "    tolerance:  " + tolerance);
                    }

                    // downsideVariance
                    if (averages[i] == 0.0)
                    {
                        expected   = sigmas[j] * sigmas[j];
                        tolerance  = expected * 1.0e-3;
                        calculated = igs.downsideVariance();
                        if (Math.Abs(calculated - expected) > tolerance)
                        {
                            QAssert.Fail("IncrementalGaussianStatistics: "
                                         + "wrong downside variance"
                                         + "for N(" + averages[i] + ", "
                                         + sigmas[j] + ")\n"
                                         + "    calculated: " + calculated + "\n"
                                         + "    expected:   " + expected + "\n"
                                         + "    tolerance:  " + tolerance);
                        }
                        calculated = igs.gaussianDownsideVariance();
                        if (Math.Abs(calculated - expected) > tolerance)
                        {
                            QAssert.Fail("IncrementalGaussianStatistics: "
                                         + "wrong Gaussian downside variance"
                                         + "for N(" + averages[i] + ", "
                                         + sigmas[j] + ")\n"
                                         + "    calculated: " + calculated + "\n"
                                         + "    expected:   " + expected + "\n"
                                         + "    tolerance:  " + tolerance);
                        }
                        calculated = s.downsideVariance();
                        if (Math.Abs(calculated - expected) > tolerance)
                        {
                            QAssert.Fail("RiskStatistics: wrong downside variance"
                                         + "for N(" + averages[i] + ", "
                                         + sigmas[j] + ")\n"
                                         + "    calculated: " + calculated + "\n"
                                         + "    expected:   " + expected + "\n"
                                         + "    tolerance:  " + tolerance);
                        }
                        calculated = s.gaussianDownsideVariance();
                        if (Math.Abs(calculated - expected) > tolerance)
                        {
                            QAssert.Fail("RiskStatistics: wrong Gaussian downside variance"
                                         + "for N(" + averages[i] + ", "
                                         + sigmas[j] + ")\n"
                                         + "    calculated: " + calculated + "\n"
                                         + "    expected:   " + expected + "\n"
                                         + "    tolerance:  " + tolerance);
                        }
                    }

                    igs.reset();
                    s.reset();
                }
            }
        }
Пример #27
0
        public void testSobol()
        {
            //("Testing Sobol sequences up to dimension "
            //              + PPMT_MAX_DIM + "...");

            List <double> point;
            double        tolerance = 1.0e-15;

            // testing max dimensionality
            int      dimensionality = (int)SobolRsg.PPMT_MAX_DIM;
            ulong    seed = 123456;
            SobolRsg rsg = new SobolRsg(dimensionality, seed);
            int      points = 100, i;

            for (i = 0; i < points; i++)
            {
                point = rsg.nextSequence().value;
                if (point.Count != dimensionality)
                {
                    QAssert.Fail("Sobol sequence generator returns " +
                                 " a sequence of wrong dimensionality: " + point.Count
                                 + " instead of  " + dimensionality);
                }
            }

            // testing homogeneity properties
            dimensionality = 33;
            seed           = 123456;
            rsg            = new SobolRsg(dimensionality, seed);
            SequenceStatistics stat = new SequenceStatistics(dimensionality);
            List <double>      mean;
            int k = 0;

            for (int j = 1; j < 5; j++)
            {
                // five cycle
                points = (int)(Utils.Pow(2.0, j) - 1); // base 2
                for (; k < points; k++)
                {
                    point = rsg.nextSequence().value;
                    stat.add(point);
                }
                mean = stat.mean();
                for (i = 0; i < dimensionality; i++)
                {
                    double error = Math.Abs(mean[i] - 0.5);
                    if (error > tolerance)
                    {
                        QAssert.Fail(i + 1 + " dimension: "
                                     // + QL_FIXED
                                     + "mean (" + mean[i]
                                     + ") at the end of the " + j + 1
                                     + " cycle in Sobol sequence is not " + 0.5
                                     //+ QL_SCIENTIFIC
                                     + " (error = " + error + ")");
                    }
                }
            }

            // testing first dimension (van der Corput sequence)
            double[] vanderCorputSequenceModuloTwo =
            {
                // first cycle (zero excluded)
                0.50000,
                // second cycle
                0.75000, 0.25000,
                // third cycle
                0.37500, 0.87500, 0.62500, 0.12500,
                // fourth cycle
                0.18750, 0.68750, 0.93750, 0.43750, 0.31250, 0.81250, 0.56250, 0.06250,
                // fifth cycle
                0.09375, 0.59375, 0.84375, 0.34375, 0.46875, 0.96875, 0.71875, 0.21875,
                0.15625, 0.65625, 0.90625, 0.40625, 0.28125, 0.78125, 0.53125, 0.03125
            };

            dimensionality = 1;
            rsg            = new SobolRsg(dimensionality);
            points         = (int)(Utils.Pow(2.0, 5)) - 1; // five cycles
            for (i = 0; i < points; i++)
            {
                point = rsg.nextSequence().value;
                double error = Math.Abs(point[0] - vanderCorputSequenceModuloTwo[i]);
                if (error > tolerance)
                {
                    QAssert.Fail(i + 1 + " draw ("
                                 //+ QL_FIXED
                                 + point[0]
                                 + ") in 1-D Sobol sequence is not in the "
                                 + "van der Corput sequence modulo two: "
                                 + "it should have been "
                                 + vanderCorputSequenceModuloTwo[i]
                                 //+ QL_SCIENTIFIC
                                 + " (error = " + error + ")");
                }
            }
        }
Пример #28
0
        public void testSimpleCovarianceModels()
        {
            // Testing simple covariance models
            const int    size      = 10;
            const double tolerance = 1e-14;
            int          i;

            LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.1);

            Matrix recon = corrModel.correlation(0.0, null)
                           - corrModel.pseudoSqrt(0.0, null) * Matrix.transpose(corrModel.pseudoSqrt(0.0, null));

            for (i = 0; i < size; ++i)
            {
                for (int j = 0; j < size; ++j)
                {
                    if (Math.Abs(recon[i, j]) > tolerance)
                    {
                        QAssert.Fail("Failed to reproduce correlation matrix"
                                     + "\n    calculated: " + recon[i, j]
                                     + "\n    expected:   " + 0);
                    }
                }
            }

            List <double> fixingTimes = new InitializedList <double>(size);

            for (i = 0; i < size; ++i)
            {
                fixingTimes[i] = 0.5 * i;
            }

            const double a = 0.2;
            const double b = 0.1;
            const double c = 2.1;
            const double d = 0.3;

            LmVolatilityModel volaModel = new LmLinearExponentialVolatilityModel(fixingTimes, a, b, c, d);

            LfmCovarianceProxy covarProxy = new LfmCovarianceProxy(volaModel, corrModel);

            LiborForwardModelProcess process = new LiborForwardModelProcess(size, makeIndex());

            LiborForwardModel liborModel = new LiborForwardModel(process, volaModel, corrModel);

            for (double t = 0; t < 4.6; t += 0.31)
            {
                recon = covarProxy.covariance(t, null)
                        - covarProxy.diffusion(t, null) * Matrix.transpose(covarProxy.diffusion(t, null));

                for (int k = 0; k < size; ++k)
                {
                    for (int j = 0; j < size; ++j)
                    {
                        if (Math.Abs(recon[k, j]) > tolerance)
                        {
                            QAssert.Fail("Failed to reproduce correlation matrix"
                                         + "\n    calculated: " + recon[k, j]
                                         + "\n    expected:   " + 0);
                        }
                    }
                }

                Vector volatility = volaModel.volatility(t, null);

                for (int k = 0; k < size; ++k)
                {
                    double expected = 0;
                    if (k > 2 * t)
                    {
                        double T = fixingTimes[k];
                        expected = (a * (T - t) + d) * Math.Exp(-b * (T - t)) + c;
                    }

                    if (Math.Abs(expected - volatility[k]) > tolerance)
                    {
                        QAssert.Fail("Failed to reproduce volatities"
                                     + "\n    calculated: " + volatility[k]
                                     + "\n    expected:   " + expected);
                    }
                }
            }
        }
Пример #29
0
        public void testModifiedBesselFunctions()
        {
            // Testing modified Bessel function of first and second kind

            /* reference values are computed with R and the additional package Bessel
             * http://cran.r-project.org/web/packages/Bessel
             */

            double[][] r =
            {
                new double[4] {
                    -1.3, 2.0, 1.2079888436539505, 0.1608243636110430
                },
                new double[4] {
                    1.3, 2.0, 1.2908192151358788, 0.1608243636110430
                },
                new double[4] {
                    0.001, 2.0, 2.2794705965773794, 0.1138938963603362
                },
                new double[4] {
                    1.2, 0.5, 0.1768918783499572, 2.1086579232338192
                },
                new double[4] {
                    2.3, 0.1, 0.00037954958988425198, 572.096866928290183
                },
                new double[4] {
                    -2.3, 1.1, 1.07222017902746969, 1.88152553684107371
                },
                new double[4] {
                    -10.0001, 1.1, 13857.7715614282552, 69288858.9474423379
                }
            };

            for (int i = 0; i < r.Length; ++i)
            {
                double nu         = r[i][0];
                double x          = r[i][1];
                double expected_i = r[i][2];
                double expected_k = r[i][3];
                double tol_i      = 5e4 * Const.QL_EPSILON * Math.Abs(expected_i);
                double tol_k      = 5e4 * Const.QL_EPSILON * Math.Abs(expected_k);

                double calculated_i = Utils.modifiedBesselFunction_i(nu, x);
                double calculated_k = Utils.modifiedBesselFunction_k(nu, x);

                if (Math.Abs(expected_i - calculated_i) > tol_i)
                {
                    QAssert.Fail("failed to reproduce modified Bessel "
                                 + "function of first kind"
                                 + "\n order     : " + nu
                                 + "\n argument  : " + x
                                 + "\n calculated: " + calculated_i
                                 + "\n expected  : " + expected_i);
                }
                if (Math.Abs(expected_k - calculated_k) > tol_k)
                {
                    QAssert.Fail("failed to reproduce modified Bessel "
                                 + "function of second kind"
                                 + "\n order     : " + nu
                                 + "\n argument  : " + x
                                 + "\n calculated: " + calculated_k
                                 + "\n expected  : " + expected_k);
                }
            }

            double[][] c =
            {
                new double[7] {
                    -1.3, 2.0, 0.0, 1.2079888436539505, 0.0, 0.1608243636110430, 0.0
                },
                new double[7] {
                    1.2, 1.5, 0.3, 0.7891550871263575, 0.2721408731632123, 0.275126507673411, -0.1316314405663727
                },
                new double[7] {
                    1.2, -1.5, 0.0, -0.6650597524355781, -0.4831941938091643, -0.251112360556051, -2.400130904230102
                },
                new double[7] {
                    -11.2, 1.5, 0.3, 12780719.20252659, 16401053.26770633, -34155172.65672453, -43830147.36759921
                },
                new double[7] {
                    1.2, -1.5, 2.0, -0.3869803778520574, 0.9756701796853728, -3.111629716783005, 0.6307859871879062
                },
                new double[7] {
                    1.2, 0.0, 9.9999, -0.03507838078252647, 0.1079601550451466, -0.05979939995451453, 0.3929814473878203
                },
                new double[7] {
                    1.2, 0.0, 10.1, -0.02782046891519293, 0.08562259917678558, -0.02035685034691133, 0.3949834389686676
                },
                new double[7] {
                    1.2, 0.0, 12.1, 0.07092110620741207, -0.2182727210128104, 0.3368505862966958, -0.1299038064313366
                },
                new double[7] {
                    1.2, 0.0, 14.1, -0.03014378676768797, 0.09277303628303372, -0.237531022649052, -0.2351923034581644
                },
                new double[7] {
                    1.2, 0.0, 16.1, -0.03823210284792657, 0.1176663135266562, -0.1091239402448228, 0.2930535651966139
                },
                new double[7] {
                    1.2, 0.0, 18.1, 0.05626742394733754, -0.173173324361983, 0.2941636588154642, -0.02023355577954348
                },
                new double[7] {
                    1.2, 0.0, 180.1, -0.001230682086826484, 0.003787649998122361, 0.02284509628723454, 0.09055419580980778
                },
                new double[7] {
                    1.2, 0.0, 21.0, -0.04746415965014021, 0.1460796627610969, -0.2693825171336859, -0.04830804448126782
                },
                new double[7] {
                    1.2, 10.0, 0.0, 2609.784936867044, 0, 1.904394919838336e-05, 0
                },
                new double[7] {
                    1.2, 14.0, 0.0, 122690.4873454286, 0, 2.902060692576643e-07, 0
                },
                new double[7] {
                    1.2, 20.0, 10.0, -37452017.91168936, -13917587.22151363, -3.821534367487143e-10, 4.083211255351664e-10
                },
                new double[7] {
                    1.2, 9.0, 9.0, -621.7335051293694, 618.1455736670332, -4.480795479964915e-05, -3.489034389148745e-08
                }
            };

            for (int i = 0; i < c.Length; ++i)
            {
                double  nu         = c[i][0];
                Complex z          = new Complex(c[i][1], c[i][2]);
                Complex expected_i = new Complex(c[i][3], c[i][4]);
                Complex expected_k = new Complex(c[i][5], c[i][6]);

                double tol_i = 5e4 * Const.QL_EPSILON * Complex.Abs(expected_i);
                double tol_k = 1e6 * Const.QL_EPSILON * Complex.Abs(expected_k);

                Complex calculated_i = Utils.modifiedBesselFunction_i(nu, z);
                Complex calculated_k = Utils.modifiedBesselFunction_k(nu, z);

                if (Complex.Abs(expected_i - calculated_i) > tol_i)
                {
                    QAssert.Fail("failed to reproduce modified Bessel "
                                 + "function of first kind"
                                 + "\n order     : " + nu
                                 + "\n argument  : " + z
                                 + "\n calculated: " + calculated_i
                                 + "\n expected  : " + expected_i);
                }

                if (Complex.Abs(expected_k) > 1e-4 && // do not check small values
                    Complex.Abs(expected_k - calculated_k) > tol_k)
                {
                    QAssert.Fail("failed to reproduce modified Bessel "
                                 + "function of second kind"
                                 + "\n order     : " + nu
                                 + "\n argument  : " + z
                                 + "\n diff      : " + (calculated_k - expected_k)
                                 + "\n calculated: " + calculated_k
                                 + "\n expected  : " + expected_k);
                }
            }
        }
        public void testDecomposition()
        {
            // Testing collared coupon against its decomposition...

            CommonVars vars = new CommonVars();

            double         tolerance = 1e-10;
            double         npvVanilla, npvCappedLeg, npvFlooredLeg, npvCollaredLeg, npvCap, npvFloor, npvCollar;
            double         error;
            double         floorstrike = 0.05;
            double         capstrike   = 0.10;
            List <double?> caps        = new InitializedList <double?>(vars.length, capstrike);
            List <double?> caps0       = new List <double?>();
            List <double?> floors      = new InitializedList <double?>(vars.length, floorstrike);
            List <double?> floors0     = new List <double?>();
            double         gearing_p   = 0.5;
            double         spread_p    = 0.002;
            double         gearing_n   = -1.5;
            double         spread_n    = 0.12;
            // fixed leg with zero rate
            List <CashFlow> fixedLeg = vars.makeFixedLeg(vars.startDate, vars.length);
            // floating leg with gearing=1 and spread=0
            List <CashFlow> floatLeg = vars.makeYoYLeg(vars.startDate, vars.length);
            // floating leg with positive gearing (gearing_p) and spread<>0
            List <CashFlow> floatLeg_p = vars.makeYoYLeg(vars.startDate, vars.length, gearing_p, spread_p);
            // floating leg with negative gearing (gearing_n) and spread<>0
            List <CashFlow> floatLeg_n = vars.makeYoYLeg(vars.startDate, vars.length, gearing_n, spread_n);
            // Swap with null fixed leg and floating leg with gearing=1 and spread=0
            Swap vanillaLeg = new Swap(fixedLeg, floatLeg);
            // Swap with null fixed leg and floating leg with positive gearing and spread<>0
            Swap vanillaLeg_p = new Swap(fixedLeg, floatLeg_p);
            // Swap with null fixed leg and floating leg with negative gearing and spread<>0
            Swap vanillaLeg_n = new Swap(fixedLeg, floatLeg_n);

            IPricingEngine engine = new DiscountingSwapEngine(vars.nominalTS);

            vanillaLeg.setPricingEngine(engine); // here use the autoset feature
            vanillaLeg_p.setPricingEngine(engine);
            vanillaLeg_n.setPricingEngine(engine);

            // CAPPED coupon - Decomposition of payoff
            // Payoff = Nom * Min(rate,strike) * accrualperiod =
            // = Nom * [rate + Min(0,strike-rate)] * accrualperiod =
            // = Nom * rate * accrualperiod - Nom * Max(rate-strike,0) * accrualperiod =
            // = VanillaFloatingLeg - Call
            //

            int whichPricer = 0;

            // Case gearing = 1 and spread = 0
            List <CashFlow> cappedLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length,
                                                                  caps, floors0, vars.volatility);
            Swap capLeg = new Swap(fixedLeg, cappedLeg);

            capLeg.setPricingEngine(engine);
            YoYInflationCap cap = new YoYInflationCap(floatLeg, new List <double>()
            {
                capstrike
            });

            cap.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvVanilla   = vanillaLeg.NPV();
            npvCappedLeg = capLeg.NPV();
            npvCap       = cap.NPV();
            error        = Math.Abs(npvCappedLeg - (npvVanilla - npvCap));
            if (error > tolerance)
            {
                QAssert.Fail("\nYoY Capped Leg: gearing=1, spread=0%, strike=" + capstrike * 100 +
                             "%\n" +
                             "  Capped Floating Leg NPV: " + npvCappedLeg + "\n" +
                             "  Floating Leg NPV - Cap NPV: " + (npvVanilla - npvCap) + "\n" +
                             "  Diff: " + error);
            }

            // gearing = 1 and spread = 0
            // FLOORED coupon - Decomposition of payoff
            // Payoff = Nom * Max(rate,strike) * accrualperiod =
            // = Nom * [rate + Max(0,strike-rate)] * accrualperiod =
            // = Nom * rate * accrualperiod + Nom * Max(strike-rate,0) * accrualperiod =
            // = VanillaFloatingLeg + Put
            //

            List <CashFlow> flooredLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length,
                                                                   caps0, floors, vars.volatility);
            Swap floorLeg = new Swap(fixedLeg, flooredLeg);

            floorLeg.setPricingEngine(engine);
            YoYInflationFloor floor = new YoYInflationFloor(floatLeg, new List <double>()
            {
                floorstrike
            });

            floor.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvFlooredLeg = floorLeg.NPV();
            npvFloor      = floor.NPV();
            error         = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor));
            if (error > tolerance)
            {
                QAssert.Fail("YoY Floored Leg: gearing=1, spread=0%, strike=" + floorstrike * 100 +
                             "%\n" +
                             "  Floored Floating Leg NPV: " + npvFlooredLeg + "\n" +
                             "  Floating Leg NPV + Floor NPV: " + (npvVanilla + npvFloor) + "\n" +
                             "  Diff: " + error);
            }

            // gearing = 1 and spread = 0
            // COLLARED coupon - Decomposition of payoff
            // Payoff = Nom * Min(strikem,Max(rate,strikeM)) * accrualperiod =
            // = VanillaFloatingLeg - Collar
            //

            List <CashFlow> collaredLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length,
                                                                    caps, floors, vars.volatility);
            Swap collarLeg = new Swap(fixedLeg, collaredLeg);

            collarLeg.setPricingEngine(engine);
            YoYInflationCollar collar = new YoYInflationCollar(floatLeg,
                                                               new List <double>()
            {
                capstrike
            },
                                                               new List <double>()
            {
                floorstrike
            });

            collar.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvCollaredLeg = collarLeg.NPV();
            npvCollar      = collar.NPV();
            error          = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar));
            if (error > tolerance)
            {
                QAssert.Fail("\nYoY Collared Leg: gearing=1, spread=0%, strike=" +
                             floorstrike * 100 + "% and " + capstrike * 100 + "%\n" +
                             "  Collared Floating Leg NPV: " + npvCollaredLeg + "\n" +
                             "  Floating Leg NPV - Collar NPV: " + (npvVanilla - npvCollar) + "\n" +
                             "  Diff: " + error);
            }

            // gearing = a and spread = b
            // CAPPED coupon - Decomposition of payoff
            // Payoff
            // = Nom * Min(a*rate+b,strike) * accrualperiod =
            // = Nom * [a*rate+b + Min(0,strike-a*rate-b)] * accrualperiod =
            // = Nom * a*rate+b * accrualperiod + Nom * Min(strike-b-a*rate,0) * accrualperiod
            // --> If a>0 (assuming positive effective strike):
            // Payoff = VanillaFloatingLeg - Call(a*rate+b,strike)
            // --> If a<0 (assuming positive effective strike):
            // Payoff = VanillaFloatingLeg + Nom * Min(strike-b+|a|*rate+,0) * accrualperiod =
            // = VanillaFloatingLeg + Put(|a|*rate+b,strike)
            //

            // Positive gearing
            List <CashFlow> cappedLeg_p = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors0,
                                                                    vars.volatility, gearing_p, spread_p);
            Swap capLeg_p = new Swap(fixedLeg, cappedLeg_p);

            capLeg_p.setPricingEngine(engine);
            YoYInflationCap cap_p = new YoYInflationCap(floatLeg_p, new List <double>()
            {
                capstrike
            });

            cap_p.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvVanilla   = vanillaLeg_p.NPV();
            npvCappedLeg = capLeg_p.NPV();
            npvCap       = cap_p.NPV();
            error        = Math.Abs(npvCappedLeg - (npvVanilla - npvCap));
            if (error > tolerance)
            {
                QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_p + ", " +
                             "spread= " + spread_p * 100 +
                             "%, strike=" + capstrike * 100 + "%, " +
                             "effective strike= " + (capstrike - spread_p) / gearing_p * 100 +
                             "%\n" +
                             "  Capped Floating Leg NPV: " + npvCappedLeg + "\n" +
                             "  Vanilla Leg NPV: " + npvVanilla + "\n" +
                             "  Cap NPV: " + npvCap + "\n" +
                             "  Floating Leg NPV - Cap NPV: " + (npvVanilla - npvCap) + "\n" +
                             "  Diff: " + error);
            }

            // Negative gearing
            List <CashFlow> cappedLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors0,
                                                                    vars.volatility, gearing_n, spread_n);
            Swap capLeg_n = new Swap(fixedLeg, cappedLeg_n);

            capLeg_n.setPricingEngine(engine);
            YoYInflationFloor floor_n = new YoYInflationFloor(floatLeg, new List <double>()
            {
                (capstrike - spread_n) / gearing_n
            });

            floor_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvVanilla   = vanillaLeg_n.NPV();
            npvCappedLeg = capLeg_n.NPV();
            npvFloor     = floor_n.NPV();
            error        = Math.Abs(npvCappedLeg - (npvVanilla + gearing_n * npvFloor));
            if (error > tolerance)
            {
                QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_n + ", " +
                             "spread= " + spread_n * 100 +
                             "%, strike=" + capstrike * 100 + "%, " +
                             "effective strike= " + ((capstrike - spread_n) / gearing_n * 100) +
                             "%\n" +
                             "  Capped Floating Leg NPV: " + npvCappedLeg + "\n" +
                             "  npv Vanilla: " + npvVanilla + "\n" +
                             "  npvFloor: " + npvFloor + "\n" +
                             "  Floating Leg NPV - Cap NPV: " + (npvVanilla + gearing_n * npvFloor) + "\n" +
                             "  Diff: " + error);
            }

            // gearing = a and spread = b
            // FLOORED coupon - Decomposition of payoff
            // Payoff
            // = Nom * Max(a*rate+b,strike) * accrualperiod =
            // = Nom * [a*rate+b + Max(0,strike-a*rate-b)] * accrualperiod =
            // = Nom * a*rate+b * accrualperiod + Nom * Max(strike-b-a*rate,0) * accrualperiod
            // --> If a>0 (assuming positive effective strike):
            // Payoff = VanillaFloatingLeg + Put(a*rate+b,strike)
            // --> If a<0 (assuming positive effective strike):
            // Payoff = VanillaFloatingLeg + Nom * Max(strike-b+|a|*rate+,0) * accrualperiod =
            // = VanillaFloatingLeg - Call(|a|*rate+b,strike)
            //

            // Positive gearing
            List <CashFlow> flooredLeg_p1 = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps0, floors,
                                                                      vars.volatility, gearing_p, spread_p);
            Swap floorLeg_p1 = new Swap(fixedLeg, flooredLeg_p1);

            floorLeg_p1.setPricingEngine(engine);
            YoYInflationFloor floor_p1 = new YoYInflationFloor(floatLeg_p, new List <double>()
            {
                floorstrike
            });

            floor_p1.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvVanilla    = vanillaLeg_p.NPV();
            npvFlooredLeg = floorLeg_p1.NPV();
            npvFloor      = floor_p1.NPV();
            error         = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor));
            if (error > tolerance)
            {
                QAssert.Fail("\nYoY Floored Leg: gearing=" + gearing_p + ", "
                             + "spread= " + spread_p * 100 + "%, strike=" + floorstrike * 100 + "%, "
                             + "effective strike= " + (floorstrike - spread_p) / gearing_p * 100
                             + "%\n" +
                             "  Floored Floating Leg NPV: " + npvFlooredLeg
                             + "\n" +
                             "  Floating Leg NPV + Floor NPV: " + (npvVanilla + npvFloor)
                             + "\n" +
                             "  Diff: " + error);
            }
            // Negative gearing
            List <CashFlow> flooredLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps0, floors,
                                                                     vars.volatility, gearing_n, spread_n);
            Swap floorLeg_n = new Swap(fixedLeg, flooredLeg_n);

            floorLeg_n.setPricingEngine(engine);
            YoYInflationCap cap_n = new YoYInflationCap(floatLeg, new List <double>()
            {
                (floorstrike - spread_n) / gearing_n
            });

            cap_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvVanilla    = vanillaLeg_n.NPV();
            npvFlooredLeg = floorLeg_n.NPV();
            npvCap        = cap_n.NPV();
            error         = Math.Abs(npvFlooredLeg - (npvVanilla - gearing_n * npvCap));
            if (error > tolerance)
            {
                QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_n + ", " +
                             "spread= " + spread_n * 100 +
                             "%, strike=" + floorstrike * 100 + "%, " +
                             "effective strike= " + (floorstrike - spread_n) / gearing_n * 100 +
                             "%\n" +
                             "  Capped Floating Leg NPV: " + npvFlooredLeg + "\n" +
                             "  Floating Leg NPV - Cap NPV: " + (npvVanilla - gearing_n * npvCap) + "\n" +
                             "  Diff: " + error);
            }
            // gearing = a and spread = b
            // COLLARED coupon - Decomposition of payoff
            // Payoff = Nom * Min(caprate,Max(a*rate+b,floorrate)) * accrualperiod
            // --> If a>0 (assuming positive effective strike):
            // Payoff = VanillaFloatingLeg - Collar(a*rate+b, floorrate, caprate)
            // --> If a<0 (assuming positive effective strike):
            // Payoff = VanillaFloatingLeg + Collar(|a|*rate+b, caprate, floorrate)
            //
            // Positive gearing
            List <CashFlow> collaredLeg_p = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors,
                                                                      vars.volatility, gearing_p, spread_p);
            Swap collarLeg_p1 = new Swap(fixedLeg, collaredLeg_p);

            collarLeg_p1.setPricingEngine(engine);
            YoYInflationCollar collar_p = new YoYInflationCollar(floatLeg_p,
                                                                 new List <double>()
            {
                capstrike
            },
                                                                 new List <double>()
            {
                floorstrike
            });

            collar_p.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvVanilla     = vanillaLeg_p.NPV();
            npvCollaredLeg = collarLeg_p1.NPV();
            npvCollar      = collar_p.NPV();
            error          = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar));
            if (error > tolerance)
            {
                QAssert.Fail("\nYoY Collared Leg: gearing=" + gearing_p + ", "
                             + "spread= " + spread_p * 100 + "%, strike="
                             + floorstrike * 100 + "% and " + capstrike * 100
                             + "%, "
                             + "effective strike=" + (floorstrike - spread_p) / gearing_p * 100
                             + "% and " + (capstrike - spread_p) / gearing_p * 100
                             + "%\n" +
                             "  Collared Floating Leg NPV: " + npvCollaredLeg
                             + "\n" +
                             "  Floating Leg NPV - Collar NPV: " + (npvVanilla - npvCollar)
                             + "\n" +
                             "  Diff: " + error);
            }
            // Negative gearing
            List <CashFlow> collaredLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors,
                                                                      vars.volatility, gearing_n, spread_n);
            Swap collarLeg_n1 = new Swap(fixedLeg, collaredLeg_n);

            collarLeg_n1.setPricingEngine(engine);
            YoYInflationCollar collar_n = new YoYInflationCollar(floatLeg,
                                                                 new List <double>()
            {
                (floorstrike - spread_n) / gearing_n
            },
                                                                 new List <double>()
            {
                (capstrike - spread_n) / gearing_n
            });

            collar_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer));
            npvVanilla     = vanillaLeg_n.NPV();
            npvCollaredLeg = collarLeg_n1.NPV();
            npvCollar      = collar_n.NPV();
            error          = Math.Abs(npvCollaredLeg - (npvVanilla - gearing_n * npvCollar));
            if (error > tolerance)
            {
                QAssert.Fail("\nYoY Collared Leg: gearing=" + gearing_n + ", "
                             + "spread= " + spread_n * 100 + "%, strike="
                             + floorstrike * 100 + "% and " + capstrike * 100
                             + "%, "
                             + "effective strike=" + (floorstrike - spread_n) / gearing_n * 100
                             + "% and " + (capstrike - spread_n) / gearing_n * 100
                             + "%\n" +
                             "  Collared Floating Leg NPV: " + npvCollaredLeg
                             + "\n" +
                             "  Floating Leg NPV - Collar NPV: " + (npvVanilla - gearing_n * npvCollar)
                             + "\n" +
                             "  Diff: " + error);
            }
            // remove circular refernce
            vars.hy.linkTo(null);
        }