Пример #1
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());
                        }
                    }
                }
            }
        }
        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);
            }
        }