Exemple #1
0
        public void testCrankNicolsonWithDamping()
        {
            SavedSettings backup = new SavedSettings();

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

            SimpleQuote           spot  = new SimpleQuote(100.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, 0.06, dc);
            YieldTermStructure    rTS   = Utilities.flatRate(today, 0.06, dc);
            BlackVolTermStructure volTS = Utilities.flatVol(today, 0.35, dc);

            StrikedTypePayoff payoff =
                new CashOrNothingPayoff(Option.Type.Put, 100, 10.0);

            double   maturity = 0.75;
            Date     exDate   = today + Convert.ToInt32(maturity * 360 + 0.5);
            Exercise exercise = new EuropeanExercise(exDate);

            BlackScholesMertonProcess process = new
                                                BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                          new Handle <YieldTermStructure>(qTS),
                                                                          new Handle <YieldTermStructure>(rTS),
                                                                          new Handle <BlackVolTermStructure>(volTS));
            IPricingEngine engine =
                new AnalyticEuropeanEngine(process);

            VanillaOption opt = new VanillaOption(payoff, exercise);

            opt.setPricingEngine(engine);
            double expectedPV    = opt.NPV();
            double expectedGamma = opt.gamma();

            // fd pricing using implicit damping steps and Crank Nicolson
            int        csSteps = 25, dampingSteps = 3, xGrid = 400;
            List <int> dim = new InitializedList <int>(1, xGrid);

            FdmLinearOpLayout layout       = new FdmLinearOpLayout(dim);
            Fdm1dMesher       equityMesher =
                new FdmBlackScholesMesher(
                    dim[0], process, maturity, payoff.strike(),
                    null, null, 0.0001, 1.5,
                    new Pair <double?, double?>(payoff.strike(), 0.01));

            FdmMesher mesher =
                new FdmMesherComposite(equityMesher);

            FdmBlackScholesOp map =
                new FdmBlackScholesOp(mesher, process, payoff.strike());

            FdmInnerValueCalculator calculator =
                new FdmLogInnerValue(payoff, mesher, 0);

            object rhs = new Vector(layout.size());
            Vector x   = new Vector(layout.size());
            FdmLinearOpIterator endIter = layout.end();

            for (FdmLinearOpIterator iter = layout.begin(); iter != endIter;
                 ++iter)
            {
                (rhs as Vector)[iter.index()] = calculator.avgInnerValue(iter, maturity);
                x[iter.index()] = mesher.location(iter, 0);
            }

            FdmBackwardSolver solver = new FdmBackwardSolver(map, new FdmBoundaryConditionSet(),
                                                             new FdmStepConditionComposite(),
                                                             new FdmSchemeDesc().Douglas());

            solver.rollback(ref rhs, maturity, 0.0, csSteps, dampingSteps);

            MonotonicCubicNaturalSpline spline = new MonotonicCubicNaturalSpline(x, x.Count, rhs as Vector);

            double s               = spot.value();
            double calculatedPV    = spline.value(Math.Log(s));
            double calculatedGamma = (spline.secondDerivative(Math.Log(s))
                                      - spline.derivative(Math.Log(s))) / (s * s);

            double relTol = 2e-3;

            if (Math.Abs(calculatedPV - expectedPV) > relTol * expectedPV)
            {
                QAssert.Fail("Error calculating the PV of the digital option" +
                             "\n rel. tolerance:  " + relTol +
                             "\n expected:        " + expectedPV +
                             "\n calculated:      " + calculatedPV);
            }
            if (Math.Abs(calculatedGamma - expectedGamma) > relTol * expectedGamma)
            {
                QAssert.Fail("Error calculating the Gamma of the digital option" +
                             "\n rel. tolerance:  " + relTol +
                             "\n expected:        " + expectedGamma +
                             "\n calculated:      " + calculatedGamma);
            }
        }
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BlackVolTermStructure obj) {
   return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
 }
Exemple #3
0
        public void testAssetAtExpiryOrNothingAmericanValues()
        {
            // Testing American asset-(at-expiry)-or-nothing digital option

            DigitalOptionData[] values =
            {
                //        type, strike,   spot,    q,    r,   t,  vol,   value, tol
                // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 95, case 7,8,11,12
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.00, 0.10, 0.5, 0.20,                     64.8426, 1e-04, true),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.00, 0.10, 0.5, 0.20,                     77.7017, 1e-04, true),
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.00, 0.10, 0.5, 0.20,                     40.1574, 1e-04, false),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.00, 0.10, 0.5, 0.20,                     17.2983, 1e-04, false),
                // data from Haug VBA code results
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.01, 0.10, 0.5, 0.20,                     65.5291, 1e-04, true),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.01, 0.10, 0.5, 0.20,                     76.5951, 1e-04, true),
                // in the money options (guaranteed discounted payoff = forward * riskFreeDiscount
                //                                                    = spot * dividendDiscount)
                new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20,                    105.0000, 1e-12, true),
                new DigitalOptionData(Option.Type.Put,  100.00,  95.00, 0.00, 0.10, 0.5, 0.20,                     95.0000, 1e-12, true),
                new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.01, 0.10, 0.5, 0.20, 105.0000 * Math.Exp(-0.005), 1e-12, true),
                new DigitalOptionData(Option.Type.Put,  100.00,  95.00, 0.01, 0.10, 0.5, 0.20,  95.0000 * Math.Exp(-0.005), 1e-12, true)
            };

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

            SimpleQuote           spot  = new SimpleQuote(100.0);
            SimpleQuote           qRate = new SimpleQuote(0.04);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.01);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.25);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new AssetOrNothingPayoff(values[i].type, values[i].strike);

                Date     exDate     = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise amExercise = new AmericanExercise(today, exDate, true);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                       new Handle <YieldTermStructure>(qTS),
                                                                                       new Handle <YieldTermStructure>(rTS),
                                                                                       new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine;
                if (values[i].knockin)
                {
                    engine = new AnalyticDigitalAmericanEngine(stochProcess);
                }
                else
                {
                    engine = new AnalyticDigitalAmericanKOEngine(stochProcess);
                }

                VanillaOption opt = new VanillaOption(payoff, amExercise);
                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, amExercise, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol, values[i].knockin);
                }
            }
        }
Exemple #4
0
        public void testCashOrNothingHaugValues()
        {
            // Testing cash-or-nothing barrier options against Haug's values

            BinaryOptionData[] values =
            {
                /* The data below are from
                 * "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 180 - cases 13,14,17,18,21,22,25,26
                 * Note:
                 * q is the dividend rate, while the book gives b, the cost of carry (q=r-b)
                 */
                //    barrierType, barrier,  cash,         type, strike,   spot,    q,    r,   t,  vol,   value, tol
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Call, 102.00, 105.00,  0.00, 0.10, 0.5, 0.20,  4.9289, 1e-4),
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Call,  98.00, 105.00,  0.00, 0.10, 0.5, 0.20,  6.2150, 1e-4),
                // following value is wrong in book.
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call, 102.00,  95.00,  0.00, 0.10, 0.5, 0.20,  5.8926, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call,  98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  7.4519, 1e-4),
                // 17,18
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Put,  102.00, 105.00,  0.00, 0.10, 0.5, 0.20,  4.4314, 1e-4),
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Put,   98.00, 105.00,  0.00, 0.10, 0.5, 0.20,  3.1454, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Put,  102.00,  95.00,  0.00, 0.10, 0.5, 0.20,  5.3297, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Put,   98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  3.7704, 1e-4),
                // 21,22
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call, 102.00, 105.00,  0.00, 0.10, 0.5, 0.20,  4.8758, 1e-4),
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call,  98.00, 105.00,  0.00, 0.10, 0.5, 0.20,  4.9081, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Call, 102.00,  95.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Call,  98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  0.0407, 1e-4),
                // 25,26
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put,  102.00, 105.00,  0.00, 0.10, 0.5, 0.20,  0.0323, 1e-4),
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put,   98.00, 105.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Put,  102.00,  95.00,  0.00, 0.10, 0.5, 0.20,  3.0461, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Put,   98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  3.0054, 1e-4),

                // other values calculated with book vba
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call, 102.00,  95.00, -0.14, 0.10, 0.5, 0.20,  8.6806, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call, 102.00,  95.00,  0.03, 0.10, 0.5, 0.20,  5.3112, 1e-4),
                // degenerate conditions (barrier touched)
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Call,  98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  7.4926, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call,  98.00, 105.00,  0.00, 0.10, 0.5, 0.20, 11.1231, 1e-4),
                // 17,18
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Put,  102.00,  98.00,  0.00, 0.10, 0.5, 0.20,  7.1344, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Put,  102.00, 101.00,  0.00, 0.10, 0.5, 0.20,  5.9299, 1e-4),
                // 21,22
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call,  98.00,  99.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Call,  98.00, 101.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                // 25,26
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put,   98.00,  99.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Put,   98.00, 101.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
            };

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

            SimpleQuote           spot  = new SimpleQuote(100.0);
            SimpleQuote           qRate = new SimpleQuote(0.04);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.01);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.25);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new CashOrNothingPayoff(values[i].type, values[i].strike, values[i].cash);

                Date     exDate     = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise amExercise = new AmericanExercise(today, exDate, true);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new AnalyticBinaryBarrierEngine(stochProcess);

                BarrierOption opt = new BarrierOption(values[i].barrierType, values[i].barrier, 0, payoff, amExercise);

                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, amExercise, values[i].barrierType,
                                   values[i].barrier, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol);
                }
            }
        }
Exemple #5
0
        public void testBjerksundStenslandValues()
        {
            // ("Testing Bjerksund and Stensland approximation for American options...");

            AmericanOptionData[] values = new AmericanOptionData[] {
                //      type, strike,   spot,    q,    r,    t,  vol,   value, tol
                // from "Option pricing formulas", Haug, McGraw-Hill 1998, pag 27
                new AmericanOptionData(Option.Type.Call, 40.00, 42.00, 0.08, 0.04, 0.75, 0.35, 5.2704),
                // from "Option pricing formulas", Haug, McGraw-Hill 1998, VBA code
                new AmericanOptionData(Option.Type.Put, 40.00, 36.00, 0.00, 0.06, 1.00, 0.20, 4.4531),
                // ATM option with very small volatility, reference value taken from R
                new AmericanOptionData(Option.Type.Call, 100, 100, 0.05, 0.05, 1.0, 0.0021, 0.08032314),
                // ATM option with very small volatility,
                // reference value taken from Barone-Adesi and Whaley Approximation
                new AmericanOptionData(Option.Type.Call, 100, 100, 0.05, 0.05, 1.0, 0.0001, 0.003860656),
                new AmericanOptionData(Option.Type.Call, 100, 99.99, 0.05, 0.05, 1.0, 0.0001, 0.00081),
                // ITM option with a very small volatility
                new AmericanOptionData(Option.Type.Call, 100, 110, 0.05, 0.05, 1.0, 0.0001, 10.0),
                new AmericanOptionData(Option.Type.Put, 110, 100, 0.05, 0.05, 1.0, 0.0001, 10.0),
                // ATM option with a very large volatility
                new AmericanOptionData(Option.Type.Put, 100, 110, 0.05, 0.05, 1.0, 10, 94.89543)
            };

            Date               today = Date.Today;
            DayCounter         dc    = new Actual360();
            SimpleQuote        spot  = new SimpleQuote(0.0);
            SimpleQuote        qRate = new SimpleQuote(0.0);
            YieldTermStructure qTS   = Utilities.flatRate(today, qRate, dc);

            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            double tolerance = 5.0e-5;

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike);
                Date     exDate          = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise exercise        = new AmericanExercise(today, exDate);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                       new Handle <YieldTermStructure>(qTS),
                                                                                       new Handle <YieldTermStructure>(rTS),
                                                                                       new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new BjerksundStenslandApproximationEngine(stochProcess);

                VanillaOption option = new VanillaOption(payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > tolerance)
                {
                    REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q,
                                   values[i].r, today, values[i].v, values[i].result,
                                   calculated, error, tolerance);
                }
            }
        }
Exemple #6
0
        public void testCashAtHitOrNothingAmericanValues()
        {
            // Testing American cash-(at-hit)-or-nothing digital option

            DigitalOptionData[] values =
            {
                //        type, strike,   spot,    q,    r,   t,  vol,   value, tol
                // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 95, case 1,2
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.00, 0.10, 0.5, 0.20,  9.7264,  1e-4, true),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.00, 0.10, 0.5, 0.20, 11.6553,  1e-4, true),

                // the following cases are not taken from a reference paper or book
                // in the money options (guaranteed immediate payoff)
                new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 15.0000, 1e-16, true),
                new DigitalOptionData(Option.Type.Put,  100.00,  95.00, 0.00, 0.10, 0.5, 0.20, 15.0000, 1e-16, true),
                // non null dividend (cross-tested with MC simulation)
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.20, 0.10, 0.5, 0.20, 12.2715,  1e-4, true),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.20, 0.10, 0.5, 0.20,  8.9109,  1e-4, true),
                new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.20, 0.10, 0.5, 0.20, 15.0000, 1e-16, true),
                new DigitalOptionData(Option.Type.Put,  100.00,  95.00, 0.20, 0.10, 0.5, 0.20, 15.0000, 1e-16, true)
            };

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

            SimpleQuote           spot  = new SimpleQuote(0.0);
            SimpleQuote           qRate = new SimpleQuote(0.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new CashOrNothingPayoff(values[i].type, values[i].strike, 15.00);

                Date     exDate     = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise amExercise = new AmericanExercise(today, exDate);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                       new Handle <YieldTermStructure>(qTS),
                                                                                       new Handle <YieldTermStructure>(rTS),
                                                                                       new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new AnalyticDigitalAmericanEngine(stochProcess);

                VanillaOption opt = new VanillaOption(payoff, amExercise);
                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, amExercise, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol, values[i].knockin);
                }
            }
        }
        //void testEngineConsistency(EngineType engine, int binomialSteps, int samples, Dictionary<string,double> tolerance,
        //                           bool testGreeks = false) {
        void testEngineConsistency(EngineType engine, int binomialSteps, int samples, Dictionary <string, double> tolerance,
                                   bool testGreeks)
        {
            //QL_TEST_START_TIMING

            Dictionary <string, double> calculated = new Dictionary <string, double>(), expected = new Dictionary <string, double>();

            // test options
            Option.Type[] types         = { Option.Type.Call, Option.Type.Put };
            double[]      strikes       = { 75.0, 100.0, 125.0 };
            int[]         lengths       = { 1 };

            // test data
            double[] underlyings        = { 100.0 };
            double[] qRates             = { 0.00, 0.05 };
            double[] rRates             = { 0.01, 0.05, 0.15 };
            double[] vols               = { 0.11, 0.50, 1.20 };

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

            SimpleQuote           spot = new SimpleQuote(0.0);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);
            SimpleQuote           qRate = new SimpleQuote(0.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);

            for (int i = 0; i < types.Length; i++)
            {
                for (int j = 0; j < strikes.Length; j++)
                {
                    for (int k = 0; k < lengths.Length; k++)
                    {
                        Date              exDate   = today + lengths[k] * 360;
                        Exercise          exercise = new EuropeanExercise(exDate);
                        StrikedTypePayoff payoff   = new PlainVanillaPayoff(types[i], strikes[j]);
                        // reference option
                        VanillaOption refOption = makeOption(payoff, exercise, spot, qTS, rTS, volTS,
                                                             EngineType.Analytic, 0, 0);
                        // option to check
                        VanillaOption option = makeOption(payoff, exercise, spot, qTS, rTS, volTS,
                                                          engine, binomialSteps, samples);

                        for (int l = 0; l < underlyings.Length; l++)
                        {
                            for (int m = 0; m < qRates.Length; m++)
                            {
                                for (int n = 0; n < rRates.Length; n++)
                                {
                                    for (int p = 0; p < vols.Length; p++)
                                    {
                                        double u = underlyings[l];
                                        double q = qRates[m],
                                               r = rRates[n];
                                        double v = vols[p];
                                        spot.setValue(u);
                                        qRate.setValue(q);
                                        rRate.setValue(r);
                                        vol.setValue(v);

                                        expected.Clear();
                                        calculated.Clear();

                                        // FLOATING_POINT_EXCEPTION
                                        expected.Add("value", refOption.NPV());
                                        calculated.Add("value", option.NPV());

                                        if (testGreeks && option.NPV() > spot.value() * 1.0e-5)
                                        {
                                            expected.Add("delta", refOption.delta());
                                            expected.Add("gamma", refOption.gamma());
                                            expected.Add("theta", refOption.theta());
                                            calculated.Add("delta", option.delta());
                                            calculated.Add("gamma", option.gamma());
                                            calculated.Add("theta", option.theta());
                                        }
                                        foreach (string greek in calculated.Keys)
                                        {
                                            double expct      = expected[greek],
                                                        calcl = calculated[greek],
                                                        tol   = tolerance[greek];
                                            double error      = Utilities.relativeError(expct, calcl, u);
                                            if (error > tol)
                                            {
                                                REPORT_FAILURE(greek, payoff, exercise,
                                                               u, q, r, today, v,
                                                               expct, calcl, error, tol);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BlackVolTermStructure obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
 GeneralizedBlackScholesProcess makeProcess(Quote u, YieldTermStructure q, YieldTermStructure r, BlackVolTermStructure vol)
 {
     return(new BlackScholesMertonProcess(new Handle <Quote>(u), new Handle <YieldTermStructure>(q),
                                          new Handle <YieldTermStructure>(r), new Handle <BlackVolTermStructure>(vol)));
 }
Exemple #10
0
        VanillaOption makeOption(StrikedTypePayoff payoff, Exercise exercise, Quote u, YieldTermStructure q,
                                 YieldTermStructure r, BlackVolTermStructure vol, EngineType engineType, int binomialSteps, int samples)
        {
            GeneralizedBlackScholesProcess stochProcess = makeProcess(u, q, r, vol);

            IPricingEngine engine;

            switch (engineType)
            {
            case EngineType.Analytic:
                engine = new AnalyticEuropeanEngine(stochProcess);
                break;

            case EngineType.JR:
                engine = new BinomialVanillaEngine <JarrowRudd>(stochProcess, binomialSteps);
                break;

            case EngineType.CRR:
                engine = new BinomialVanillaEngine <CoxRossRubinstein>(stochProcess, binomialSteps);
                break;

            case EngineType.EQP:
                engine = new BinomialVanillaEngine <AdditiveEQPBinomialTree>(stochProcess, binomialSteps);
                break;

            case EngineType.TGEO:
                engine = new BinomialVanillaEngine <Trigeorgis>(stochProcess, binomialSteps);
                break;

            case EngineType.TIAN:
                engine = new BinomialVanillaEngine <Tian>(stochProcess, binomialSteps);
                break;

            case EngineType.LR:
                engine = new BinomialVanillaEngine <LeisenReimer>(stochProcess, binomialSteps);
                break;

            case EngineType.JOSHI:
                engine = new BinomialVanillaEngine <Joshi4>(stochProcess, binomialSteps);
                break;

            case EngineType.FiniteDifferences:
                engine = new FDEuropeanEngine(stochProcess, binomialSteps, samples);
                break;

            case EngineType.Integral:
                engine = new IntegralEngine(stochProcess);
                break;

            //case EngineType.PseudoMonteCarlo:
            //  engine = MakeMCEuropeanEngine<PseudoRandom>(stochProcess)
            //      .withSteps(1)
            //      .withSamples(samples)
            //      .withSeed(42);
            //  break;
            //case EngineType.QuasiMonteCarlo:
            //  engine = MakeMCEuropeanEngine<LowDiscrepancy>(stochProcess)
            //      .withSteps(1)
            //      .withSamples(samples);
            //  break;
            default:
                throw new ArgumentException("unknown engine type");
            }

            VanillaOption option = new EuropeanOption(payoff, exercise);

            option.setPricingEngine(engine);
            return(option);
        }
Exemple #11
0
        public void testHaugValues()
        {
            // Testing cash-or-nothing double barrier options against Haug's values

            DoubleBinaryOptionData[] values =
            {
                /* The data below are from
                 *  "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 181
                 *  Note: book uses cost of carry b, instead of dividend rate q
                 */
                //                                  barrierType,          bar_lo, bar_hi, cash,   spot,   q,    r,    t,    vol,   value, tol
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  9.8716, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  8.9307, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  6.3272, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  1.9094, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  9.7961, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  7.2300, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  3.7100, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  0.4271, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  8.9054, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  3.6752, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  0.7960, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  0.0059, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  3.6323, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.0911, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  0.0002, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  0.0000, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.2402, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  1.4076, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  3.8160, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0075, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.9910, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  2.8098, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.6612, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.2656, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  2.7954, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  4.4024, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.9266, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  2.6285, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  4.7523, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  4.9096, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.9675, 1e-4),

                // following values calculated with haug's VBA code
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0042, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.9450, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  3.5486, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  7.9663, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0797, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  2.6458, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  6.1658, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  9.4486, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.9704, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  6.2006, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  9.0798, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  9.8699, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  6.2434, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  9.7847, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  9.8756, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  9.8758, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0041, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  0.7080, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  2.1581, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.2061, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.0723, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  1.6663, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  3.3930, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  4.8679, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  0.7080, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  3.4424, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  4.7496, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  5.0475, 1e-4),

                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10,  3.6524, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20,  5.1256, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30,  5.0763, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50,  5.0275, 1e-4),

                // degenerate cases
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00,  80.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  95.00, 105.00, 10.00,  80.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn,  95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     95.00, 105.00, 10.00,  80.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO,     95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     95.00, 105.00, 10.00,  80.00, 0.02, 0.05, 0.25, 0.10,  0.0000, 1e-4),
                new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI,     95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4),
            };

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

            SimpleQuote           spot  = new SimpleQuote(100.0);
            SimpleQuote           qRate = new SimpleQuote(0.04);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.01);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.25);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new CashOrNothingPayoff(Option.Type.Call, 0, values[i].cash);

                Date     exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise exercise;
                if (values[i].barrierType == DoubleBarrier.Type.KIKO ||
                    values[i].barrierType == DoubleBarrier.Type.KOKI)
                {
                    exercise = new AmericanExercise(today, exDate, true);
                }
                else
                {
                    exercise = new EuropeanExercise(exDate);
                }

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new AnalyticDoubleBarrierBinaryEngine(stochProcess);

                DoubleBarrierOption opt = new DoubleBarrierOption(values[i].barrierType,
                                                                  values[i].barrier_lo,
                                                                  values[i].barrier_hi,
                                                                  0,
                                                                  payoff,
                                                                  exercise);

                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double expected   = values[i].result;
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, exercise, values[i].barrierType,
                                   values[i].barrier_lo, values[i].barrier_hi, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol);
                }

                int steps = 500;
                // checking with binomial engine
                engine = new BinomialDoubleBarrierEngine(
                    (d, end, step, strike) => new CoxRossRubinstein(d, end, step, strike),
                    (args, process, grid) => new DiscretizedDoubleBarrierOption(args, process, grid),
                    stochProcess, steps);
                opt.setPricingEngine(engine);
                calculated = opt.NPV();
                expected   = values[i].result;
                error      = Math.Abs(calculated - expected);
                double tol = 0.22;
                if (error > tol)
                {
                    REPORT_FAILURE("Binomial value", payoff, exercise, values[i].barrierType,
                                   values[i].barrier_lo, values[i].barrier_hi, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, tol);
                }
            }
        }
Exemple #12
0
        public void testKirkEngine()
        {
            // Testing Kirk approximation for spread options

            /* The example data below are from "complete guide to option
             * pricing formulas", Espen Gaarder Haug, p 60
             *
             * Expected values of option theta were calculated using automatic
             * differentiation of the pricing function. The engine uses closed-form
             * formula */

            Case[] cases =
            {
                new Case(28.0,   20.0, 7.0, 0.05, 0.29, 0.36, 0.42,  90,  2.1670,  3.0431),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, -0.5,  36,  4.7530, 25.5905),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20,  0.0,  36,  3.7970, 20.8841),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20,  0.5,  36,  2.5537, 14.7260),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, -0.5, 180, 10.7517, 10.0847),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20,  0.0, 180,  8.7020,  8.2619),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20,  0.5, 180,  6.0257,  5.8661),
                new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, -0.5,  36,  5.4275, 28.9013),
                new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20,  0.0,  36,  4.3712, 23.7133),
                new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20,  0.5,  36,  3.0086, 16.9864),
                new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, -0.5, 180, 12.1941, 11.3603),
                new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20,  0.0, 180,  9.9340,  9.3589),
                new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20,  0.5, 180,  7.0067,  6.7463),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, -0.5,  36,  5.4061, 28.7963),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25,  0.0,  36,  4.3451, 23.5848),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25,  0.5,  36,  2.9723, 16.8060),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, -0.5, 180, 12.1483, 11.3200),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25,  0.0, 180,  9.8780,  9.3091),
                new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25,  0.5, 180,  6.9284, 6.6761)
            };

            for (int i = 0; i < cases.Length; ++i)
            {
                // First step: preparing the test values
                // Useful dates
                DayCounter dc           = new Actual360();
                Date       today        = Date.Today;
                Date       exerciseDate = today + cases[i].length;

                // Futures values
                SimpleQuote F1 = new SimpleQuote(cases[i].F1);
                SimpleQuote F2 = new SimpleQuote(cases[i].F2);

                // Risk-free interest rate
                double             riskFreeRate = cases[i].r;
                YieldTermStructure forwardRate  = Utilities.flatRate(today, riskFreeRate, dc);

                // Correlation
                Quote rho = new SimpleQuote(cases[i].rho);

                // Volatilities
                double vol1 = cases[i].sigma1;
                double vol2 = cases[i].sigma2;
                BlackVolTermStructure volTS1 = Utilities.flatVol(today, vol1, dc);
                BlackVolTermStructure volTS2 = Utilities.flatVol(today, vol2, dc);

                // Black-Scholes Processes
                // The BlackProcess is the relevant class for futures contracts
                BlackProcess stochProcess1 = new BlackProcess(new Handle <Quote>(F1),
                                                              new Handle <YieldTermStructure>(forwardRate),
                                                              new Handle <BlackVolTermStructure>(volTS1));

                BlackProcess stochProcess2 = new BlackProcess(new Handle <Quote>(F2),
                                                              new Handle <YieldTermStructure>(forwardRate),
                                                              new Handle <BlackVolTermStructure>(volTS2));

                // Creating the pricing engine
                IPricingEngine engine = new KirkSpreadOptionEngine(stochProcess1,
                                                                   stochProcess2, new Handle <Quote>(rho));

                // Finally, create the option:
                Option.Type        type     = Option.Type.Call;
                double             strike   = cases[i].X;
                PlainVanillaPayoff payoff   = new PlainVanillaPayoff(type, strike);
                Exercise           exercise = new EuropeanExercise(exerciseDate);

                SpreadOption option = new SpreadOption(payoff, exercise);
                option.setPricingEngine(engine);

                // And test the data
                double value     = option.NPV();
                double theta     = option.theta();
                double tolerance = 1e-4;

                if (Math.Abs(value - cases[i].value) > tolerance)
                {
                    REPORT_FAILURE("value",
                                   payoff, exercise,
                                   cases[i].value, value, tolerance, today);
                }

                if (Math.Abs(theta - cases[i].theta) > tolerance)
                {
                    REPORT_FAILURE("theta",
                                   payoff, exercise,
                                   cases[i].theta, theta, tolerance, today);
                }
            }
        }
 public BlackVolTermStructure __deref__() {
   BlackVolTermStructure ret = new BlackVolTermStructure(NQuantLibcPINVOKE.BlackVolTermStructureHandle___deref__(swigCPtr), true);
   if (NQuantLibcPINVOKE.SWIGPendingException.Pending) throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve();
   return ret;
 }
Exemple #14
0
        public void testMonteCarloLookback()
        {
            double tolerance = 0.1;

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

            double strike = 90;
            double t      = 1;
            double t1     = 0.25;

            Date     exDate   = today + Convert.ToInt32(t * 360 + 0.5);
            Exercise exercise = new EuropeanExercise(exDate);

            SimpleQuote           spot  = new SimpleQuote(0.0);
            SimpleQuote           qRate = new SimpleQuote(0.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            spot.setValue(100);
            qRate.setValue(0);
            rRate.setValue(0.06);
            vol.setValue(0.1);

            BlackScholesMertonProcess stochProcess =
                new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

            Option.Type[] types = new Option.Type[] { Option.Type.Call, Option.Type.Put };

            for (int i = 0; i < types.Length; i++)
            {
                Option.Type type = types[i];

                StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike);

                /**
                 * Partial Fixed
                 * **/

                Date lookbackStart = today + Convert.ToInt32(t1 * 360 + 0.5);
                ContinuousPartialFixedLookbackOption partialFixedLookback
                    = new ContinuousPartialFixedLookbackOption(lookbackStart,
                                                               payoff,
                                                               exercise);
                IPricingEngine engine =
                    new AnalyticContinuousPartialFixedLookbackEngine(stochProcess);

                partialFixedLookback.setPricingEngine(engine);

                double analytical = partialFixedLookback.NPV();

                IPricingEngine mcpartialfixedengine =
                    new MakeMCLookbackEngine <ContinuousPartialFixedLookbackOption.Arguments, ContinuousPartialFixedLookbackOption.Results,
                                              PseudoRandom, Statistics>(stochProcess)
                    .withSteps(2000)
                    .withAntitheticVariate()
                    .withSeed(1)
                    .withAbsoluteTolerance(tolerance)
                    .value();

                partialFixedLookback.setPricingEngine(mcpartialfixedengine);
                double monteCarlo = partialFixedLookback.NPV();

                double diff = Math.Abs(analytical - monteCarlo);

                if (diff > tolerance)
                {
                    REPORT_FAILURE_MC("Partial Fixed", type, analytical, monteCarlo, tolerance);
                }

                /**
                 * Fixed
                 * **/

                double minMax = 100;

                ContinuousFixedLookbackOption fixedLookback
                    = new ContinuousFixedLookbackOption(minMax,
                                                        payoff,
                                                        exercise);
                IPricingEngine analyticalfixedengine =
                    new AnalyticContinuousFixedLookbackEngine(stochProcess);

                fixedLookback.setPricingEngine(analyticalfixedengine);
                analytical = fixedLookback.NPV();

                IPricingEngine mcfixedengine =
                    new MakeMCLookbackEngine <ContinuousFixedLookbackOption.Arguments, ContinuousFixedLookbackOption.Results,
                                              PseudoRandom, Statistics>(stochProcess)
                    .withSteps(2000)
                    .withAntitheticVariate()
                    .withSeed(1)
                    .withAbsoluteTolerance(tolerance)
                    .value();

                fixedLookback.setPricingEngine(mcfixedengine);
                monteCarlo = fixedLookback.NPV();

                diff = Math.Abs(analytical - monteCarlo);

                if (diff > tolerance)
                {
                    REPORT_FAILURE_MC("Fixed", type, analytical, monteCarlo, tolerance);
                }

                /**
                 * Partial Floating
                 * **/

                double lambda      = 1;
                Date   lookbackEnd = today + Convert.ToInt32(t1 * 360 + 0.5);

                FloatingTypePayoff floatingPayoff = new FloatingTypePayoff(type);

                ContinuousPartialFloatingLookbackOption partialFloating
                    = new ContinuousPartialFloatingLookbackOption(minMax,
                                                                  lambda,
                                                                  lookbackEnd,
                                                                  floatingPayoff,
                                                                  exercise);
                IPricingEngine analyticalpartialFloatingengine =
                    new AnalyticContinuousPartialFloatingLookbackEngine(stochProcess);
                partialFloating.setPricingEngine(analyticalpartialFloatingengine);

                analytical = partialFloating.NPV();

                IPricingEngine mcpartialfloatingengine =
                    new MakeMCLookbackEngine <ContinuousPartialFloatingLookbackOption.Arguments, ContinuousPartialFloatingLookbackOption.Results,
                                              PseudoRandom, Statistics>
                        (stochProcess)
                    .withSteps(2000)
                    .withAntitheticVariate()
                    .withSeed(1)
                    .withAbsoluteTolerance(tolerance)
                    .value();

                partialFloating.setPricingEngine(mcpartialfloatingengine);
                monteCarlo = partialFloating.NPV();

                diff = Math.Abs(analytical - monteCarlo);

                if (diff > tolerance)
                {
                    REPORT_FAILURE_MC("Partial Floating", type, analytical, monteCarlo, tolerance);
                }

                /**
                 * Floating
                 * **/

                ContinuousFloatingLookbackOption floating =
                    new ContinuousFloatingLookbackOption(minMax,
                                                         floatingPayoff,
                                                         exercise);
                IPricingEngine analyticalFloatingengine =
                    new AnalyticContinuousFloatingLookbackEngine(stochProcess);
                floating.setPricingEngine(analyticalFloatingengine);

                analytical = floating.NPV();

                IPricingEngine mcfloatingengine =
                    new MakeMCLookbackEngine <ContinuousFloatingLookbackOption.Arguments, ContinuousFloatingLookbackOption.Results,
                                              PseudoRandom, Statistics>
                        (stochProcess)
                    .withSteps(2000)
                    .withAntitheticVariate()
                    .withSeed(1)
                    .withAbsoluteTolerance(tolerance)
                    .value();

                floating.setPricingEngine(mcfloatingengine);
                monteCarlo = floating.NPV();

                diff = Math.Abs(analytical - monteCarlo);

                if (diff > tolerance)
                {
                    REPORT_FAILURE_MC("Floating", type, analytical, monteCarlo, tolerance);
                }
            }
        }
 public RelinkableBlackVolTermStructureHandle(BlackVolTermStructure arg0) : this(NQuantLibcPINVOKE.new_RelinkableBlackVolTermStructureHandle__SWIG_0(BlackVolTermStructure.getCPtr(arg0)), true) {
   if (NQuantLibcPINVOKE.SWIGPendingException.Pending) throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve();
 }
Exemple #16
0
        public void testBSMOperatorConsistency()
        {
            //("Testing consistency of BSM operators...");

            Vector grid   = new Vector(10);
            double price  = 20.0;
            double factor = 1.1;

            for (int i = 0; i < grid.size(); i++)
            {
                grid[i] = price;
                price  *= factor;
            }

            double dx    = Math.Log(factor);
            double r     = 0.05;
            double q     = 0.01;
            double sigma = 0.5;

            BSMOperator refer = new BSMOperator(grid.size(), dx, r, q, sigma);

            DayCounter dc           = new Actual360();
            Date       today        = Date.Today;
            Date       exercise     = today + new Period(2, TimeUnit.Years);
            double     residualTime = dc.yearFraction(today, exercise);

            SimpleQuote                    spot         = new SimpleQuote(0.0);
            YieldTermStructure             qTS          = Utilities.flatRate(today, q, dc);
            YieldTermStructure             rTS          = Utilities.flatRate(today, r, dc);
            BlackVolTermStructure          volTS        = Utilities.flatVol(today, sigma, dc);
            GeneralizedBlackScholesProcess stochProcess = new GeneralizedBlackScholesProcess(
                new Handle <Quote>(spot),
                new Handle <YieldTermStructure>(qTS),
                new Handle <YieldTermStructure>(rTS),
                new Handle <BlackVolTermStructure>(volTS));
            BSMOperator          op1 = new BSMOperator(grid, stochProcess, residualTime);
            PdeOperator <PdeBSM> op2 = new PdeOperator <PdeBSM>(grid, stochProcess, residualTime);

            double tolerance = 1.0e-6;
            Vector lderror   = refer.lowerDiagonal() - op1.lowerDiagonal();
            Vector derror    = refer.diagonal() - op1.diagonal();
            Vector uderror   = refer.upperDiagonal() - op1.upperDiagonal();

            for (int i = 2; i < grid.size() - 2; i++)
            {
                if (Math.Abs(lderror[i]) > tolerance ||
                    Math.Abs(derror[i]) > tolerance ||
                    Math.Abs(uderror[i]) > tolerance)
                {
                    Assert.Fail("inconsistency between BSM operators:\n"
                                + i + " row:\n"
                                + "expected:   "
                                + refer.lowerDiagonal()[i] + ", "
                                + refer.diagonal()[i] + ", "
                                + refer.upperDiagonal()[i] + "\n"
                                + "calculated: "
                                + op1.lowerDiagonal()[i] + ", "
                                + op1.diagonal()[i] + ", "
                                + op1.upperDiagonal()[i]);
                }
            }
            lderror = refer.lowerDiagonal() - op2.lowerDiagonal();
            derror  = refer.diagonal() - op2.diagonal();
            uderror = refer.upperDiagonal() - op2.upperDiagonal();

            for (int i = 2; i < grid.size() - 2; i++)
            {
                if (Math.Abs(lderror[i]) > tolerance ||
                    Math.Abs(derror[i]) > tolerance ||
                    Math.Abs(uderror[i]) > tolerance)
                {
                    Assert.Fail("inconsistency between BSM operators:\n"
                                + i + " row:\n"
                                + "expected:   "
                                + refer.lowerDiagonal()[i] + ", "
                                + refer.diagonal()[i] + ", "
                                + refer.upperDiagonal()[i] + "\n"
                                + "calculated: "
                                + op2.lowerDiagonal()[i] + ", "
                                + op2.diagonal()[i] + ", "
                                + op2.upperDiagonal()[i]);
                }
            }
        }
 public void linkTo(BlackVolTermStructure arg0) {
   NQuantLibcPINVOKE.RelinkableBlackVolTermStructureHandle_linkTo(swigCPtr, BlackVolTermStructure.getCPtr(arg0));
   if (NQuantLibcPINVOKE.SWIGPendingException.Pending) throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve();
 }
Exemple #18
0
        public void testBaroneAdesiWhaleyValues()
        {
            // ("Testing Barone-Adesi and Whaley approximation for American options...");

            /* The data below are from
             * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 24
             *
             * The following values were replicated only up to the second digit
             * by the VB code provided by Haug, which was used as base for the
             * C++ implementation
             *
             */
            AmericanOptionData[] values =
            {
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.15,  0.0206),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15,  1.8771),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 10.0089),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.25,  0.3159),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25,  3.1280),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 10.3919),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.35,  0.9495),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35,  4.3777),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 11.1679),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.15,  0.8208),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15,  4.0842),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 10.8087),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.25,  2.7437),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25,  6.8015),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 13.0170),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.35,  5.0063),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35,  9.5106),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 15.5689),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.15, 10.0000),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.15,  1.8770),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.15,  0.0410),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.25, 10.2533),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.25,  3.1277),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.25,  0.4562),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.35, 10.8787),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.35,  4.3777),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.35,  1.2402),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.15, 10.5595),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.15,  4.0842),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.15,  1.0822),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.25, 12.4419),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.25,  6.8014),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.25,  3.3226),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.35, 14.6945),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.35,  9.5104),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.35,  5.8823),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.00, 0.00, 0.50, 0.15, 4.22949)
            };

            Date               today = Date.Today;
            DayCounter         dc    = new Actual360();
            SimpleQuote        spot  = new SimpleQuote(0.0);
            SimpleQuote        qRate = new SimpleQuote(0.0);
            YieldTermStructure qTS   = Utilities.flatRate(today, qRate, dc);

            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            double tolerance = 3.0e-3;

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike);
                Date     exDate          = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise exercise        = new AmericanExercise(today, exDate);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                       new Handle <YieldTermStructure>(qTS),
                                                                                       new Handle <YieldTermStructure>(rTS),
                                                                                       new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new BaroneAdesiWhaleyApproximationEngine(stochProcess);

                VanillaOption option = new VanillaOption(payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > tolerance)
                {
                    REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q,
                                   values[i].r, today, values[i].v, values[i].result,
                                   calculated, error, tolerance);
                }
            }
        }
Exemple #19
0
        public void testEuroTwoValues()
        {
            // Testing two-asset European basket options...

            /*
             * Data from:
             * Excel spreadsheet www.maths.ox.ac.uk/~firth/computing/excel.shtml
             * and
             * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 56-58
             * European two asset max basket options
             */
            BasketOptionTwoData[] values =
            {
                // basketType,   optionType, strike,    s1,    s2,   q1,   q2,    r,    t,   v1,   v2,  rho, result, tol
                // data from http://www.maths.ox.ac.uk/~firth/computing/excel.shtml
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.90,  10.898, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.70,   8.483, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.50,   6.844, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30,   5.531, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.10,   4.413, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.50, 0.70, 0.00,   4.981, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.50, 0.30, 0.00,   4.159, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.50, 0.10, 0.00,   2.597, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.50, 0.10, 0.50,   4.030, 1.0e-3),

                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.90,  17.565, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.70,  19.980, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.50,  21.619, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30,  22.932, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.10,  24.049, 1.1e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0,  80.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30,  16.508, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0,  80.0,  80.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30,   8.049, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0,  80.0, 120.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30,  30.141, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call, 100.0, 120.0, 120.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30,  42.889, 1.0e-3),

                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.90,  11.369, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.70,  12.856, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.50,  13.890, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30,  14.741, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.10,  15.485, 1.0e-3),

                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 0.50, 0.30, 0.30, 0.10,  11.893, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 0.25, 0.30, 0.30, 0.10,   8.881, 1.0e-3),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 2.00, 0.30, 0.30, 0.10,  19.268, 1.0e-3),

                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.90,   7.339, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.70,   5.853, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.50,   4.818, 1.0e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30,   3.967, 1.1e-3),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Put,  100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.10,   3.223, 1.0e-3),

                //      basketType,   optionType, strike,    s1,    s2,   q1,   q2,    r,    t,   v1,   v2,  rho,  result, tol
                // data from "Option pricing formulas" VB code + spreadsheet
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call,  98.0, 100.0, 105.0, 0.00, 0.00, 0.05, 0.50, 0.11, 0.16, 0.63,  4.8177, 1.0e-4),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call,  98.0, 100.0, 105.0, 0.00, 0.00, 0.05, 0.50, 0.11, 0.16, 0.63, 11.6323, 1.0e-4),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,   98.0, 100.0, 105.0, 0.00, 0.00, 0.05, 0.50, 0.11, 0.16, 0.63,  2.0376, 1.0e-4),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Put,   98.0, 100.0, 105.0, 0.00, 0.00, 0.05, 0.50, 0.11, 0.16, 0.63,  0.5731, 1.0e-4),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Call,  98.0, 100.0, 105.0, 0.06, 0.09, 0.05, 0.50, 0.11, 0.16, 0.63,  2.9340, 1.0e-4),
                new BasketOptionTwoData(BasketType.MinBasket,    Option.Type.Put,   98.0, 100.0, 105.0, 0.06, 0.09, 0.05, 0.50, 0.11, 0.16, 0.63,  3.5224, 1.0e-4),
                // data from "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 58
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Call,  98.0, 100.0, 105.0, 0.06, 0.09, 0.05, 0.50, 0.11, 0.16, 0.63,  8.0701, 1.0e-4),
                new BasketOptionTwoData(BasketType.MaxBasket,    Option.Type.Put,   98.0, 100.0, 105.0, 0.06, 0.09, 0.05, 0.50, 0.11, 0.16, 0.63,  1.2181, 1.0e-4),

                /* "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 59-60
                 * Kirk approx. for a european spread option on two futures*/

                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.20, 0.20, -0.5,  4.7530, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.20, 0.20,  0.0,  3.7970, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.20, 0.20,  0.5,  2.5537, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.25, 0.20, -0.5,  5.4275, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.25, 0.20,  0.0,  4.3712, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.25, 0.20,  0.5,  3.0086, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.20, 0.25, -0.5,  5.4061, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.20, 0.25,  0.0,  4.3451, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.1, 0.20, 0.25,  0.5,  2.9723, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.20, 0.20, -0.5, 10.7517, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.20, 0.20,  0.0,  8.7020, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.20, 0.20,  0.5,  6.0257, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.25, 0.20, -0.5, 12.1941, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.25, 0.20,  0.0,  9.9340, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.25, 0.20,  0.5,  7.0067, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.20, 0.25, -0.5, 12.1483, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.20, 0.25,  0.0,  9.8780, 1.0e-3),
                new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call,   3.0, 122.0, 120.0,  0.0,  0.0, 0.10,  0.5, 0.20, 0.25,  0.5,  6.9284, 1.0e-3)
            };

            DayCounter dc = new Actual360();


            Date today = Date.Today;

            SimpleQuote spot1 = new SimpleQuote(0.0);
            SimpleQuote spot2 = new SimpleQuote(0.0);

            SimpleQuote        qRate1 = new SimpleQuote(0.0);
            YieldTermStructure qTS1   = Utilities.flatRate(today, qRate1, dc);
            SimpleQuote        qRate2 = new SimpleQuote(0.0);
            YieldTermStructure qTS2   = Utilities.flatRate(today, qRate2, dc);

            SimpleQuote        rRate = new SimpleQuote(0.0);
            YieldTermStructure rTS   = Utilities.flatRate(today, rRate, dc);

            SimpleQuote           vol1   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS1 = Utilities.flatVol(today, vol1, dc);
            SimpleQuote           vol2   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS2 = Utilities.flatVol(today, vol2, dc);

            //double mcRelativeErrorTolerance = 0.01;
            //double fdRelativeErrorTolerance = 0.01;

            for (int i = 0; i < values.Length; i++)
            {
                PlainVanillaPayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike);

                Date     exDate   = today + (int)(values[i].t * 360 + 0.5);
                Exercise exercise = new EuropeanExercise(exDate);

                spot1.setValue(values[i].s1);
                spot2.setValue(values[i].s2);
                qRate1.setValue(values[i].q1);
                qRate2.setValue(values[i].q2);
                rRate.setValue(values[i].r);
                vol1.setValue(values[i].v1);
                vol2.setValue(values[i].v2);


                IPricingEngine analyticEngine = null;
                GeneralizedBlackScholesProcess p1 = null, p2 = null;

                switch (values[i].basketType)
                {
                case BasketType.MaxBasket:
                case BasketType.MinBasket:
                    p1 = new BlackScholesMertonProcess(new Handle <Quote>(spot1),
                                                       new Handle <YieldTermStructure>(qTS1),
                                                       new Handle <YieldTermStructure>(rTS),
                                                       new Handle <BlackVolTermStructure>(volTS1));
                    p2 = new BlackScholesMertonProcess(new Handle <Quote>(spot2),
                                                       new Handle <YieldTermStructure>(qTS2),
                                                       new Handle <YieldTermStructure>(rTS),
                                                       new Handle <BlackVolTermStructure>(volTS2));
                    analyticEngine = new StulzEngine(p1, p2, values[i].rho);
                    break;

                case BasketType.SpreadBasket:
                    p1 = new BlackProcess(new Handle <Quote>(spot1),
                                          new Handle <YieldTermStructure>(rTS),
                                          new Handle <BlackVolTermStructure>(volTS1));
                    p2 = new BlackProcess(new Handle <Quote>(spot2),
                                          new Handle <YieldTermStructure>(rTS),
                                          new Handle <BlackVolTermStructure>(volTS2));

                    analyticEngine = new KirkEngine((BlackProcess)p1, (BlackProcess)p2, values[i].rho);
                    break;

                default:
                    Utils.QL_FAIL("unknown basket type");
                    break;
                }


                List <StochasticProcess1D> procs = new List <StochasticProcess1D> {
                    p1, p2
                };

                Matrix correlationMatrix = new Matrix(2, 2, values[i].rho);
                for (int j = 0; j < 2; j++)
                {
                    correlationMatrix[j, j] = 1.0;
                }

                StochasticProcessArray process = new StochasticProcessArray(procs, correlationMatrix);

                //IPricingEngine mcEngine = MakeMCEuropeanBasketEngine<PseudoRandom, Statistics>(process)
                //                           .withStepsPerYear(1)
                //                           .withSamples(10000)
                //                           .withSeed(42);



                //IPricingEngine fdEngine = new Fd2dBlackScholesVanillaEngine(p1, p2, values[i].rho, 50, 50, 15);

                BasketOption basketOption = new BasketOption(basketTypeToPayoff(values[i].basketType, payoff), exercise);

                // analytic engine
                basketOption.setPricingEngine(analyticEngine);
                double calculated = basketOption.NPV();
                double expected   = values[i].result;
                double error      = Math.Abs(calculated - expected);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE_2("value", values[i].basketType, payoff, exercise,
                                     values[i].s1, values[i].s2, values[i].q1,
                                     values[i].q2, values[i].r, today, values[i].v1,
                                     values[i].v2, values[i].rho, values[i].result,
                                     calculated, error, values[i].tol);
                }

                // // fd engine
                // basketOption.setPricingEngine(fdEngine);
                // calculated = basketOption.NPV();
                // double relError = relativeError(calculated, expected, expected);
                // if (relError > mcRelativeErrorTolerance )
                // {
                //    REPORT_FAILURE_2("FD value", values[i].basketType, payoff,
                //                      exercise, values[i].s1, values[i].s2,
                //                      values[i].q1, values[i].q2, values[i].r,
                //                      today, values[i].v1, values[i].v2, values[i].rho,
                //                      values[i].result, calculated, relError,
                //                      fdRelativeErrorTolerance);
                // }

                //// mc engine
                //basketOption.setPricingEngine(mcEngine);
                //calculated = basketOption.NPV();
                //relError = relativeError(calculated, expected, values[i].s1);
                //if (relError > mcRelativeErrorTolerance )
                //{
                //    REPORT_FAILURE_2("MC value", values[i].basketType, payoff,
                //                     exercise, values[i].s1, values[i].s2,
                //                     values[i].q1, values[i].q2, values[i].r,
                //                     today, values[i].v1, values[i].v2, values[i].rho,
                //                     values[i].result, calculated, relError,
                //                     mcRelativeErrorTolerance);
                //}
            }
        }
Exemple #20
0
        public void testFdGreeks <Engine>() where Engine : IFDEngine, new()
        {
            using (SavedSettings backup = new SavedSettings())
            {
                Dictionary <string, double> calculated = new Dictionary <string, double>(),
                                            expected   = new Dictionary <string, double>(),
                                            tolerance  = new Dictionary <string, double>();

                tolerance.Add("delta", 7.0e-4);
                tolerance.Add("gamma", 2.0e-4);
                //tolerance["theta"]  = 1.0e-4;

                Option.Type[] types       = new Option.Type[] { Option.Type.Call, Option.Type.Put };
                double[]      strikes     = { 50.0, 99.5, 100.0, 100.5, 150.0 };
                double[]      underlyings = { 100.0 };
                double[]      qRates      = { 0.04, 0.05, 0.06 };
                double[]      rRates      = { 0.01, 0.05, 0.15 };
                int[]         years       = { 1, 2 };
                double[]      vols        = { 0.11, 0.50, 1.20 };

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

                DayCounter         dc    = new Actual360();
                SimpleQuote        spot  = new SimpleQuote(0.0);
                SimpleQuote        qRate = new SimpleQuote(0.0);
                YieldTermStructure qTS   = Utilities.flatRate(today, qRate, dc);

                SimpleQuote           rRate = new SimpleQuote(0.0);
                YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
                SimpleQuote           vol   = new SimpleQuote(0.0);
                BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

                for (int i = 0; i < types.Length; i++)
                {
                    for (int j = 0; j < strikes.Length; j++)
                    {
                        for (int k = 0; k < years.Length; k++)
                        {
                            Date                      exDate       = today + new Period(years[k], TimeUnit.Years);
                            Exercise                  exercise     = new AmericanExercise(today, exDate);
                            StrikedTypePayoff         payoff       = new PlainVanillaPayoff(types[i], strikes[j]);
                            BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                                   new Handle <YieldTermStructure>(qTS),
                                                                                                   new Handle <YieldTermStructure>(rTS),
                                                                                                   new Handle <BlackVolTermStructure>(volTS));

                            IPricingEngine engine = new Engine().factory(stochProcess);

                            VanillaOption option = new VanillaOption(payoff, exercise);
                            option.setPricingEngine(engine);

                            for (int l = 0; l < underlyings.Length; l++)
                            {
                                for (int m = 0; m < qRates.Length; m++)
                                {
                                    for (int n = 0; n < rRates.Length; n++)
                                    {
                                        for (int p = 0; p < vols.Length; p++)
                                        {
                                            double u = underlyings[l];
                                            double q = qRates[m],
                                                   r = rRates[n];
                                            double v = vols[p];
                                            spot.setValue(u);
                                            qRate.setValue(q);
                                            rRate.setValue(r);
                                            vol.setValue(v);

                                            double value = option.NPV();
                                            calculated.Add("delta", option.delta());
                                            calculated.Add("gamma", option.gamma());
                                            //calculated["theta"]  = option.theta();

                                            if (value > spot.value() * 1.0e-5)
                                            {
                                                // perturb spot and get delta and gamma
                                                double du = u * 1.0e-4;
                                                spot.setValue(u + du);
                                                double value_p = option.NPV(),
                                                       delta_p = option.delta();
                                                spot.setValue(u - du);
                                                double value_m = option.NPV(),
                                                       delta_m = option.delta();
                                                spot.setValue(u);
                                                expected.Add("delta", (value_p - value_m) / (2 * du));
                                                expected.Add("gamma", (delta_p - delta_m) / (2 * du));

                                                /*
                                                 * // perturb date and get theta
                                                 * Time dT = dc.yearFraction(today-1, today+1);
                                                 * Settings::instance().setEvaluationDate(today-1);
                                                 * value_m = option.NPV();
                                                 * Settings::instance().setEvaluationDate(today+1);
                                                 * value_p = option.NPV();
                                                 * Settings::instance().setEvaluationDate(today);
                                                 * expected["theta"] = (value_p - value_m)/dT;
                                                 */

                                                // compare
                                                foreach (string greek in calculated.Keys)
                                                {
                                                    double expct      = expected[greek],
                                                                calcl = calculated[greek],
                                                                tol   = tolerance[greek];
                                                    double error      = Utilities.relativeError(expct, calcl, u);
                                                    if (error > tol)
                                                    {
                                                        REPORT_FAILURE(greek, payoff, exercise,
                                                                       u, q, r, today, v,
                                                                       expct, calcl, error, tol);
                                                    }
                                                }
                                            }
                                            calculated.Clear();
                                            expected.Clear();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Exemple #21
0
        public void testAnalyticContinuousFloatingLookback()
        {
            // Testing analytic continuous floating-strike lookback options
            LookbackOptionData[] values =
            {
                // data from "Option Pricing Formulas", Haug, 1998, pg.61-62
                new LookbackOptionData(Option.Type.Call, 0, 100, 120.0, 0.06, 0.10, 0.50, 0.30, 0, 0, 25.3533, 1.0e-4),
                // data from "Connecting discrete and continuous path-dependent options",
                // Broadie, Glasserman & Kou, 1999, pg.70-74
                new LookbackOptionData(Option.Type.Call, 0, 100, 100.0, 0.00, 0.05, 1.00, 0.30, 0, 0, 23.7884, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 100, 100.0, 0.00, 0.05, 0.20, 0.30, 0, 0, 10.7190, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 100, 110.0, 0.00, 0.05, 0.20, 0.30, 0, 0, 14.4597, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 15.3526, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 16.8468, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 120, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 21.0645, 1.0e-4),
            };

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

            SimpleQuote           spot  = new SimpleQuote(0.0);
            SimpleQuote           qRate = new SimpleQuote(0.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                Date     exDate   = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise exercise = new EuropeanExercise(exDate);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                FloatingTypePayoff payoff = new FloatingTypePayoff(values[i].type);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new AnalyticContinuousFloatingLookbackEngine(stochProcess);

                ContinuousFloatingLookbackOption option = new ContinuousFloatingLookbackOption(values[i].minmax,
                                                                                               payoff,
                                                                                               exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double expected   = values[i].result;
                double error      = Math.Abs(calculated - expected);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE_FLOATING("value", values[i].minmax, payoff,
                                            exercise, values[i].s, values[i].q,
                                            values[i].r, today, values[i].v,
                                            expected, calculated, error,
                                            values[i].tol);
                }
            }
        }
Exemple #22
0
        public void testCashAtExpiryOrNothingAmericanValues()
        {
            // Testing American cash-(at-expiry)-or-nothing digital option

            DigitalOptionData[] values =
            {
                //        type, strike,   spot,    q,    r,   t,  vol,   value, tol
                // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 95, case 5,6,9,10
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.00, 0.10,  0.5,  0.20,                    9.3604,  1e-4, true),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.00, 0.10,  0.5,  0.20,                   11.2223,  1e-4, true),
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.00, 0.10,  0.5,  0.20,                    4.9081,  1e-4, false),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.00, 0.10,  0.5,  0.20,                    3.0461,  1e-4, false),
                // in the money options (guaranteed discounted payoff)
                new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.00, 0.10,  0.5,  0.20, 15.0000 * Math.Exp(-0.05), 1e-12, true),
                new DigitalOptionData(Option.Type.Put,  100.00,  95.00, 0.00, 0.10,  0.5,  0.20, 15.0000 * Math.Exp(-0.05), 1e-12, true),
                // out of bonds case
                new DigitalOptionData(Option.Type.Call,   2.37,   2.33, 0.07, 0.43, 0.19, 0.005,                    0.0000,  1e-4, false),
            };

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

            SimpleQuote           spot  = new SimpleQuote(100.0);
            SimpleQuote           qRate = new SimpleQuote(0.04);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.01);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.25);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new CashOrNothingPayoff(values[i].type, values[i].strike, 15.0);

                Date     exDate     = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise amExercise = new AmericanExercise(today, exDate, true);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                       new Handle <YieldTermStructure>(qTS),
                                                                                       new Handle <YieldTermStructure>(rTS),
                                                                                       new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine;
                if (values[i].knockin)
                {
                    engine = new AnalyticDigitalAmericanEngine(stochProcess);
                }
                else
                {
                    engine = new AnalyticDigitalAmericanKOEngine(stochProcess);
                }

                VanillaOption opt = new VanillaOption(payoff, amExercise);
                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, amExercise, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol, values[i].knockin);
                }
            }
        }
Exemple #23
0
        public void testAnalyticContinuousFixedLookback()
        {
            // Testing analytic continuous fixed-strike lookback options
            LookbackOptionData[] values =
            {
                // data from "Option Pricing Formulas", Haug, 1998, pg.63-64
                //type,            strike, minmax,  s,     q,    r,    t,    v,    l, t1, result,  tol
                new LookbackOptionData(Option.Type.Call,  95, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0, 13.2687, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  95, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 18.9263, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  95, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 24.9857, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0,  8.5126, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 14.1702, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 20.2296, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0,  4.3908, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0,  9.8905, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 15.8512, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  95, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0, 18.3241, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  95, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 26.0731, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  95, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 34.7116, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0, 13.8000, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 21.5489, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 30.1874, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0,  9.5445, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 17.2965, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 25.9002, 1.0e-4),

                new LookbackOptionData(Option.Type.Put,   95, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0,  0.6899, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   95, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0,  4.4448, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   95, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0,  8.9213, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  100, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0,  3.3917, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  100, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0,  8.3177, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  100, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 13.1579, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  105, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0,  8.1478, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  105, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 13.0739, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  105, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 17.9140, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   95, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0,  1.0534, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   95, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0,  6.2813, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   95, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 12.2376, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  100, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0,  3.8079, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  100, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 10.1294, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  100, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 16.3889, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  105, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0,  8.3321, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  105, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 14.6536, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  105, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 20.9130, 1.0e-4)
            };

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

            SimpleQuote           spot  = new SimpleQuote(0.0);
            SimpleQuote           qRate = new SimpleQuote(0.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                Date     exDate   = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise exercise = new EuropeanExercise(exDate);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new AnalyticContinuousFixedLookbackEngine(stochProcess);

                ContinuousFixedLookbackOption option = new ContinuousFixedLookbackOption(values[i].minmax,
                                                                                         payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double expected   = values[i].result;
                double error      = Math.Abs(calculated - expected);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE_FIXED("value", values[i].minmax, payoff, exercise,
                                         values[i].s, values[i].q, values[i].r, today,
                                         values[i].v, expected, calculated, error,
                                         values[i].tol);
                }
            }
        }
Exemple #24
0
        public void testAssetOrNothingHaugValues()
        {
            // Testing asset-or-nothing barrier options against Haug's values

            BinaryOptionData[] values =
            {
                /* The data below are from
                 * "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 180 - cases 15,16,19,20,23,24,27,28
                 * Note:
                 * q is the dividend rate, while the book gives b, the cost of carry (q=r-b)
                 */
                //    barrierType, barrier,  cash,         type, strike,   spot,    q,    r,   t,  vol,   value, tol
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 0.00, Option.Type.Call, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 37.2782, 1e-4),
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 0.00, Option.Type.Call,  98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 45.8530, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 0.00, Option.Type.Call, 102.00,  95.00, 0.00, 0.10, 0.5, 0.20, 44.5294, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 0.00, Option.Type.Call,  98.00,  95.00, 0.00, 0.10, 0.5, 0.20, 54.9262, 1e-4),
                // 19,20
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 0.00, Option.Type.Put,  102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 27.5644, 1e-4),
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 0.00, Option.Type.Put,   98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 18.9896, 1e-4),
                // following value is wrong in book.
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 0.00, Option.Type.Put,  102.00,  95.00, 0.00, 0.10, 0.5, 0.20, 33.1723, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 0.00, Option.Type.Put,   98.00,  95.00, 0.00, 0.10, 0.5, 0.20, 22.7755, 1e-4),
                // 23,24
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Call, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 39.9391, 1e-4),
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Call,  98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 40.1574, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 0.00, Option.Type.Call, 102.00,  95.00, 0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 0.00, Option.Type.Call,  98.00,  95.00, 0.00, 0.10, 0.5, 0.20,  0.2676, 1e-4),
                // 27,28
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Put,  102.00, 105.00, 0.00, 0.10, 0.5, 0.20,  0.2183, 1e-4),
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Put,   98.00, 105.00, 0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 0.00, Option.Type.Put,  102.00,  95.00, 0.00, 0.10, 0.5, 0.20, 17.2983, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 0.00, Option.Type.Put,   98.00,  95.00, 0.00, 0.10, 0.5, 0.20, 17.0306, 1e-4),
            };

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

            SimpleQuote           spot  = new SimpleQuote(100.0);
            SimpleQuote           qRate = new SimpleQuote(0.04);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.01);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.25);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new AssetOrNothingPayoff(values[i].type, values[i].strike);
                Date     exDate          = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise amExercise      = new AmericanExercise(today, exDate, true);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new AnalyticBinaryBarrierEngine(stochProcess);

                BarrierOption opt = new BarrierOption(values[i].barrierType, values[i].barrier, 0, payoff, amExercise);

                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, amExercise, values[i].barrierType,
                                   values[i].barrier, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol);
                }
            }
        }
Exemple #25
0
        public void testAnalyticContinuousPartialFloatingLookback()
        {
            // Testing analytic continuous partial floating-strike lookback options...");
            LookbackOptionData[] values =
            {
                // data from "Option Pricing Formulas, Second Edition", Haug, 2006, pg.146

                //type,         strike, minmax, s,    q,    r,    t,    v,    l,  t1,     result,   tol
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.1, 1, 0.25,  8.6524, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.1, 1,  0.5,  9.2128, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.1, 1, 0.75,  9.5567, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.25, 10.5751, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.1, 1,  0.5, 11.2601, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.75, 11.6804, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.2, 1, 0.25, 13.3402, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.2, 1,  0.5, 14.5121, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.2, 1, 0.75,  15.314, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.25, 16.3047, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.2, 1,  0.5,  17.737, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.75, 18.7171, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.3, 1, 0.25, 17.9831, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.3, 1,  0.5, 19.6618, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0,  90,  90, 0, 0.06, 1, 0.3, 1, 0.75, 20.8493, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.25, 21.9793, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.3, 1,  0.5, 24.0311, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.75, 25.4825, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.1, 1, 0.25,  2.7189, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.1, 1,  0.5,  3.4639, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.1, 1, 0.75,  4.1912, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.25,  3.3231, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.1, 1,  0.5,  4.2336, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.75,  5.1226, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.2, 1, 0.25,  7.9153, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.2, 1,  0.5,  9.5825, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.2, 1, 0.75, 11.0362, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.25,  9.6743, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.2, 1,  0.5, 11.7119, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.75, 13.4887, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.3, 1, 0.25, 13.4719, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.3, 1,  0.5, 16.1495, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0,  90,  90, 0, 0.06, 1, 0.3, 1, 0.75, 18.4071, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.25, 16.4657, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.3, 1,  0.5, 19.7383, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.75, 22.4976, 1.0e-4)
            };

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

            SimpleQuote           spot  = new SimpleQuote(0.0);
            SimpleQuote           qRate = new SimpleQuote(0.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                Date     exDate   = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise exercise = new EuropeanExercise(exDate);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                FloatingTypePayoff payoff = new FloatingTypePayoff(values[i].type);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new AnalyticContinuousPartialFloatingLookbackEngine(stochProcess);

                Date lookbackEnd = today + Convert.ToInt32(values[i].t1 * 360 + 0.5);
                ContinuousPartialFloatingLookbackOption option = new ContinuousPartialFloatingLookbackOption(
                    values[i].minmax, values[i].l, lookbackEnd, payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double expected   = values[i].result;
                double error      = Math.Abs(calculated - expected);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE_FLOATING("value", values[i].minmax, payoff,
                                            exercise, values[i].s, values[i].q,
                                            values[i].r, today, values[i].v,
                                            expected, calculated, error,
                                            values[i].tol);
                }
            }
        }
Exemple #26
0
        public void testEuropeanHaugValues()
        {
            // Testing double barrier european options against Haug's values

            Exercise.Type          european = Exercise.Type.European;
            NewBarrierOptionData[] values   =
            {
                /* The data below are from
                 * "The complete guide to option pricing formulas 2nd Ed",E.G. Haug, McGraw-Hill, p.156 and following.
                 *
                 * Note:
                 * The book uses b instead of q (q=r-b)
                 */
                //           BarrierType, barr.lo,  barr.hi,         type, exercise,strk,     s,   q,   r,    t,    v,  result, tol
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  4.3515, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  6.1644, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  7.0373, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  6.9853, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  7.9336, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  6.5088, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  4.3505, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  5.8500, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  5.7726, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  6.8082, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  6.3383, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  4.3841, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  4.3139, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  4.8293, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  3.7765, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  5.9697, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  4.0004, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  2.2563, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  3.7516, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  2.6387, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  1.4903, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  3.5805, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  1.5098, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  0.5635, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  1.2055, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  0.3098, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  0.0477, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  0.5537, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  0.0441, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  0.0011, 1.0e-4),

                //           BarrierType, barr.lo,  barr.hi,         type, exercise,strk,     s,   q,   r,    t,    v,  result, tol
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  1.8825, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  3.7855, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  5.7191, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  2.1374, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  4.7033, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  7.1683, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  1.8825, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  3.7845, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  5.6060, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  2.1374, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  4.6236, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  6.1062, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  1.8825, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  3.7014, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  4.6472, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  2.1325, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  3.8944, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  3.5868, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  1.8600, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  2.6866, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  2.0719, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  1.8883, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  1.7851, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  0.8244, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  0.9473, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  0.3449, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  0.0578, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  0.4555, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  0.0491, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put,  european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  0.0013, 1.0e-4),

                //           BarrierType, barr.lo,  barr.hi,         type,  strk,     s,   q,   r,    t,    v,  result, tol
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  0.0000, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  0.0900, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  1.1537, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  0.0292, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  1.6487, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  5.7321, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  0.0010, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  0.4045, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  2.4184, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  0.2062, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  3.2439, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  7.8569, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  0.0376, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  1.4252, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  4.4145, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  1.0447, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  5.5818, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35,  9.9846, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  0.5999, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  3.6158, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  6.7007, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  3.4340, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  8.0724, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 11.6774, 1.0e-4),

                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15,  3.1460, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25,  5.9447, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35,  8.1432, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15,  6.4608, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25,  9.5382, 1.0e-4),
                new NewBarrierOptionData(DoubleBarrier.Type.KnockIn,  90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 12.2398, 1.0e-4),
            };

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

            SimpleQuote           spot  = new SimpleQuote(0.0);
            SimpleQuote           qRate = new SimpleQuote(0.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                Date     exDate   = today + (int)(values[i].t * 360 + 0.5);
                Exercise exercise = new EuropeanExercise(exDate);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

                DoubleBarrierOption opt = new DoubleBarrierOption(values[i].barrierType, values[i].barrierlo,
                                                                  values[i].barrierhi, 0, // no rebate
                                                                  payoff, exercise);

                // Ikeda/Kunitomo engine
                IPricingEngine engine = new AnalyticDoubleBarrierEngine(stochProcess);
                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double expected   = values[i].result;
                double error      = Math.Abs(calculated - expected);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("Ikeda/Kunitomo value", values[i].barrierType, values[i].barrierlo,
                                   values[i].barrierhi, payoff, exercise, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   expected, calculated, error, values[i].tol);
                }

                // Wulin Suo/Yong Wang engine
                engine = new WulinYongDoubleBarrierEngine(stochProcess);
                opt.setPricingEngine(engine);

                calculated = opt.NPV();
                expected   = values[i].result;
                error      = Math.Abs(calculated - expected);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("Wulin/Yong value", values[i].barrierType, values[i].barrierlo,
                                   values[i].barrierhi, payoff, exercise, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   expected, calculated, error, values[i].tol);
                }
            }
        }
Exemple #27
0
        public void testAnalyticContinuousPartialFixedLookback()
        {
            // Testing analytic continuous fixed-strike lookback options
            LookbackOptionData[] values =
            {
                // data from "Option Pricing Formulas, Second Edition", Haug, 2006, pg.148
                //type,         strike, minmax, s,    q,    r,    t,    v, l,   t1,  result,   tol
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.25, 20.2845, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.1, 0,  0.5, 19.6239, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.75, 18.6244, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.25,  4.0432, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.1, 0,  0.5,   3.958, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.75,  3.7015, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.25, 27.5385, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.2, 0,  0.5, 25.8126, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.75, 23.4957, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.25, 11.4895, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.2, 0,  0.5, 10.8995, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.75,  9.8244, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.25, 35.4578, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.3, 0,  0.5, 32.7172, 1.0e-4),
                new LookbackOptionData(Option.Type.Call,  90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.75, 29.1473, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.25,  19.725, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.3, 0,  0.5, 18.4025, 1.0e-4),
                new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.75, 16.2976, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.25,  0.4973, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.1, 0,  0.5,  0.4632, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.75,  0.3863, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.25, 12.6978, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.1, 0,  0.5, 10.9492, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.75,  9.1555, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.25,  4.5863, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.2, 0,  0.5,  4.1925, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.75,  3.5831, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.25, 19.0255, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.2, 0,  0.5, 16.9433, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.75, 14.6505, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.25,  9.9348, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.3, 0,  0.5,  9.1111, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,   90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.75,  7.9267, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.25, 25.2112, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.3, 0,  0.5, 22.8217, 1.0e-4),
                new LookbackOptionData(Option.Type.Put,  110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.75, 20.0566, 1.0e-4)
            };

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

            SimpleQuote           spot  = new SimpleQuote(0.0);
            SimpleQuote           qRate = new SimpleQuote(0.0);
            YieldTermStructure    qTS   = Utilities.flatRate(today, qRate, dc);
            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < values.Length; i++)
            {
                Date     exDate   = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise exercise = new EuropeanExercise(exDate);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike);

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(
                    new Handle <Quote>(spot),
                    new Handle <YieldTermStructure>(qTS),
                    new Handle <YieldTermStructure>(rTS),
                    new Handle <BlackVolTermStructure>(volTS));

                IPricingEngine engine = new AnalyticContinuousPartialFixedLookbackEngine(stochProcess);

                Date lookbackStart = today + Convert.ToInt32(values[i].t1 * 360 + 0.5);
                ContinuousPartialFixedLookbackOption option = new ContinuousPartialFixedLookbackOption(lookbackStart,
                                                                                                       payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double expected   = values[i].result;
                double error      = Math.Abs(calculated - expected);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE_FIXED("value", values[i].minmax, payoff, exercise,
                                         values[i].s, values[i].q, values[i].r, today,
                                         values[i].v, expected, calculated, error,
                                         values[i].tol);
                }
            }
        }
Exemple #28
0
 public RelinkableBlackVolTermStructureHandle(BlackVolTermStructure arg0) : this(NQuantLibcPINVOKE.new_RelinkableBlackVolTermStructureHandle__SWIG_0(BlackVolTermStructure.getCPtr(arg0)), true)
 {
     if (NQuantLibcPINVOKE.SWIGPendingException.Pending)
     {
         throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve();
     }
 }
Exemple #29
0
        //! Detailed constructor
        public FXVolCurve(Date asof, FXVolatilityCurveSpec spec, Loader loader, CurveConfigurations curveConfigs,
                          Dictionary <string, FXSpot> fxSpots,
                          Dictionary <string, YieldCurve> yieldCurves)
        {
            try
            {
                FXVolatilityCurveConfig config = curveConfigs.FxVolCurveConfig(spec.CurveConfigID());

                Utils.QL_REQUIRE(config.GetDimension() == FXVolatilityCurveConfig.Dimension.ATM ||
                                 config.GetDimension() == FXVolatilityCurveConfig.Dimension.Smile,
                                 () => "Unkown FX curve building dimension");

                bool isATM = config.GetDimension() == FXVolatilityCurveConfig.Dimension.ATM;

                // We loop over all market data, looking for quotes that match the configuration
                // every time we find a matching expiry we remove it from the list
                // we replicate this for all 3 types of quotes were applicable.
                int n = isATM ? 1 : 3; // [0] = ATM, [1] = RR, [2] = BF
                List <List <FXOptionQuote> > quotes   = new List <List <FXOptionQuote> >(n);
                List <List <Period> >        expiries = new InitializedList <List <Period> >(n, config.Expiries());
                foreach (var md in loader.LoadQuotes(asof))
                {
                    // skip irrelevant data
                    if (md.AsofDate() == asof && md.GetInstrumentType() == MarketDatum.InstrumentType.FX_OPTION)
                    {
                        FXOptionQuote q = md as FXOptionQuote;

                        if (q.UnitCcy() == spec.UnitCcy() && q.Ccy() == spec.Ccy())
                        {
                            int idx = 999999;
                            if (q.Strike() == "ATM")
                            {
                                idx = 0;
                            }
                            else if (q.Strike() == "25RR")
                            {
                                idx = 1;
                            }
                            else if (q.Strike() == "25BF")
                            {
                                idx = 2;
                            }

                            // silently skip unknown strike strings
                            if ((isATM && idx == 0) || (!isATM && idx <= 2))
                            {
                                if (expiries[idx].Contains(q.Expiry()))
                                //var it = std::find(expiries[idx].begin(), expiries[idx].end(), q->expiry());
                                //if (it != expiries[idx].end())
                                {
                                    // we have a hit
                                    quotes[idx].Add(q);
                                    // remove it from the list
                                    expiries[idx].Remove(q.Expiry());
                                }

                                // check if we are done
                                // for ATM we just check expiries[0], otherwise we check all 3
                                if (expiries[0].empty() && (isATM || (expiries[1].empty() && expiries[2].empty())))
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                // Check ATM first
                // Check that we have all the expiries we need
                //LOG("FXVolCurve: read " + quotes[0].Count + " ATM vols");
                Utils.QL_REQUIRE(expiries[0].Count == 0, () => "No ATM quote found for spec " + spec + " with expiry " + expiries[0].First());
                Utils.QL_REQUIRE(quotes[0].Count > 0, () => "No ATM quotes found for spec " + spec);
                // No check the rest
                if (!isATM)
                {
                    //LOG("FXVolCurve: read " + quotes[1].Count + " RR and " + quotes[2].Count + " BF quotes");
                    Utils.QL_REQUIRE(expiries[1].Count == 0, () => "No RR quote found for spec " + spec + " with expiry " + expiries[1].First());
                    Utils.QL_REQUIRE(expiries[2].Count == 0, () => "No BF quote found for spec " + spec + " with expiry " + expiries[2].First());
                }

                // daycounter used for interpolation in time.
                // TODO: push into conventions or config
                DayCounter dc  = config.DayCounter();
                Calendar   cal = config.Calendar();

                // sort all quotes
                for (int i = 0; i < n; i++)
                {
                    // TODO!!
                    //IComparer<FXOptionQuote> compare =
                    //quotes[i] = quotes[i].Sort((a,b) => a.Expiry().CompareTo(b.Expiry()))
                }

                // build vol curve
                if (isATM && quotes[0].Count == 1)
                {
                    _vol = new BlackConstantVol(asof, new Calendar(), quotes[0].First().Quote().link.value(), dc);
                }
                else
                {
                    int                   numExpiries = quotes[0].Count;
                    List <Date>           dates       = new List <Date>(numExpiries);
                    List <List <double> > vols        = new InitializedList <List <double> >(n, new List <double>(numExpiries)); // same as above: [0] = ATM, etc.

                    for (int i = 0; i < numExpiries; i++)
                    {
                        dates[i] = asof + quotes[0][i].Expiry();
                        for (int idx = 0; idx < n; idx++)
                        {
                            vols[idx][i] = quotes[idx][i].Quote().link.value();
                        }
                    }

                    if (isATM)
                    {
                        // ATM
                        _vol = new BlackVarianceCurve(asof, dates, vols[0], dc, false);
                    }
                    else
                    {
                        // Smile
                        if (fxSpots.ContainsKey(config.FxSpotID()) && yieldCurves.ContainsKey(config.FxDomesticYieldCurveID()) && yieldCurves.ContainsKey(config.FxForeignYieldCurveID()))
                        {
                            var fxSpot = fxSpots[config.FxSpotID()]; // new Handle<Quote>(config.FxSpotID(), fxSpots);
                            var domYTS = yieldCurves[config.FxDomesticYieldCurveID()];
                            var forYTS = yieldCurves[config.FxForeignYieldCurveID()];

                            // TODO!!
                            //_vol = new QuantExt.FxBlackVannaVolgaVolatilitySurface(asof, dates, vols[0], vols[1], vols[2], dc, cal, fxSpot, domYTS, forYTS));
                        }
                        else
                        {
                            Utils.QL_FAIL("FXVolCurve: Can't find spec " + spec);
                        }
                    }
                }
                _vol.enableExtrapolation();
            }
            catch (Exception e)
            {
                Utils.QL_FAIL("fx vol curve building failed :" + e.Message);
            }
        }