Esempio n. 1
0
        private void pathGenerator(UnderlyingInfo under)
        {
            ulong seed      = 1;
            int   timeSteps = 365;
            //
            int dimensions = this.processArr_.factors();

            double t = processArr_.time(maturity);

            TimeGrid grid = new TimeGrid(t, timeSteps);

            IRNG rndGenerator = (IRNG) new PseudoRandom().make_sequence_generator(dimensions * (grid.size() - 1), seed);

            this.pathGenerator_ = new MultiPathGenerator <IRNG>(this.processArr_, grid, rndGenerator, false);
        }
        private void pathGenerator(UnderlyingInfo under)
        {
            ulong seed = 1;
            int timeSteps = 365;
            //
            int dimensions = this.processArr_.factors();

            double t = processArr_.time(maturity);

            TimeGrid grid = new TimeGrid(t, timeSteps);

            IRNG rndGenerator = (IRNG)new PseudoRandom().make_sequence_generator(dimensions * (grid.size() - 1), seed);

            this.pathGenerator_ = new MultiPathGenerator<IRNG>(this.processArr_, grid, rndGenerator, false);

        }
Esempio n. 3
0
        public ScenarioCube(double r, double[] spots, double[] q, double[] vols, double[,] correlations, int nSteps, double dt)
        {
            nAssets     = spots.Length;
            this.nSteps = nSteps;
            this.dt     = dt;

            Processes    = new List <StochasticProcess1D>(nAssets);
            Correlations = new Matrix(nAssets, nAssets);

            Date       now = new Date(DateTime.Now.Date);
            DayCounter dc  = new SimpleDayCounter();

            yc = new Handle <YieldTermStructure>(new FlatForward(now, r, dc));
            for (int i = 0; i < nAssets; ++i)
            {
                Handle <Quote> x0 = new Handle <Quote>(new SimpleQuote(spots[i]));
                Handle <YieldTermStructure>    dyc = new Handle <YieldTermStructure>(new FlatForward(now, q[i], dc));
                Handle <BlackVolTermStructure> bv  = new Handle <BlackVolTermStructure>(new BlackConstantVol(now, new Calendar(), vols[i], dc));

                Processes.Add(new GeneralizedBlackScholesProcess(x0, dyc, yc, bv));

                for (int j = 0; j < nAssets; ++j)
                {
                    if (i == j)
                    {
                        Correlations[i, j] = 1;
                    }
                    else
                    {
                        Correlations[i, j] = Correlations[j, i] = correlations[i, j];
                    }
                }
            }

            spa = new StochasticProcessArray(Processes, Correlations);
            rsg = new RandomSequenceGenerator <MersenneTwisterUniformRng>(nSteps * Processes.Count, new MersenneTwisterUniformRng());
            tg  = new TimeGrid(nSteps * dt, nSteps);

            var rsg2 = new InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng>,
                                                 InverseCumulativeNormal>(rsg, new InverseCumulativeNormal());

            mpg = new MultiPathGenerator <InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng>, InverseCumulativeNormal> >(spa, tg, rsg2, false);
        }
Esempio n. 4
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 <MultiPath> sample = generator.next();
            Vector             calculated = new Vector(assets);
            double             error, tolerance = 2.0e-7;

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

            for (int j = 0; j < assets; j++)
            {
                error = Math.Abs(calculated[j] - expected[j]);
                if (error > tolerance)
                {
                    Assert.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();
            for (int j = 0; j < assets; j++)
            {
                calculated[j] = sample.value[j].back();
            }
            for (int j = 0; j < assets; j++)
            {
                error = Math.Abs(calculated[j] - antithetic[j]);
                if (error > tolerance)
                {
                    Assert.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);
                }
            }
        }
Esempio n. 5
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());
                        }
                    }
                }
            }
        }
Esempio n. 6
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<MultiPath> sample = generator.next();
            Vector calculated = new Vector(assets);
            double error, tolerance = 2.0e-7;

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

            for (int j=0; j<assets; j++) {
                error = Math.Abs(calculated[j]-expected[j]);
                if (error > tolerance) {
                    Assert.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();
            for (int j=0; j<assets; j++)
                calculated[j] = sample.value[j].back();
            for (int j=0; j<assets; j++) {
                error = Math.Abs(calculated[j]-antithetic[j]);
                if (error > tolerance) {
                    Assert.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);
                }
            }
        }
Esempio n. 7
0
        public void testMonteCarloCapletPricing()
        {
            //"Testing caplet LMM Monte-Carlo caplet pricing..."

            //SavedSettings backup;

            /* 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 ,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<MultiPath> path1 = generator1.next();
                Sample<MultiPath> path2 = generator2.next();

                List<double> rates1=new InitializedList<double>(len);
                List<double> rates2 = new InitializedList<double>(len);
                for (int j=0; j<process1.size(); ++j) {
                    rates1[j] = path1.value[j][location[j]];
                    rates2[j] = path2.value[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) {
                    Assert.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) {
                    Assert.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) {
                        Assert.Fail("Failed to reproduce expected caplet NPV"
                                    + "\n    calculated: " + calculated3
                                    + "\n    error int:  " + tolerance3 + refError
                                    + "\n    expected:   " + expected);
                    }
                }
            }
        }
Esempio n. 8
0
        public void testMonteCarloCapletPricing()
        {
            //"Testing caplet LMM Monte-Carlo caplet pricing..."

            //SavedSettings backup;

            /* 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, 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 <MultiPath> path1 = generator1.next();
                Sample <MultiPath> path2 = generator2.next();

                List <double> rates1 = new InitializedList <double>(len);
                List <double> rates2 = new InitializedList <double>(len);
                for (int j = 0; j < process1.size(); ++j)
                {
                    rates1[j] = path1.value[j][location[j]];
                    rates2[j] = path2.value[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)
                {
                    Assert.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)
                {
                    Assert.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)
                    {
                        Assert.Fail("Failed to reproduce expected caplet NPV"
                                    + "\n    calculated: " + calculated3
                                    + "\n    error int:  " + tolerance3 + refError
                                    + "\n    expected:   " + expected);
                    }
                }
            }
        }
Esempio n. 9
0
        public void testSwaptionPricing()
        {
            //"Testing forward swap and swaption pricing...");

            //SavedSettings backup;

            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 ,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)
                        Assert.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<MultiPath> path = (n%2!=0) ? generator.antithetic()
                                                     : generator.next();

                            //Sample<MultiPath> path = generator.next();
                            List<double> rates_ = new InitializedList<double>(size);
                            for (int k=0; k<process.size(); ++k) {
                                rates_[k] = path.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)
                            Assert.Fail("Failed to reproduce swaption npv"
                                        + "\n    calculated: " + stat.mean()
                                        + "\n    expected:   " + swaption.NPV());
                    }
                }
            }
        }
        public void testCallableEquityPricing()
        {
            // Testing the pricing of a callable equity product

            /*
             * For the definition of the example product see
             * Alexander Giese, On the Pricing of Auto-Callable Equity
             * Structures in the Presence of Stochastic Volatility and
             * Stochastic Interest Rates .
             * http://workshop.mathfinance.de/2006/papers/giese/slides.pdf
             */

            int        maturity = 7;
            DayCounter dc       = new Actual365Fixed();
            Date       today    = Date.Today;

            Settings.Instance.setEvaluationDate(today);

            Handle <Quote> spot             = new Handle <Quote>(new SimpleQuote(100.0));
            SimpleQuote    qRate            = new SimpleQuote(0.04);
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, qRate, dc));
            SimpleQuote rRate = new SimpleQuote(0.04);
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, rRate, dc));

            HestonProcess hestonProcess = new HestonProcess(rTS, qTS, spot, 0.0625, 1.0, 0.24 * 0.24, 1e-4, 0.0);
            // FLOATING_POINT_EXCEPTION
            HullWhiteForwardProcess hwProcess = new HullWhiteForwardProcess(rTS, 0.00883, 0.00526);

            hwProcess.setForwardMeasureTime(dc.yearFraction(today, today + new Period(maturity + 1, TimeUnit.Years)));

            HybridHestonHullWhiteProcess jointProcess = new HybridHestonHullWhiteProcess(hestonProcess, hwProcess, -0.4);

            Schedule schedule = new Schedule(today, today + new Period(maturity, TimeUnit.Years), new Period(1, TimeUnit.Years),
                                             new TARGET(), BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false);

            List <double> times = new InitializedList <double>(maturity + 1);

            for (int i = 0; i <= maturity; ++i)
            {
                times[i] = i;
            }

            TimeGrid grid = new TimeGrid(times, times.Count);

            List <double> redemption = new InitializedList <double>(maturity);

            for (int i = 0; i < maturity; ++i)
            {
                redemption[i] = 1.07 + 0.03 * i;
            }

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

            MultiPathGenerator <IRNG> generator = new MultiPathGenerator <IRNG>(jointProcess, grid, rsg, false);
            GeneralStatistics         stat      = new GeneralStatistics();

            double antitheticPayoff = 0;
            int    nrTrails         = 40000;

            for (int i = 0; i < nrTrails; ++i)
            {
                bool antithetic = (i % 2) != 0;

                Sample <IPath> path  = antithetic ? generator.antithetic() : generator.next();
                MultiPath      value = path.value as MultiPath;
                Utils.QL_REQUIRE(value != null, () => "Invalid Path");

                double payoff = 0;
                for (int j = 1; j <= maturity; ++j)
                {
                    if (value[0][j] > spot.link.value())
                    {
                        Vector states = new Vector(3);
                        for (int k = 0; k < 3; ++k)
                        {
                            states[k] = value[k][j];
                        }
                        payoff = redemption[j - 1] / jointProcess.numeraire(grid[j], states);
                        break;
                    }
                    else if (j == maturity)
                    {
                        Vector states = new Vector(3);
                        for (int k = 0; k < 3; ++k)
                        {
                            states[k] = value[k][j];
                        }
                        payoff = 1.0 / jointProcess.numeraire(grid[j], states);
                    }
                }

                if (antithetic)
                {
                    stat.add(0.5 * (antitheticPayoff + payoff));
                }
                else
                {
                    antitheticPayoff = payoff;
                }
            }

            double expected   = 0.938;
            double calculated = stat.mean();
            double error      = stat.errorEstimate();

            if (Math.Abs(expected - calculated) > 3 * error)
            {
                QAssert.Fail("Failed to reproduce auto-callable equity structure price"
                             + "\n   calculated: " + calculated
                             + "\n   error:      " + error
                             + "\n   expected:   " + expected);
            }
        }
        public void testZeroBondPricing()
        {
            // Testing Monte-Carlo zero bond pricing

            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.Instance.setEvaluationDate(today);

            // construct a strange yield curve to check drifts and discounting
            // of the joint stochastic process

            List <Date>   dates = new List <Date>();
            List <double> times = new List <double>();
            List <double> rates = new List <double>();

            dates.Add(today);
            rates.Add(0.02);
            times.Add(0.0);
            for (int i = 120; i < 240; ++i)
            {
                dates.Add(today + new Period(i, TimeUnit.Months));
                rates.Add(0.02 + 0.0002 * Math.Exp(Math.Sin(i / 8.0)));
                times.Add(dc.yearFraction(today, dates.Last()));
            }

            Date maturity = dates.Last() + new Period(10, TimeUnit.Years);

            dates.Add(maturity);
            rates.Add(0.04);
            //times.Add(dc.yearFraction(today, dates.Last()));

            Handle <Quote> s0 = new Handle <Quote>(new SimpleQuote(100));

            Handle <YieldTermStructure> ts = new Handle <YieldTermStructure>(new InterpolatedZeroCurve <Linear>(dates, rates, dc));
            Handle <YieldTermStructure> ds = new Handle <YieldTermStructure>(Utilities.flatRate(today, 0.0, dc));

            HestonProcess           hestonProcess = new HestonProcess(ts, ds, s0, 0.02, 1.0, 0.2, 0.5, -0.8);
            HullWhiteForwardProcess hwProcess     = new HullWhiteForwardProcess(ts, 0.05, 0.05);

            hwProcess.setForwardMeasureTime(dc.yearFraction(today, maturity));
            HullWhite hwModel = new HullWhite(ts, 0.05, 0.05);

            HybridHestonHullWhiteProcess jointProcess = new HybridHestonHullWhiteProcess(hestonProcess, hwProcess, -0.4);

            TimeGrid grid = new TimeGrid(times);

            int factors = jointProcess.factors();
            int steps   = grid.size() - 1;
            SobolBrownianBridgeRsg rsg = new SobolBrownianBridgeRsg(factors, steps);
            MultiPathGenerator <SobolBrownianBridgeRsg> generator = new MultiPathGenerator <SobolBrownianBridgeRsg>(
                jointProcess, grid, rsg, false);

            int m = 90;
            List <GeneralStatistics> zeroStat   = new InitializedList <GeneralStatistics>(m);
            List <GeneralStatistics> optionStat = new InitializedList <GeneralStatistics>(m);

            int    nrTrails    = 8191;
            int    optionTenor = 24;
            double strike      = 0.5;

            for (int i = 0; i < nrTrails; ++i)
            {
                Sample <IPath> path  = generator.next();
                MultiPath      value = path.value as MultiPath;
                Utils.QL_REQUIRE(value != null, () => "Invalid Path");

                for (int j = 1; j < m; ++j)
                {
                    double t = grid[j];               // zero end and option maturity
                    double T = grid[j + optionTenor]; // maturity of zero bond
                    // of option

                    Vector states       = new Vector(3);
                    Vector optionStates = new Vector(3);
                    for (int k = 0; k < jointProcess.size(); ++k)
                    {
                        states[k]       = value[k][j];
                        optionStates[k] = value[k][j + optionTenor];
                    }

                    double zeroBond
                        = 1.0 / jointProcess.numeraire(t, states);
                    double zeroOption = zeroBond * Math.Max(0.0, hwModel.discountBond(t, T, states[2]) - strike);

                    zeroStat[j].add(zeroBond);
                    optionStat[j].add(zeroOption);
                }
            }

            for (int j = 1; j < m; ++j)
            {
                double t          = grid[j];
                double calculated = zeroStat[j].mean();
                double expected   = ts.link.discount(t);

                if (Math.Abs(calculated - expected) > 0.03)
                {
                    QAssert.Fail("Failed to reproduce expected zero bond prices"
                                 + "\n   t:          " + t
                                 + "\n   calculated: " + calculated
                                 + "\n   expected:   " + expected);
                }

                double T = grid[j + optionTenor];

                calculated = optionStat[j].mean();
                expected   = hwModel.discountBondOption(Option.Type.Call, strike, t, T);

                if (Math.Abs(calculated - expected) > 0.0035)
                {
                    QAssert.Fail("Failed to reproduce expected zero bond option prices"
                                 + "\n   t:          " + t
                                 + "\n   T:          " + T
                                 + "\n   calculated: " + calculated
                                 + "\n   expected:   " + expected);
                }
            }
        }
Esempio n. 12
0
        public override void Reset()
        {
            PseudoRandom rsg = new PseudoRandom();

            _pg = rsg.make_sequence_generator(_process.size() * (_grid.size() - 1), _seed) as MultiPathGenerator <InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng>, InverseCumulativeNormal> >;
        }