// utilities
            public void makeObservabilityTest(string description,
                                              SwaptionVolatilityStructure vol,
                                              bool mktDataFloating,
                                              bool referenceDateFloating)
            {
                double dummyStrike   = .02;
                Date   referenceDate = Settings.evaluationDate();
                double initialVol    = vol.volatility(
                    referenceDate + atm.tenors.options[0],
                    atm.tenors.swaps[0], dummyStrike, false);

                // testing evaluation date change ...
                Settings.setEvaluationDate(referenceDate - new Period(1, TimeUnit.Years));
                double newVol = vol.volatility(
                    referenceDate + atm.tenors.options[0],
                    atm.tenors.swaps[0], dummyStrike, false);

                Settings.setEvaluationDate(referenceDate);
                if (referenceDateFloating && (initialVol == newVol))
                {
                    Assert.Fail(description +
                                " the volatility should change when the reference date is changed !");
                }
                if (!referenceDateFloating && (initialVol != newVol))
                {
                    Assert.Fail(description +
                                " the volatility should not change when the reference date is changed !");
                }

                // test market data change...
                if (mktDataFloating)
                {
                    double initialVolatility = atm.volsHandle[0][0].link.value();

                    SimpleQuote sq = (SimpleQuote)(atm.volsHandle[0][0].currentLink());
                    sq.setValue(10);

                    newVol = vol.volatility(referenceDate + atm.tenors.options[0],
                                            atm.tenors.swaps[0], dummyStrike, false);
                    sq.setValue(initialVolatility);

                    if (initialVol == newVol)
                    {
                        Assert.Fail(description + " the volatility should change when" +
                                    " the market data is changed !");
                    }
                }
            }
Exemple #2
0
        public void testFSpreadedObs()
        {
            // ("Testing observability of forward-spreaded term structure...");

            CommonVars vars = new CommonVars();

            SimpleQuote    me = new SimpleQuote(0.01);
            Handle <Quote> mh = new Handle <Quote>(me);
            RelinkableHandle <YieldTermStructure> h = new RelinkableHandle <YieldTermStructure>(); //(vars.dummyTermStructure);
            YieldTermStructure spreaded             = new ForwardSpreadedTermStructure(h, mh);
            Flag flag = new Flag();

            spreaded.registerWith(flag.update);
            h.linkTo(vars.termStructure);
            if (!flag.isUp())
            {
                Console.WriteLine("Observer was not notified of term structure change");
            }
            flag.lower();
            me.setValue(0.005);
            if (!flag.isUp())
            {
                Console.WriteLine("Observer was not notified of spread change");
            }
        }
Exemple #3
0
        public void testZSpreadedObs()
        {
            // Testing observability of zero-spreaded term structure
            CommonVars vars = new CommonVars();

            SimpleQuote    me = new SimpleQuote(0.01);
            Handle <Quote> mh = new Handle <Quote>(me);
            RelinkableHandle <YieldTermStructure> h = new RelinkableHandle <YieldTermStructure>(vars.dummyTermStructure);

            YieldTermStructure spreaded = new ZeroSpreadedTermStructure(h, mh);
            Flag flag = new Flag();

            spreaded.registerWith(flag.update);
            h.linkTo(vars.termStructure);
            if (!flag.isUp())
            {
                QAssert.Fail("Observer was not notified of term structure change");
            }
            flag.lower();
            me.setValue(0.005);
            if (!flag.isUp())
            {
                QAssert.Fail("Observer was not notified of spread change");
            }
        }
Exemple #4
0
        // Reference pg. 253 - Hull - Options, Futures, and Other Derivatives 5th ed
        // Exercise 12.8
        // Doesn't quite work.  Need to deal with date conventions
        private void testEuropeanKnownValue()
        {
            // Testing dividend European option values with known value...
            using (SavedSettings backup = new SavedSettings())
            {
                double tolerance = 1.0e-2;
                double expected  = 3.67;

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

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

                Date     exDate   = today + new Period(6, TimeUnit.Months);
                Exercise exercise = new EuropeanExercise(exDate);

                List <Date>   dividendDates = new List <Date>();
                List <double> dividends     = new List <double>();
                dividendDates.Add(today + new Period(2, TimeUnit.Months));
                dividends.Add(0.50);
                dividendDates.Add(today + new Period(5, TimeUnit.Months));
                dividends.Add(0.50);

                StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, 40.0);

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

                IPricingEngine engine = new AnalyticDividendEuropeanEngine(stochProcess);

                DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends);
                option.setPricingEngine(engine);

                double u = 40.0;
                double q = 0.0, r = 0.09;
                double v = 0.30;
                spot.setValue(u);
                qRate.setValue(q);
                rRate.setValue(r);
                vol.setValue(v);

                double calculated = option.NPV();
                double error      = Math.Abs(calculated - expected);
                if (error > tolerance)
                {
                    REPORT_FAILURE("value start limit",
                                   payoff, exercise,
                                   u, q, r, today, v,
                                   expected, calculated,
                                   error, tolerance);
                }
            }
        }
Exemple #5
0
        public void testObservableHandle()
        {
            // Testing observability of quote handles

            SimpleQuote me1            = new SimpleQuote(0.0);
            RelinkableHandle <Quote> h = new RelinkableHandle <Quote>(me1);

            Flag f = new Flag();

            h.registerWith(f.update);

            me1.setValue(3.14);

            if (!f.isUp())
            {
                QAssert.Fail("Observer was not notified of quote change");
            }

            f.lower();
            SimpleQuote me2 = new SimpleQuote(0.0);

            h.linkTo(me2);

            if (!f.isUp())
            {
                QAssert.Fail("Observer was not notified of quote change");
            }
        }
Exemple #6
0
        public void testPerformanceValues()
        {
            // Testing forward performance option values...

            /* The data below are the performance equivalent of the
             * forward options tested above and taken from
             * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998
             */
            ForwardOptionData[] values =
            {
                //  type, moneyness, spot,  div, rate,start, maturity,  vol,                       result, tol
                new ForwardOptionData(Option.Type.Call, 1.1, 60.0, 0.04, 0.08, 0.25, 1.0, 0.30, 4.4064 / 60 * Math.Exp(-0.04 * 0.25), 1.0e-4),
                new ForwardOptionData(Option.Type.Put,  1.1, 60.0, 0.04, 0.08, 0.25, 1.0, 0.30, 8.2971 / 60 * Math.Exp(-0.04 * 0.25), 1.0e-4)
            };

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

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

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

            IPricingEngine engine = new ForwardPerformanceVanillaEngine(stochProcess, process => new AnalyticEuropeanEngine(process));  // AnalyticEuropeanEngine

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

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

                ForwardVanillaOption option = new ForwardVanillaOption(values[i].moneyness, reset, payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                double tolerance  = 1e-4;
                if (error > tolerance)
                {
                    REPORT_FAILURE("value", payoff, exercise, values[i].s,
                                   values[i].q, values[i].r, today,
                                   values[i].v, values[i].moneyness, reset,
                                   values[i].result, calculated,
                                   error, tolerance);
                }
            }
        }
        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)
            };

            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 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 #8
0
        public void testCashOrNothingEuropeanValues()
        {
            // Testing European cash-or-nothing digital option

            DigitalOptionData[] values =
            {
                // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 88
                //        type, strike,  spot,    q,    r,    t,  vol,  value, tol
                new DigitalOptionData(Option.Type.Put, 80.00, 100.0, 0.06, 0.06, 0.75, 0.35, 2.6710, 1e-4, 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, 10.0);

                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);

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

                IPricingEngine engine = new AnalyticEuropeanEngine(stochProcess);

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

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, exercise, 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 #9
0
        public void testQuoteChanging()
        {
            // Testing quote update...

            CommonVars vars = new CommonVars();

            List <Handle <Quote> > spreads = new List <Handle <Quote> >();
            SimpleQuote            spread1 = new SimpleQuote(0.02);
            SimpleQuote            spread2 = new SimpleQuote(0.03);

            spreads.Add(new Handle <Quote>(spread1));
            spreads.Add(new Handle <Quote>(spread2));

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

            spreadDates.Add(vars.calendar.advance(vars.today, 100, TimeUnit.Days));
            spreadDates.Add(vars.calendar.advance(vars.today, 150, TimeUnit.Days));

            Date interpolationDate = vars.calendar.advance(vars.today, 120, TimeUnit.Days);

            ZeroYieldStructure spreadedTermStructure =
                new InterpolatedPiecewiseZeroSpreadedTermStructure <BackwardFlat>(
                    new Handle <YieldTermStructure>(vars.termStructure),
                    spreads, spreadDates);

            double t = vars.dayCount.yearFraction(vars.settlementDate, interpolationDate);
            double interpolatedZeroRate = spreadedTermStructure.zeroRate(t, vars.compounding).value();
            double tolerance            = 1e-9;
            double expectedRate         = vars.termStructure.zeroRate(t, vars.compounding).value() +
                                          0.03;

            if (Math.Abs(interpolatedZeroRate - expectedRate) > tolerance)
            {
                QAssert.Fail(
                    "unable to reproduce interpolated rate\n"
                    + "    calculated: " + interpolatedZeroRate + "\n"
                    + "    expected: " + expectedRate);
            }

            spread2.setValue(0.025);

            interpolatedZeroRate = spreadedTermStructure.zeroRate(t, vars.compounding).value();
            expectedRate         = vars.termStructure.zeroRate(t, vars.compounding).value() +
                                   0.025;

            if (Math.Abs(interpolatedZeroRate - expectedRate) > tolerance)
            {
                QAssert.Fail(
                    "unable to reproduce interpolated rate\n"
                    + "    calculated: " + interpolatedZeroRate + "\n"
                    + "    expected: " + expectedRate);
            }
        }
Exemple #10
0
        public void testObservable()
        {
            // Testing observability of quotes

            SimpleQuote me = new SimpleQuote(0.0);
            Flag        f  = new Flag();

            me.registerWith(f.update);
            me.setValue(3.14);

            if (!f.isUp())
            {
                QAssert.Fail("Observer was not notified of quote change");
            }
        }
Exemple #11
0
        public void testFdValues()
        {
            //("Testing finite-difference engine for American options...");

            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 = 8.0e-2;

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

                spot.setValue(juValues[i].s);
                qRate.setValue(juValues[i].q);
                rRate.setValue(juValues[i].r);
                vol.setValue(juValues[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 FDAmericanEngine(stochProcess, 100, 100);

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

                double calculated = option.NPV();
                double error      = Math.Abs(calculated - juValues[i].result);
                if (error > tolerance)
                {
                    REPORT_FAILURE("value", payoff, exercise, juValues[i].s, juValues[i].q,
                                   juValues[i].r, today, juValues[i].v, juValues[i].result,
                                   calculated, error, tolerance);
                }
            }
        }
Exemple #12
0
        public void testObservable()
        {
            //.("Testing observability of instruments...");

            SimpleQuote me1            = new SimpleQuote(0.0);
            RelinkableHandle <Quote> h = new RelinkableHandle <Quote>(me1);
            Instrument s = new Stock(h);

            Flag f = new Flag();

            s.registerWith(f.update);

            s.NPV();
            me1.setValue(3.14);
            if (!f.isUp())
            {
                QAssert.Fail("Observer was not notified of instrument change");
            }

            s.NPV();
            f.lower();
            SimpleQuote me2 = new SimpleQuote(0.0);

            h.linkTo(me2);
            if (!f.isUp())
            {
                QAssert.Fail("Observer was not notified of instrument change");
            }

            f.lower();
            s.freeze();
            s.NPV();
            me2.setValue(2.71);
            if (f.isUp())
            {
                QAssert.Fail("Observer was notified of frozen instrument change");
            }
            s.NPV();
            s.unfreeze();
            if (!f.isUp())
            {
                QAssert.Fail("Observer was not notified of instrument change");
            }
        }
Exemple #13
0
        public void testReferenceChange()
        {
            // ("Testing term structure against evaluation date change...");

            CommonVars vars = new CommonVars();

            SimpleQuote    flatRate       = new SimpleQuote();
            Handle <Quote> flatRateHandle = new Handle <Quote>(flatRate);

            vars.termStructure = new FlatForward(vars.settlementDays, new NullCalendar(), flatRateHandle, new Actual360());
            flatRate.setValue(.03);

            int[] days = new int[] { 10, 30, 60, 120, 360, 720 };

            Date          today    = Settings.evaluationDate();
            List <double> expected = new InitializedList <double>(days.Length);

            for (int i = 0; i < days.Length; i++)
            {
                expected[i] = vars.termStructure.discount(today + days[i]);
            }

            Settings.setEvaluationDate(today + 30);
            List <double> calculated = new InitializedList <double>(days.Length);

            for (int i = 0; i < days.Length; i++)
            {
                calculated[i] = vars.termStructure.discount(today + 30 + days[i]);
            }

            for (int i = 0; i < days.Length; i++)
            {
                if (!Utils.close(expected[i], calculated[i]))
                {
                    Console.WriteLine("\n  Discount at " + days[i] + " days:\n"
                                      + "    before date change: " + expected[i] + "\n"
                                      + "    after date change:  " + calculated[i]);
                }
            }
        }
Exemple #14
0
        public void testCashAtHitOrNothingAmericanGreeks()
        {
            // Testing American cash-(at-hit)-or-nothing digital option greeks

            SavedSettings backup = new SavedSettings();

            SortedDictionary <string, double> calculated = new SortedDictionary <string, double>();
            SortedDictionary <string, double> expected   = new SortedDictionary <string, double>();
            SortedDictionary <string, double> tolerance  = new SortedDictionary <string, double>(); // std::map<std::string,Real> calculated, expected, tolerance;

            tolerance["delta"] = 5.0e-5;
            tolerance["gamma"] = 5.0e-5;
            tolerance["rho"]   = 5.0e-5;

            Option.Type[] types      = { QLNet.Option.Type.Call, QLNet.Option.Type.Put };
            double[]      strikes    = { 50.0, 99.5, 100.5, 150.0 };
            double        cashPayoff = 100.0;

            double[] underlyings = { 100 };
            double[] qRates      = { 0.04, 0.05, 0.06 };
            double[] rRates      = { 0.01, 0.05, 0.15 };
            double[] vols        = { 0.11, 0.5, 1.2 };

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

            Settings.setEvaluationDate(today);

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

            // there is no cycling on different residual times
            Date     exDate     = today + 360;
            Exercise exercise   = new EuropeanExercise(exDate);
            Exercise amExercise = new AmericanExercise(today, exDate, false);

            Exercise[] exercises = { exercise, amExercise };

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

            IPricingEngine euroEngine = new AnalyticEuropeanEngine(stochProcess);

            IPricingEngine amEngine = new AnalyticDigitalAmericanEngine(stochProcess);

            IPricingEngine[] engines = { euroEngine, amEngine };

            bool knockin = true;

            for (int j = 0; j < engines.Length; j++)
            {
                for (int i1 = 0; i1 < types.Length; i1++)
                {
                    for (int i6 = 0; i6 < strikes.Length; i6++)
                    {
                        StrikedTypePayoff payoff = new CashOrNothingPayoff(types[i1], strikes[i6], cashPayoff);

                        VanillaOption opt = new VanillaOption(payoff, exercises[j]);
                        opt.setPricingEngine(engines[j]);

                        for (int i2 = 0; i2 < underlyings.Length; i2++)
                        {
                            for (int i4 = 0; i4 < qRates.Length; i4++)
                            {
                                for (int i3 = 0; i3 < rRates.Length; i3++)
                                {
                                    for (int i7 = 0; i7 < vols.Length; i7++)
                                    {
                                        // test data
                                        double u = underlyings[i2];
                                        double q = qRates[i4];
                                        double r = rRates[i3];
                                        double v = vols[i7];
                                        spot.setValue(u);
                                        qRate.setValue(q);
                                        rRate.setValue(r);
                                        vol.setValue(v);

                                        // theta, dividend rho and vega are not available for
                                        // digital option with american exercise. Greeks of
                                        // digital options with european payoff are tested
                                        // in the europeanoption.cpp test
                                        double value = opt.NPV();
                                        calculated["delta"] = opt.delta();
                                        calculated["gamma"] = opt.gamma();
                                        calculated["rho"]   = opt.rho();

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

                                            // perturb rates and get rho and dividend rho
                                            double dr = r * 1.0e-4;
                                            rRate.setValue(r + dr);
                                            value_p = opt.NPV();
                                            rRate.setValue(r - dr);
                                            value_m = opt.NPV();
                                            rRate.setValue(r);
                                            expected["rho"] = (value_p - value_m) / (2 * dr);

                                            // check
                                            //std::map<std::string,Real>::iterator it;
                                            foreach (var it in calculated)
                                            {
                                                string greek = it.Key;
                                                double expct = expected  [greek],
                                                       calcl = calculated[greek],
                                                       tol   = tolerance [greek];
                                                double error = Utilities.relativeError(expct, calcl, value);
                                                if (error > tol)
                                                {
                                                    REPORT_FAILURE(greek, payoff, exercise,
                                                                   u, q, r, today, v,
                                                                   expct, calcl, error, tol, knockin);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Exemple #15
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 #16
0
        public void calculate(double[] p, GBMParaViewModel para)
        {
            this.xData_ = p;
            this.yData_ = new double[p.Length];

            double sellBuySign = 1.0;

            if (this.sellBuy_ == "매도")
            {
                sellBuySign = -1.0;
            }
            else
            {
            }

            // set up dates
            Calendar calendar = new TARGET();
            //Date todaysDate = new Date(DateTime.Now);
            Date settlementDate = new Date(para.ReferenceDate_);

            Settings.setEvaluationDate(settlementDate);

            // our options
            Option.Type type = this.callPutEnum_;

            double underlying    = para.CurrentPrice_;
            double strike        = this.strike_;
            double dividendYield = para.Dividend_ / 100;
            double riskFreeRate  = para.Drift_ / 100;

            if (this.callPutEnum_ == Option.Type.Call)
            {
                this.imVol_ = para.Call_Interpolation_.value(this.strike_);
            }
            else if (this.callPutEnum_ == Option.Type.Put)
            {
                this.imVol_ = para.Put_Interpolation_.value(this.strike_);
            }

            double volatility = (this.imVol_) / 100;

            Date maturity = new Date(this.maturiry_.AddDays(1));


            if (this.callPutEnum_ == 0)
            {
                this.deltaCal_ = 1.0;
                this.gammaCal_ = 0.0;
                this.vegaCal_  = 0.0;
                this.thetaCal_ = 0.0;
                this.rhoCal_   = 0.0;

                this.deltaPosition_ = sellBuySign * this.unit_ * 500000 * underlying;

                this.deltaRisk_ = this.deltaPosition_ * 0.09;
                this.gammaRisk_ = 0.0;
                this.vegaRisk_  = 0.0;

                this.totalRisk_ = this.deltaRisk_ + this.gammaRisk_ + this.vegaRisk_;
                this.deepOTM_   = 0.0;

                //this.remainDays_ = maturity - settlementDate;
                this.remainDays_ = (this.maturiry_ - para.ReferenceDate_).Days + 1;

                return;
            }

            DayCounter dayCounter = new Actual365Fixed();

            Exercise europeanExercise = new EuropeanExercise(maturity);

            SimpleQuote quote = new SimpleQuote(underlying);

            Handle <Quote> underlyingH = new Handle <Quote>(quote);

            // bootstrap the yield/dividend/vol curves
            var flatTermStructure    = new Handle <YieldTermStructure>(new FlatForward(settlementDate, riskFreeRate, dayCounter));
            var flatDividendTS       = new Handle <YieldTermStructure>(new FlatForward(settlementDate, dividendYield, dayCounter));
            var flatVolTS            = new Handle <BlackVolTermStructure>(new BlackConstantVol(settlementDate, calendar, volatility, dayCounter));
            StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike);
            var bsmProcess           = new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS);

            // options
            VanillaOption europeanOption = new VanillaOption(payoff, europeanExercise);

            // Analytic formulas:
            // Black-Scholes for European
            europeanOption.setPricingEngine(new AnalyticEuropeanEngine(bsmProcess));

            this.npv_      = Math.Round(europeanOption.NPV(), 6);
            this.deltaCal_ = sellBuySign * Math.Round(europeanOption.delta(), 6);
            this.gammaCal_ = sellBuySign * Math.Round(europeanOption.gamma(), 6);
            this.vegaCal_  = sellBuySign * Math.Round(europeanOption.vega() / 100, 6);
            this.thetaCal_ = sellBuySign * Math.Round(europeanOption.theta() / 365, 6);
            this.rhoCal_   = sellBuySign * Math.Round(europeanOption.rho() / 100, 6);

            this.deltaPosition_ = Math.Round(this.deltaCal_ * this.unit_ * 500000 * underlying, 0);
            this.deltaRisk_     = Math.Round(this.deltaPosition_ * 0.09, 0);
            this.gammaRisk_     = Math.Round(0.5 * this.gammaCal_ * (underlying * underlying * 0.08 * 0.08) * this.unit_ * 500000, 0);
            this.vegaRisk_      = Math.Round(this.vegaCal_ * this.imVol_ * 0.25 * this.unit_ * 500000, 0);

            this.totalRisk_ = this.deltaRisk_ + this.gammaRisk_ + this.vegaRisk_;

            this.deepOTM_ = 0.0;
            //this.remainDays_ = maturity - settlementDate;
            this.remainDays_ = (this.maturiry_ - para.ReferenceDate_).Days + 1;


            for (int i = 0; i < this.xData_.Length; i++)
            {
                quote.setValue(this.xData_[i]);
                this.yData_[i] = 500000.0 * (double)this.unit_ * europeanOption.NPV();
            }
        }
Exemple #17
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 #18
0
        public void testPutCallParity()
        {
            // Testing put-call parity for deltas

            // Test for put call parity between put and call deltas.

            SavedSettings backup = new SavedSettings();

            /* The data below are from
             * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998
             * pag 11-16
             */

            EuropeanOptionData[] values =
            {
                // pag 2-8
                //        type, strike,   spot,    q,    r,    t,  vol,   value,    tol
                new EuropeanOptionData(Option.Type.Call,  65.00,  60.00, 0.00, 0.08, 0.25, 0.30,  2.1334, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,   95.00, 100.00, 0.05, 0.10, 0.50, 0.20,  2.4648, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,   19.00,  19.00, 0.10, 0.10, 0.75, 0.28,  1.7011, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call,  19.00,  19.00, 0.10, 0.10, 0.75, 0.28,  1.7011, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call,   1.60,   1.56, 0.08, 0.06, 0.50, 0.12,  0.0291, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,   70.00,  75.00, 0.05, 0.10, 0.50, 0.35,  4.0870, 1.0e-4),
                // pag 24
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.15,  0.0205, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15,  1.8734, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15,  9.9413, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.25,  0.3150, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25,  3.1217, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 10.3556, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.35,  0.9474, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35,  4.3693, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 11.1381, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.15,  0.8069, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15,  4.0232, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 10.5769, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.25,  2.7026, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25,  6.6997, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 12.7857, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.35,  4.9329, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35,  9.3679, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 15.3086, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.15,  9.9210, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.15,  1.8734, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.15,  0.0408, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.25, 10.2155, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.25,  3.1217, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.25,  0.4551, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.35, 10.8479, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.35,  4.3693, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.35,  1.2376, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.15, 10.3192, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.15,  4.0232, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.15,  1.0646, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.25, 12.2149, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.25,  6.6997, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.25,  3.2734, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.35, 14.4452, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.35,  9.3679, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.35,  5.7963, 1.0e-4),
                // pag 27
                new EuropeanOptionData(Option.Type.Call,  40.00,  42.00, 0.08, 0.04, 0.75, 0.35,  5.0975, 1.0e-4)
            };

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

            double discFor        = 0.0;
            double discDom        = 0.0;
            double implVol        = 0.0;
            double deltaCall      = 0.0;
            double deltaPut       = 0.0;
            double expectedDiff   = 0.0;
            double calculatedDiff = 0.0;
            double error          = 0.0;
            double forward        = 0.0;

            SimpleQuote spotQuote = new SimpleQuote(0.0);

            SimpleQuote        qQuote  = new SimpleQuote(0.0);
            Handle <Quote>     qHandle = new Handle <Quote>(qQuote);
            YieldTermStructure qTS     = new FlatForward(today, qHandle, dc);

            SimpleQuote        rQuote  = new SimpleQuote(0.0);
            Handle <Quote>     rHandle = new Handle <Quote>(qQuote);
            YieldTermStructure rTS     = new FlatForward(today, rHandle, dc);

            SimpleQuote           volQuote  = new SimpleQuote(0.0);
            Handle <Quote>        volHandle = new Handle <Quote>(volQuote);
            BlackVolTermStructure volTS     = new BlackConstantVol(today, calendar, volHandle, dc);

            StrikedTypePayoff payoff;
            Date     exDate;
            Exercise exercise;

            double tolerance = 1.0e-10;

            for (int i = 0; i < values.Length; ++i)
            {
                payoff   = new PlainVanillaPayoff(Option.Type.Call, values[i].strike);
                exDate   = today + timeToDays(values[i].t);
                exercise = new EuropeanExercise(exDate);

                spotQuote.setValue(values[i].s);
                volQuote.setValue(values[i].v);
                rQuote.setValue(values[i].r);
                qQuote.setValue(values[i].q);
                discDom = rTS.discount(exDate);
                discFor = qTS.discount(exDate);
                implVol = Math.Sqrt(volTS.blackVariance(exDate, 0.0));
                forward = spotQuote.value() * discFor / discDom;

                BlackDeltaCalculator myCalc = new BlackDeltaCalculator(Option.Type.Call, DeltaVolQuote.DeltaType.Spot,
                                                                       spotQuote.value(), discDom, discFor, implVol);

                deltaCall = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Put);
                deltaPut = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Call);

                expectedDiff   = discFor;
                calculatedDiff = deltaCall - deltaPut;
                error          = Math.Abs(expectedDiff - calculatedDiff);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Put-call parity failed for spot delta. \n"
                                 + "Calculated Call Delta: " + deltaCall + "\n"
                                 + "Calculated Put Delta:  " + deltaPut + "\n"
                                 + "Expected Difference:   " + expectedDiff + "\n"
                                 + "Calculated Difference: " + calculatedDiff);
                }
                myCalc.setDeltaType(DeltaVolQuote.DeltaType.Fwd);

                deltaCall = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Put);
                deltaPut = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Call);

                expectedDiff   = 1.0;
                calculatedDiff = deltaCall - deltaPut;
                error          = Math.Abs(expectedDiff - calculatedDiff);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Put-call parity failed for forward delta. \n"
                                 + "Calculated Call Delta: " + deltaCall + "\n"
                                 + "Calculated Put Delta:  " + deltaPut + "\n"
                                 + "Expected Difference:   " + expectedDiff + "\n"
                                 + "Calculated Difference: " + calculatedDiff);
                }

                myCalc.setDeltaType(DeltaVolQuote.DeltaType.PaSpot);

                deltaCall = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Put);
                deltaPut = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Call);

                expectedDiff   = discFor * values[i].strike / forward;
                calculatedDiff = deltaCall - deltaPut;
                error          = Math.Abs(expectedDiff - calculatedDiff);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Put-call parity failed for premium-adjusted spot delta. \n"
                                 + "Calculated Call Delta: " + deltaCall + "\n"
                                 + "Calculated Put Delta:  " + deltaPut + "\n"
                                 + "Expected Difference:   " + expectedDiff + "\n"
                                 + "Calculated Difference: " + calculatedDiff);
                }

                myCalc.setDeltaType(DeltaVolQuote.DeltaType.PaFwd);

                deltaCall = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Put);
                deltaPut = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Call);

                expectedDiff   = values[i].strike / forward;
                calculatedDiff = deltaCall - deltaPut;
                error          = Math.Abs(expectedDiff - calculatedDiff);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Put-call parity failed for premium-adjusted forward delta. \n"
                                 + "Calculated Call Delta: " + deltaCall + "\n"
                                 + "Calculated Put Delta:  " + deltaPut + "\n"
                                 + "Expected Difference:   " + expectedDiff + "\n"
                                 + "Calculated Difference: " + calculatedDiff);
                }
            }
        }
Exemple #19
0
        public void testDeltaPriceConsistency()
        {
            // Testing premium-adjusted delta price consistency

            // This function tests for price consistencies with the standard
            // Black Scholes calculator, since premium adjusted deltas can be calculated
            // from spot deltas by adding/subtracting the premium.

            SavedSettings backup = new SavedSettings();

            // actually, value and tol won't be needed for testing
            EuropeanOptionData[] values =
            {
                //        type, strike,   spot,    rd,    rf,    t,  vol,   value,    tol
                new EuropeanOptionData(Option.Type.Call, 0.9123, 1.2212, 0.0231, 0.0000, 0.25, 0.301, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 0.9234, 1.2212, 0.0231, 0.0000, 0.35, 0.111, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 0.9783, 1.2212, 0.0231, 0.0000, 0.45, 0.071, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.0000, 1.2212, 0.0231, 0.0000, 0.55, 0.082, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.1230, 1.2212, 0.0231, 0.0000, 0.65, 0.012, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.2212, 1.2212, 0.0231, 0.0000, 0.75, 0.129, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.3212, 1.2212, 0.0231, 0.0000, 0.85, 0.034, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.3923, 1.2212, 0.0131, 0.2344, 0.95, 0.001, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.3455, 1.2212, 0.0000, 0.0000, 1.00, 0.127, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  0.9123, 1.2212, 0.0231, 0.0000, 0.25, 0.301, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  0.9234, 1.2212, 0.0231, 0.0000, 0.35, 0.111, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  0.9783, 1.2212, 0.0231, 0.0000, 0.45, 0.071, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.0000, 1.2212, 0.0231, 0.0000, 0.55, 0.082, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.1230, 1.2212, 0.0231, 0.0000, 0.65, 0.012, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.2212, 1.2212, 0.0231, 0.0000, 0.75, 0.129, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.3212, 1.2212, 0.0231, 0.0000, 0.85, 0.034, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.3923, 1.2212, 0.0131, 0.2344, 0.95, 0.001, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.3455, 1.2212, 0.0000, 0.0000, 1.00, 0.127, 0.0, 0.0),
                // extreme case: zero vol
                new EuropeanOptionData(Option.Type.Put,  1.3455, 1.2212, 0.0000, 0.0000, 0.50, 0.000, 0.0, 0.0),
                // extreme case: zero strike
                new EuropeanOptionData(Option.Type.Put,  0.0000, 1.2212, 0.0000, 0.0000, 1.50, 0.133, 0.0, 0.0),
                // extreme case: zero strike+zero vol
                new EuropeanOptionData(Option.Type.Put,  0.0000, 1.2212, 0.0000, 0.0000, 1.00, 0.133, 0.0, 0.0),
            };

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

            // Start setup of market data

            double discFor       = 0.0;
            double discDom       = 0.0;
            double implVol       = 0.0;
            double expectedVal   = 0.0;
            double calculatedVal = 0.0;
            double error         = 0.0;

            SimpleQuote    spotQuote  = new SimpleQuote(0.0);
            Handle <Quote> spotHandle = new Handle <Quote>(spotQuote);

            SimpleQuote        qQuote  = new SimpleQuote(0.0);
            Handle <Quote>     qHandle = new Handle <Quote>(qQuote);
            YieldTermStructure qTS     = new FlatForward(today, qHandle, dc);

            SimpleQuote        rQuote  = new SimpleQuote(0.0);
            Handle <Quote>     rHandle = new Handle <Quote>(qQuote);
            YieldTermStructure rTS     = new FlatForward(today, rHandle, dc);

            SimpleQuote           volQuote  = new SimpleQuote(0.0);
            Handle <Quote>        volHandle = new Handle <Quote>(volQuote);
            BlackVolTermStructure volTS     = new BlackConstantVol(today, calendar, volHandle, dc);

            BlackScholesMertonProcess stochProcess;
            IPricingEngine            engine;
            StrikedTypePayoff         payoff;
            Date     exDate;
            Exercise exercise;
            // Setup of market data finished

            double tolerance = 1.0e-10;

            for (int i = 0; i < values.Length; ++i)
            {
                payoff   = new PlainVanillaPayoff(values[i].type, values[i].strike);
                exDate   = today + timeToDays(values[i].t);
                exercise = new EuropeanExercise(exDate);

                spotQuote.setValue(values[i].s);
                volQuote.setValue(values[i].v);
                rQuote.setValue(values[i].r);
                qQuote.setValue(values[i].q);

                discDom = rTS.discount(exDate);
                discFor = qTS.discount(exDate);
                implVol = Math.Sqrt(volTS.blackVariance(exDate, 0.0));

                BlackDeltaCalculator myCalc = new BlackDeltaCalculator(values[i].type, DeltaVolQuote.DeltaType.PaSpot,
                                                                       spotQuote.value(), discDom, discFor, implVol);

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

                engine = new AnalyticEuropeanEngine(stochProcess);

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

                calculatedVal = myCalc.deltaFromStrike(values[i].strike);
                expectedVal   = option.delta() - option.NPV() / spotQuote.value();
                error         = Math.Abs(expectedVal - calculatedVal);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Premium-adjusted spot delta test failed. \n"
                                 + "Calculated Delta: " + calculatedVal + "\n"
                                 + "Expected Value:   " + expectedVal + "\n"
                                 + "Error: " + error);
                }

                myCalc.setDeltaType(DeltaVolQuote.DeltaType.PaFwd);

                calculatedVal = myCalc.deltaFromStrike(values[i].strike);
                expectedVal   = expectedVal / discFor; // Premium adjusted Fwd Delta is PA spot without discount
                error         = Math.Abs(expectedVal - calculatedVal);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Premium-adjusted forward delta test failed. \n"
                                 + "Calculated Delta: " + calculatedVal + "\n"
                                 + "Expected Value:   " + expectedVal + "\n"
                                 + "Error: " + error);
                }


                // Test consistency with BlackScholes Calculator for Spot Delta
                myCalc.setDeltaType(DeltaVolQuote.DeltaType.Spot);

                calculatedVal = myCalc.deltaFromStrike(values[i].strike);
                expectedVal   = option.delta();
                error         = Math.Abs(calculatedVal - expectedVal);

                if (error > tolerance)
                {
                    QAssert.Fail("\n spot delta in BlackDeltaCalculator differs from delta in BlackScholesCalculator. \n"
                                 + "Calculated Value: " + calculatedVal + "\n"
                                 + "Expected Value:   " + expectedVal + "\n"
                                 + "Error: " + error);
                }
            }
        }
Exemple #20
0
        private void testOptionGreeks(ForwardVanillaEngine.GetOriginalEngine getEngine)
        {
            SavedSettings backup = new SavedSettings();

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

            tolerance["delta"]  = 1.0e-5;
            tolerance["gamma"]  = 1.0e-5;
            tolerance["theta"]  = 1.0e-5;
            tolerance["rho"]    = 1.0e-5;
            tolerance["divRho"] = 1.0e-5;
            tolerance["vega"]   = 1.0e-5;

            Option.Type[] types       = { Option.Type.Call, Option.Type.Put };
            double[]      moneyness   = { 0.9, 1.0, 1.1 };
            double[]      underlyings = { 100.0 };
            double[]      qRates      = { 0.04, 0.05, 0.06 };
            double[]      rRates      = { 0.01, 0.05, 0.15 };
            int[]         lengths     = { 1, 2 };
            Frequency[]   frequencies = { Frequency.Semiannual, Frequency.Quarterly, };
            double[]      vols        = { 0.11, 0.50, 1.20 };

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

            Settings.setEvaluationDate(today);

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

            BlackScholesMertonProcess process = new BlackScholesMertonProcess(new Handle <Quote>(spot), qTS, rTS, volTS);

            for (int i = 0; i < types.Length; i++)
            {
                for (int j = 0; j < moneyness.Length; j++)
                {
                    for (int k = 0; k < lengths.Length; k++)
                    {
                        for (int kk = 0; kk < frequencies.Length; kk++)
                        {
                            EuropeanExercise maturity = new EuropeanExercise(today + new Period(lengths[k], TimeUnit.Years));

                            PercentageStrikePayoff payoff = new PercentageStrikePayoff(types[i], moneyness[j]);

                            List <Date> reset = new List <Date>();
                            for (Date d = today + new Period(frequencies[kk]);
                                 d < maturity.lastDate();
                                 d += new Period(frequencies[kk]))
                            {
                                reset.Add(d);
                            }

                            IPricingEngine engine = getEngine(process);

                            CliquetOption option = new CliquetOption(payoff, maturity, reset);
                            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["delta"]  = option.delta();
                                            calculated["gamma"]  = option.gamma();
                                            calculated["theta"]  = option.theta();
                                            calculated["rho"]    = option.rho();
                                            calculated["divRho"] = option.dividendRho();
                                            calculated["vega"]   = option.vega();

                                            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["delta"] = (value_p - value_m) / (2 * du);
                                                expected["gamma"] = (delta_p - delta_m) / (2 * du);

                                                // perturb rates and get rho and dividend rho
                                                double dr = r * 1.0e-4;
                                                rRate.setValue(r + dr);
                                                value_p = option.NPV();
                                                rRate.setValue(r - dr);
                                                value_m = option.NPV();
                                                rRate.setValue(r);
                                                expected["rho"] = (value_p - value_m) / (2 * dr);

                                                double dq = q * 1.0e-4;
                                                qRate.setValue(q + dq);
                                                value_p = option.NPV();
                                                qRate.setValue(q - dq);
                                                value_m = option.NPV();
                                                qRate.setValue(q);
                                                expected["divRho"] = (value_p - value_m) / (2 * dq);

                                                // perturb volatility and get vega
                                                double dv = v * 1.0e-4;
                                                vol.setValue(v + dv);
                                                value_p = option.NPV();
                                                vol.setValue(v - dv);
                                                value_m = option.NPV();
                                                vol.setValue(v);
                                                expected["vega"] = (value_p - value_m) / (2 * dv);

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

                                                // compare
                                                foreach (var it in calculated)
                                                {
                                                    String greek = it.Key;
                                                    double expct = expected  [greek],
                                                           calcl = calculated[greek],
                                                           tol   = tolerance [greek];
                                                    double error = Utilities.relativeError(expct, calcl, u);
                                                    if (error > tol)
                                                    {
                                                        REPORT_FAILURE(greek, payoff, maturity,
                                                                       u, q, r, today, v,
                                                                       expct, calcl, error, tol);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Exemple #21
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 #22
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 #23
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 #24
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);
                }
            }
        }
Exemple #25
0
        public void testVannaVolgaDoubleBarrierValues()
        {
            // Testing double-barrier FX options against Vanna/Volga values
            SavedSettings backup = new SavedSettings();

            DoubleBarrierFxOptionData[] values =
            {
                //                             BarrierType,                    barr.1, barr.2, rebate,         type,    strike,          s,         q,         r,  t, vol25Put,    volAtm,vol25Call,      vol,    result,   tol
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638, 0.14413, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088, 0.07456, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925, 0.02710, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463, 0.00569, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412, 0.00013, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638, 0.00017, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088, 0.00353, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925, 0.02221, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463, 0.06049, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412, 0.11103, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511, 0.19981, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890, 0.10389, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444, 0.03555, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197, 0.00634, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261, 0.00000, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511, 0.00000, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890, 0.00436, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444, 0.03173, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197, 0.09346, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261, 0.17704, 1.0e-4),
            };

            DayCounter dc    = new Actual360();
            Date       today = new Date(05, Month.Mar, 2013);

            Settings.setEvaluationDate(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        vol25Put  = new SimpleQuote(0.0);
            SimpleQuote        volAtm    = new SimpleQuote(0.0);
            SimpleQuote        vol25Call = new SimpleQuote(0.0);

            for (int i = 0; i < values.Length; i++)
            {
                for (int j = 0; j <= 1; j++)
                {
                    DoubleBarrier.Type barrierType = (DoubleBarrier.Type)j;
                    spot.setValue(values[i].s);
                    qRate.setValue(values[i].q);
                    rRate.setValue(values[i].r);
                    vol25Put.setValue(values[i].vol25Put);
                    volAtm.setValue(values[i].volAtm);
                    vol25Call.setValue(values[i].vol25Call);

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

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

                    Handle <DeltaVolQuote> volAtmQuote = new Handle <DeltaVolQuote>(
                        new DeltaVolQuote(new Handle <Quote>(volAtm), DeltaVolQuote.DeltaType.Fwd, values[i].t,
                                          DeltaVolQuote.AtmType.AtmDeltaNeutral));

                    //always delta neutral atm
                    Handle <DeltaVolQuote> vol25PutQuote = new Handle <DeltaVolQuote>(new DeltaVolQuote(-0.25,
                                                                                                        new Handle <Quote>(vol25Put), values[i].t, DeltaVolQuote.DeltaType.Fwd));

                    Handle <DeltaVolQuote> vol25CallQuote = new Handle <DeltaVolQuote>(new DeltaVolQuote(0.25,
                                                                                                         new Handle <Quote>(vol25Call), values[i].t, DeltaVolQuote.DeltaType.Fwd));

                    DoubleBarrierOption doubleBarrierOption = new DoubleBarrierOption(barrierType,
                                                                                      values[i].barrier1, values[i].barrier2, values[i].rebate, payoff, exercise);

                    double bsVanillaPrice = Utils.blackFormula(values[i].type, values[i].strike,
                                                               spot.value() * qTS.discount(values[i].t) / rTS.discount(values[i].t),
                                                               values[i].v * Math.Sqrt(values[i].t), rTS.discount(values[i].t));

                    IPricingEngine vannaVolgaEngine;

                    vannaVolgaEngine = new VannaVolgaDoubleBarrierEngine(volAtmQuote, vol25PutQuote, vol25CallQuote,
                                                                         new Handle <Quote>(spot),
                                                                         new Handle <YieldTermStructure>(rTS),
                                                                         new Handle <YieldTermStructure>(qTS),
                                                                         (process, series) => new WulinYongDoubleBarrierEngine(process, series),
                                                                         true,
                                                                         bsVanillaPrice);
                    doubleBarrierOption.setPricingEngine(vannaVolgaEngine);

                    double expected = 0;
                    if (barrierType == DoubleBarrier.Type.KnockOut)
                    {
                        expected = values[i].result;
                    }
                    else if (barrierType == DoubleBarrier.Type.KnockIn)
                    {
                        expected = (bsVanillaPrice - values[i].result);
                    }

                    double calculated = doubleBarrierOption.NPV();
                    double error      = Math.Abs(calculated - expected);
                    if (error > values[i].tol)
                    {
                        REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType,
                                                  values[i].barrier1, values[i].barrier2,
                                                  values[i].rebate, payoff, exercise, values[i].s,
                                                  values[i].q, values[i].r, today, values[i].vol25Put,
                                                  values[i].volAtm, values[i].vol25Call, values[i].v,
                                                  expected, calculated, error, values[i].tol);
                    }

                    vannaVolgaEngine = new VannaVolgaDoubleBarrierEngine(volAtmQuote, vol25PutQuote, vol25CallQuote,
                                                                         new Handle <Quote>(spot),
                                                                         new Handle <YieldTermStructure>(rTS),
                                                                         new Handle <YieldTermStructure>(qTS),
                                                                         (process, series) => new AnalyticDoubleBarrierEngine(process, series),
                                                                         true,
                                                                         bsVanillaPrice);
                    doubleBarrierOption.setPricingEngine(vannaVolgaEngine);

                    calculated = doubleBarrierOption.NPV();
                    error      = Math.Abs(calculated - expected);
                    double maxtol = 5.0e-3; // different engines have somewhat different results
                    if (error > maxtol)
                    {
                        REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType,
                                                  values[i].barrier1, values[i].barrier2,
                                                  values[i].rebate, payoff, exercise, values[i].s,
                                                  values[i].q, values[i].r, today, values[i].vol25Put,
                                                  values[i].volAtm, values[i].vol25Call, values[i].v,
                                                  expected, calculated, error, values[i].tol);
                    }
                }
            }
        }
Exemple #26
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 #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 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);
                }
            }
        }
Exemple #29
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 #30
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);
                }
            }
        }