Exemple #1
0
        public void testFdmHestonEuropeanWithDividends()
        {
            //Testing FDM with European option with dividends in Heston model...
            using (SavedSettings backup = new SavedSettings())
            {
                Handle <Quote> s0 = new Handle <Quote>(new SimpleQuote(100.0));

                Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.05, new Actual365Fixed()));
                Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.0, new Actual365Fixed()));

                HestonProcess hestonProcess = new HestonProcess(rTS, qTS, s0, 0.04, 2.5, 0.04, 0.66, -0.8);

                Settings.Instance.setEvaluationDate(new Date(28, 3, 2004));
                Date              exerciseDate = new Date(28, 3, 2005);
                Exercise          exercise     = new AmericanExercise(exerciseDate);
                StrikedTypePayoff payoff       = new PlainVanillaPayoff(Option.Type.Put, 100);

                List <double> dividends     = new InitializedList <double>(1, 5);
                List <Date>   dividendDates = new InitializedList <Date>(1, new Date(28, 9, 2004));

                DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends);
                IPricingEngine        engine = new FdHestonVanillaEngine(new HestonModel(hestonProcess), 50, 100, 50);
                option.setPricingEngine(engine);

                double tol           = 0.01;
                double gammaTol      = 0.001;
                double npvExpected   = 7.365075;
                double deltaExpected = -0.396678;
                double gammaExpected = 0.027681;

                if (Math.Abs(option.NPV() - npvExpected) > tol)
                {
                    QAssert.Fail("Failed to reproduce expected npv"
                                 + "\n    calculated: " + option.NPV()
                                 + "\n    expected:   " + npvExpected
                                 + "\n    tolerance:  " + tol);
                }
                if (Math.Abs(option.delta() - deltaExpected) > tol)
                {
                    QAssert.Fail("Failed to reproduce expected delta"
                                 + "\n    calculated: " + option.delta()
                                 + "\n    expected:   " + deltaExpected
                                 + "\n    tolerance:  " + tol);
                }
                if (Math.Abs(option.gamma() - gammaExpected) > gammaTol)
                {
                    QAssert.Fail("Failed to reproduce expected gamma"
                                 + "\n    calculated: " + option.gamma()
                                 + "\n    expected:   " + gammaExpected
                                 + "\n    tolerance:  " + tol);
                }
            }
        }
Exemple #2
0
        public void testFdmHestonIkonenToivanen()
        {
            //Testing FDM Heston for Ikonen and Toivanen tests...

            /* check prices of american puts as given in:
             * From Efficient numerical methods for pricing American options under
             * stochastic volatility, Samuli Ikonen, Jari Toivanen,
             * http://users.jyu.fi/~tene/papers/reportB12-05.pdf
             */
            using (SavedSettings backup = new SavedSettings())
            {
                Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.10, new Actual360()));
                Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.0, new Actual360()));

                Settings.Instance.setEvaluationDate(new Date(28, 3, 2004));
                Date              exerciseDate = new Date(26, 6, 2004);
                Exercise          exercise     = new AmericanExercise(exerciseDate);
                StrikedTypePayoff payoff       = new PlainVanillaPayoff(Option.Type.Put, 10);
                VanillaOption     option       = new VanillaOption(payoff, exercise);

                double[] strikes  = new double[] { 8, 9, 10, 11, 12 };
                double[] expected = new double[] { 2.00000, 1.10763, 0.520038, 0.213681, 0.082046 };
                double   tol      = 0.001;

                for (int i = 0; i < strikes.Length; ++i)
                {
                    Handle <Quote> s0            = new Handle <Quote>(new SimpleQuote(strikes[i]));
                    HestonProcess  hestonProcess = new HestonProcess(rTS, qTS, s0, 0.0625, 5, 0.16, 0.9, 0.1);
                    IPricingEngine engine        = new FdHestonVanillaEngine(new HestonModel(hestonProcess), 100, 400);
                    option.setPricingEngine(engine);

                    double calculated = option.NPV();
                    if (Math.Abs(calculated - expected[i]) > tol)
                    {
                        QAssert.Fail("Failed to reproduce expected npv"
                                     + "\n    strike:     " + strikes[i]
                                     + "\n    calculated: " + calculated
                                     + "\n    expected:   " + expected[i]
                                     + "\n    tolerance:  " + tol);
                    }
                }
            }
        }
Exemple #3
0
        public void testSpuriousOscillations()
        {
            //Testing for spurious oscillations when solving the Heston PDEs...
            using (SavedSettings backup = new SavedSettings())
            {
                DayCounter dc    = new Actual365Fixed();
                Date       today = new Date(7, 6, 2018);

                Settings.Instance.setEvaluationDate(today);

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

                double v0    = 0.005;
                double kappa = 1.0;
                double theta = 0.005;
                double sigma = 0.4;
                double rho   = -0.75;

                Date maturity = today + new Period(1, TimeUnit.Years);

                HestonProcess process =
                    new HestonProcess(
                        rTS, qTS, spot, v0, kappa, theta, sigma, rho);

                HestonModel model =
                    new HestonModel(process);

                FdHestonVanillaEngine hestonEngine =
                    new FdHestonVanillaEngine(
                        model, 6, 200, 13, 0, new FdmSchemeDesc().TrBDF2());

                VanillaOption option = new VanillaOption(new PlainVanillaPayoff(Option.Type.Call, spot.currentLink().value()),
                                                         new EuropeanExercise(maturity));

                option.setupArguments(hestonEngine.getArguments());

                List <Tuple <FdmSchemeDesc, string, bool> > descs = new List <Tuple <FdmSchemeDesc, string, bool> >();
                descs.Add(new Tuple <FdmSchemeDesc, string, bool>(new FdmSchemeDesc().CraigSneyd(), "Craig-Sneyd", true));
                descs.Add(new Tuple <FdmSchemeDesc, string, bool>(new FdmSchemeDesc().Hundsdorfer(), "Hundsdorfer", true));
                descs.Add(new Tuple <FdmSchemeDesc, string, bool>(new FdmSchemeDesc().ModifiedHundsdorfer(), "Mod. Hundsdorfer", true));
                descs.Add(new Tuple <FdmSchemeDesc, string, bool>(new FdmSchemeDesc().Douglas(), "Douglas", true));
                descs.Add(new Tuple <FdmSchemeDesc, string, bool>(new FdmSchemeDesc().CrankNicolson(), "Crank-Nicolson", true));
                descs.Add(new Tuple <FdmSchemeDesc, string, bool>(new FdmSchemeDesc().ImplicitEuler(), "Implicit", false));
                descs.Add(new Tuple <FdmSchemeDesc, string, bool>(new FdmSchemeDesc().TrBDF2(), "TR-BDF2", false));

                for (int j = 0; j < descs.Count; ++j)
                {
                    FdmHestonSolver solver =
                        new FdmHestonSolver(new Handle <HestonProcess>(process),
                                            hestonEngine.getSolverDesc(1.0),
                                            descs[j].Item1);

                    List <double> gammas = new List <double>();
                    for (double x = 99; x < 101.001; x += 0.1)
                    {
                        gammas.Add(solver.gammaAt(x, v0));
                    }

                    double maximum = Double.MinValue;
                    for (int i = 1; i < gammas.Count; ++i)
                    {
                        double diff = Math.Abs(gammas[i] - gammas[i - 1]);
                        if (diff > maximum)
                        {
                            maximum = diff;
                        }
                    }

                    double tol = 0.01;
                    bool   hasSpuriousOscillations = maximum > tol;

                    if (hasSpuriousOscillations != descs[j].Item3)
                    {
                        QAssert.Fail("unable to reproduce spurious oscillation behaviour "
                                     + "\n   scheme name          : " + descs[j].Item2
                                     + "\n   oscillations observed: "
                                     + hasSpuriousOscillations
                                     + "\n   oscillations expected: " + descs[j].Item3
                                     );
                    }
                }
            }
        }
Exemple #4
0
        public void testMethodOfLinesAndCN()
        {
            //Testing method of lines to solve Heston PDEs...

            using (SavedSettings backup = new SavedSettings())
            {
                DayCounter dc    = new Actual365Fixed();
                Date       today = new Date(21, 2, 2018);

                Settings.Instance.setEvaluationDate(today);

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

                double v0    = 0.09;
                double kappa = 1.0;
                double theta = v0;
                double sigma = 0.4;
                double rho   = -0.75;

                Date maturity = today + new Period(3, TimeUnit.Months);

                HestonModel model =
                    new HestonModel(
                        new HestonProcess(rTS, qTS, spot, v0, kappa, theta, sigma, rho));

                int xGrid = 21;
                int vGrid = 7;

                IPricingEngine fdmDefault =
                    new FdHestonVanillaEngine(model, 10, xGrid, vGrid, 0);

                IPricingEngine fdmMol =
                    new FdHestonVanillaEngine(
                        model, 10, xGrid, vGrid, 0, new FdmSchemeDesc().MethodOfLines());

                PlainVanillaPayoff payoff =
                    new PlainVanillaPayoff(Option.Type.Put, spot.currentLink().value());

                VanillaOption option = new VanillaOption(payoff, new AmericanExercise(maturity));

                option.setPricingEngine(fdmMol);
                double calculatedMoL = option.NPV();

                option.setPricingEngine(fdmDefault);
                double expected = option.NPV();

                double tol     = 0.005;
                double diffMoL = Math.Abs(expected - calculatedMoL);

                if (diffMoL > tol)
                {
                    QAssert.Fail("Failed to reproduce european option values with MOL"
                                 + "\n    calculated: " + calculatedMoL
                                 + "\n    expected:   " + expected
                                 + "\n    difference: " + diffMoL
                                 + "\n    tolerance:  " + tol);
                }

                IPricingEngine fdmCN =
                    new FdHestonVanillaEngine(model, 10, xGrid, vGrid, 0, new FdmSchemeDesc().CrankNicolson());
                option.setPricingEngine(fdmCN);

                double calculatedCN = option.NPV();
                double diffCN       = Math.Abs(expected - calculatedCN);

                if (diffCN > tol)
                {
                    QAssert.Fail("Failed to reproduce european option values with Crank-Nicolson"
                                 + "\n    calculated: " + calculatedCN
                                 + "\n    expected:   " + expected
                                 + "\n    difference: " + diffCN
                                 + "\n    tolerance:  " + tol);
                }

                BarrierOption barrierOption =
                    new BarrierOption(Barrier.Type.DownOut, 85.0, 10.0,
                                      payoff, new EuropeanExercise(maturity));

                barrierOption.setPricingEngine(new FdHestonBarrierEngine(model, 100, 31, 11));

                double expectedBarrier = barrierOption.NPV();

                barrierOption.setPricingEngine(new FdHestonBarrierEngine(model, 100, 31, 11, 0, new FdmSchemeDesc().MethodOfLines()));

                double calculatedBarrierMoL = barrierOption.NPV();

                double barrierTol     = 0.01;
                double barrierDiffMoL = Math.Abs(expectedBarrier - calculatedBarrierMoL);

                if (barrierDiffMoL > barrierTol)
                {
                    QAssert.Fail("Failed to reproduce barrier option values with MOL"
                                 + "\n    calculated: " + calculatedBarrierMoL
                                 + "\n    expected:   " + expectedBarrier
                                 + "\n    difference: " + barrierDiffMoL
                                 + "\n    tolerance:  " + barrierTol);
                }

                barrierOption.setPricingEngine(new FdHestonBarrierEngine(model, 100, 31, 11, 0, new FdmSchemeDesc().CrankNicolson()));

                double calculatedBarrierCN = barrierOption.NPV();
                double barrierDiffCN       = Math.Abs(expectedBarrier - calculatedBarrierCN);

                if (barrierDiffCN > barrierTol)
                {
                    QAssert.Fail("Failed to reproduce barrier option values with Crank-Nicolson"
                                 + "\n    calculated: " + calculatedBarrierCN
                                 + "\n    expected:   " + expectedBarrier
                                 + "\n    difference: " + barrierDiffCN
                                 + "\n    tolerance:  " + barrierTol);
                }
            }
        }
Exemple #5
0
        public void testFdmHestonConvergence()
        {
            /* convergence tests based on
             * ADI finite difference schemes for option pricing in the
             * Heston model with correlation, K.J. in t'Hout and S. Foulon
             */

            //Testing FDM Heston convergence...

            using (SavedSettings backup = new SavedSettings())
            {
                HestonTestData[] values = new HestonTestData[] {
                    new HestonTestData(1.5, 0.04, 0.3, -0.9, 0.025, 0.0, 1.0, 100),
                    new HestonTestData(3.0, 0.12, 0.04, 0.6, 0.01, 0.04, 1.0, 100),
                    new HestonTestData(0.6067, 0.0707, 0.2928, -0.7571, 0.03, 0.0, 3.0, 100),
                    new HestonTestData(2.5, 0.06, 0.5, -0.1, 0.0507, 0.0469, 0.25, 100)
                };

                FdmSchemeDesc[] schemes = new FdmSchemeDesc[] {
                    new FdmSchemeDesc().Hundsdorfer(),
                    new FdmSchemeDesc().ModifiedCraigSneyd(),
                    new FdmSchemeDesc().ModifiedHundsdorfer(),
                    new FdmSchemeDesc().CraigSneyd(),
                    new FdmSchemeDesc().TrBDF2(),
                    new FdmSchemeDesc().CrankNicolson(),
                };

                int[]    tn = new int[] { 60 };
                double[] v0 = new double[] { 0.04 };

                Date todaysDate = new Date(28, 3, 2004);
                Settings.Instance.setEvaluationDate(todaysDate);

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

                for (int l = 0; l < schemes.Length; ++l)
                {
                    for (int i = 0; i < values.Length; ++i)
                    {
                        for (int j = 0; j < tn.Length; ++j)
                        {
                            for (int k = 0; k < v0.Length; ++k)
                            {
                                Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(
                                    Utilities.flatRate(values[i].r, new Actual365Fixed()));
                                Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(
                                    Utilities.flatRate(values[i].q, new Actual365Fixed()));

                                HestonProcess hestonProcess =
                                    new HestonProcess(rTS, qTS, s0,
                                                      v0[k],
                                                      values[i].kappa,
                                                      values[i].theta,
                                                      values[i].sigma,
                                                      values[i].rho);

                                Date exerciseDate = todaysDate
                                                    + new Period(Convert.ToInt32(values[i].T * 365), TimeUnit.Days);

                                Exercise          exercise = new EuropeanExercise(exerciseDate);
                                StrikedTypePayoff payoff   = new PlainVanillaPayoff(Option.Type.Call, values[i].K);

                                VanillaOption  option = new VanillaOption(payoff, exercise);
                                IPricingEngine engine =
                                    new FdHestonVanillaEngine(
                                        new HestonModel(hestonProcess),
                                        tn[j], 101, 51, 0,
                                        schemes[l]);

                                option.setPricingEngine(engine);

                                double calculated = option.NPV();

                                IPricingEngine analyticEngine =
                                    new AnalyticHestonEngine(
                                        new HestonModel(hestonProcess), 144);

                                option.setPricingEngine(analyticEngine);
                                double expected = option.NPV();
                                if (Math.Abs(expected - calculated) / expected > 0.02 &&
                                    Math.Abs(expected - calculated) > 0.002)
                                {
                                    QAssert.Fail("Failed to reproduce expected npv"
                                                 + "\n    calculated: " + calculated
                                                 + "\n    expected:   " + expected
                                                 + "\n    tolerance:  " + 0.01);
                                }
                            }
                        }
                    }
                }
            }
        }
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(FdHestonVanillaEngine obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }